From c223d0b390be1c012804a6c8153206878a737ab5 Mon Sep 17 00:00:00 2001
From: ColumbusLabs <287001685+ColumbusLabs@users.noreply.github.com>
Date: Wed, 22 Jul 2026 15:25:43 -0400
Subject: [PATCH 1/2] test: migrate FilesList header specs to testing Pinia
Signed-off-by: ColumbusLabs <287001685+ColumbusLabs@users.noreply.github.com>
---
.../FilesList/FilesListTableHeader.spec.ts | 42 ++++------
.../FilesListTableHeaderButton.spec.ts | 79 +++++++++++--------
2 files changed, 65 insertions(+), 56 deletions(-)
diff --git a/src/tests/views/FilesList/FilesListTableHeader.spec.ts b/src/tests/views/FilesList/FilesListTableHeader.spec.ts
index 49a4cc9501..49c6c25204 100644
--- a/src/tests/views/FilesList/FilesListTableHeader.spec.ts
+++ b/src/tests/views/FilesList/FilesListTableHeader.spec.ts
@@ -3,13 +3,13 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { createTestingPinia } from '@pinia/testing'
import { mount } from '@vue/test-utils'
-import { createPinia, setActivePinia } from 'pinia'
+import { setActivePinia } from 'pinia'
+import { beforeEach, describe, expect, it, vi } from 'vitest'
import FilesListTableHeader from '../../../views/FilesList/FilesListTableHeader.vue'
-import { useFilesStore } from '../../../store/files.js'
-import { useFilesSortingStore } from '../../../store/filesSorting.js'
+
import { useSelectionStore } from '../../../store/selection.js'
type Column = {
@@ -103,6 +103,7 @@ function createWrapper(filesCount = 2) {
nodes: Array.from({ length: filesCount }, (_, index) => ({ id: index + 1, basename: `file${index + 1}.pdf` })),
},
global: {
+ plugins: [pinia],
stubs: {
NcCheckboxRadioSwitch: NcCheckboxRadioSwitchStub,
FilesListTableHeaderButton: {
@@ -116,7 +117,6 @@ function createWrapper(filesCount = 2) {
describe('FilesListTableHeader.vue', () => {
beforeEach(() => {
- setActivePinia(createPinia())
vi.clearAllMocks()
})
@@ -230,20 +230,14 @@ describe('FilesListTableHeader.vue', () => {
})
it('sets modelValue to true when all files are selected', async () => {
- const wrapper = createWrapper(2)
- const selectionStore = useSelectionStore()
-
- selectionStore.set([1, 2])
+ const wrapper = createWrapper(2, { selected: [1, 2] })
await wrapper.vm.$nextTick()
expect(wrapper.findComponent(NcCheckboxRadioSwitchStub).props('modelValue')).toBe(true)
})
it('sets indeterminate when only some files are selected', async () => {
- const wrapper = createWrapper(2)
- const selectionStore = useSelectionStore()
-
- selectionStore.set([1])
+ const wrapper = createWrapper(2, { selected: [1] })
await wrapper.vm.$nextTick()
const stub = wrapper.findComponent(NcCheckboxRadioSwitchStub)
@@ -268,24 +262,22 @@ describe('FilesListTableHeader.vue', () => {
expect(vm.ariaSortForMode('actions', false)).toBeNull()
})
- it('returns descending when the active mode is descending', async () => {
- const wrapper = createWrapper()
+ it('returns descending when the active mode is descending', () => {
+ const wrapper = createWrapper(2, {
+ sortingMode: 'created_at',
+ sortingDirection: 'desc',
+ })
const vm = wrapper.vm as FilesListTableHeaderVm
- const sortingStore = useFilesSortingStore()
- sortingStore.sortingMode = 'created_at'
- sortingStore.sortingDirection = 'desc'
- await wrapper.vm.$nextTick()
expect(vm.ariaSortForMode('created_at')).toBe('descending')
})
- it('returns ascending when the active mode is ascending', async () => {
- const wrapper = createWrapper()
+ it('returns ascending when the active mode is ascending', () => {
+ const wrapper = createWrapper(2, {
+ sortingMode: 'status',
+ sortingDirection: 'asc',
+ })
const vm = wrapper.vm as FilesListTableHeaderVm
- const sortingStore = useFilesSortingStore()
- sortingStore.sortingMode = 'status'
- sortingStore.sortingDirection = 'asc'
- await wrapper.vm.$nextTick()
expect(vm.ariaSortForMode('status')).toBe('ascending')
})
diff --git a/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts b/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts
index b9c82973c4..bef2f55146 100644
--- a/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts
+++ b/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts
@@ -3,11 +3,13 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import { beforeEach, describe, expect, it, vi } from 'vitest'
+import { createTestingPinia } from '@pinia/testing'
import { mount } from '@vue/test-utils'
-import { createPinia, setActivePinia } from 'pinia'
+import { setActivePinia } from 'pinia'
+import { beforeEach, describe, expect, it, vi } from 'vitest'
import FilesListTableHeaderButton from '../../../views/FilesList/FilesListTableHeaderButton.vue'
+
import { useFilesSortingStore } from '../../../store/filesSorting.js'
vi.mock('@nextcloud/event-bus', () => ({
@@ -57,10 +59,31 @@ const NcButtonStub = {
template: '',
}
-function createWrapper(mode = 'size', name = 'Size') {
+type FilesSortingState = {
+ sortingMode?: string
+ sortingDirection?: string
+}
+
+/**
+ * Mount the header button with isolated sorting-store state.
+ *
+ * @param mode Sort key represented by the button.
+ * @param name Visible label for the button.
+ * @param sortingState Initial state for the sorting store.
+ */
+function createWrapper(mode = 'size', name = 'Size', sortingState: FilesSortingState = {}) {
+ const pinia = createTestingPinia({
+ createSpy: vi.fn,
+ initialState: {
+ filesSorting: sortingState,
+ },
+ })
+ setActivePinia(pinia)
+
return mount(FilesListTableHeaderButton, {
props: { name, mode },
global: {
+ plugins: [pinia],
stubs: {
NcButton: NcButtonStub,
NcIconSvgWrapper: true,
@@ -71,7 +94,6 @@ function createWrapper(mode = 'size', name = 'Size') {
describe('FilesListTableHeaderButton.vue', () => {
beforeEach(() => {
- setActivePinia(createPinia())
vi.clearAllMocks()
})
@@ -82,11 +104,10 @@ describe('FilesListTableHeaderButton.vue', () => {
})
it('computes descending state when the same column is sorted descending', () => {
- const sortingStore = useFilesSortingStore()
- sortingStore.sortingMode = 'size'
- sortingStore.sortingDirection = 'desc'
-
- const wrapper = createWrapper('size')
+ const wrapper = createWrapper('size', 'Size', {
+ sortingMode: 'size',
+ sortingDirection: 'desc',
+ })
expect(wrapper.vm.isAscending).toBe(false)
})
@@ -97,31 +118,29 @@ describe('FilesListTableHeaderButton.vue', () => {
})
it('triggers the store sort toggle for the current mode', async () => {
- const sortingStore = useFilesSortingStore()
- const spy = vi.spyOn(sortingStore, 'toggleSortBy')
const wrapper = createWrapper('size')
+ const sortingStore = useFilesSortingStore()
await wrapper.find('button').trigger('click')
- expect(spy).toHaveBeenCalledWith('size')
+ expect(sortingStore.toggleSortBy).toHaveBeenCalledWith('size')
})
describe('Vue 3 sorting interactions', () => {
it('is true when the column is active and direction is asc', () => {
- const sortingStore = useFilesSortingStore()
- sortingStore.sortingMode = 'created_at'
- sortingStore.sortingDirection = 'asc'
-
- const wrapper = createWrapper('created_at', 'Created at')
+ const wrapper = createWrapper('created_at', 'Created at', {
+ sortingMode: 'created_at',
+ sortingDirection: 'asc',
+ })
expect(wrapper.vm.isAscending).toBe(true)
})
it('reacts when direction changes from asc to desc', async () => {
+ const wrapper = createWrapper('created_at', 'Created at', {
+ sortingMode: 'created_at',
+ sortingDirection: 'asc',
+ })
const sortingStore = useFilesSortingStore()
- sortingStore.sortingMode = 'created_at'
- sortingStore.sortingDirection = 'asc'
-
- const wrapper = createWrapper('created_at', 'Created at')
expect(wrapper.vm.isAscending).toBe(true)
sortingStore.sortingDirection = 'desc'
@@ -131,10 +150,9 @@ describe('FilesListTableHeaderButton.vue', () => {
})
it('adds the active class when the column is the active sort mode', () => {
- const sortingStore = useFilesSortingStore()
- sortingStore.sortingMode = 'created_at'
-
- const wrapper = createWrapper('created_at', 'Created at')
+ const wrapper = createWrapper('created_at', 'Created at', {
+ sortingMode: 'created_at',
+ })
expect(wrapper.find('button').classes()).toContain('files-list__column-sort-button--active')
})
@@ -145,10 +163,10 @@ describe('FilesListTableHeaderButton.vue', () => {
})
it('removes the active class when the active mode changes', async () => {
+ const wrapper = createWrapper('created_at', 'Created at', {
+ sortingMode: 'created_at',
+ })
const sortingStore = useFilesSortingStore()
- sortingStore.sortingMode = 'created_at'
-
- const wrapper = createWrapper('created_at', 'Created at')
expect(wrapper.find('button').classes()).toContain('files-list__column-sort-button--active')
sortingStore.sortingMode = 'status'
@@ -158,13 +176,12 @@ describe('FilesListTableHeaderButton.vue', () => {
})
it('delegates click to toggleSortBy for the provided mode', async () => {
- const sortingStore = useFilesSortingStore()
- const spy = vi.spyOn(sortingStore, 'toggleSortBy')
const wrapper = createWrapper('created_at', 'Created at')
+ const sortingStore = useFilesSortingStore()
await wrapper.find('button').trigger('click')
- expect(spy).toHaveBeenCalledWith('created_at')
+ expect(sortingStore.toggleSortBy).toHaveBeenCalledWith('created_at')
})
})
})
From cf3671c5a3527820bf8cccc68e6cad71b4338ccd Mon Sep 17 00:00:00 2001
From: ColumbusLabs <287001685+ColumbusLabs@users.noreply.github.com>
Date: Thu, 23 Jul 2026 15:10:06 -0400
Subject: [PATCH 2/2] test: narrow FilesList Pinia action stubbing
Signed-off-by: ColumbusLabs <287001685+ColumbusLabs@users.noreply.github.com>
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
---
.../FilesList/FilesListTableHeader.spec.ts | 46 +++++++++++++------
.../FilesListTableHeaderButton.spec.ts | 16 +------
2 files changed, 32 insertions(+), 30 deletions(-)
diff --git a/src/tests/views/FilesList/FilesListTableHeader.spec.ts b/src/tests/views/FilesList/FilesListTableHeader.spec.ts
index 49c6c25204..f679aaf9c2 100644
--- a/src/tests/views/FilesList/FilesListTableHeader.spec.ts
+++ b/src/tests/views/FilesList/FilesListTableHeader.spec.ts
@@ -5,11 +5,11 @@
import { createTestingPinia } from '@pinia/testing'
import { mount } from '@vue/test-utils'
-import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import FilesListTableHeader from '../../../views/FilesList/FilesListTableHeader.vue'
+import { useFilesSortingStore } from '../../../store/filesSorting.js'
import { useSelectionStore } from '../../../store/selection.js'
type Column = {
@@ -95,8 +95,16 @@ const NcCheckboxRadioSwitchStub = {
}
function createWrapper(filesCount = 2) {
- const filesStore = useFilesStore()
- filesStore.ordered = Array.from({ length: filesCount }, (_, index) => index + 1) as typeof filesStore.ordered
+ const ordered = Array.from({ length: filesCount }, (_, index) => index + 1)
+ const pinia = createTestingPinia({
+ createSpy: vi.fn,
+ stubActions: (action, store) => !(store.$id === 'selection' && ['set', 'reset'].includes(action)),
+ initialState: {
+ files: {
+ ordered,
+ },
+ },
+ })
return mount(FilesListTableHeader, {
props: {
@@ -230,14 +238,20 @@ describe('FilesListTableHeader.vue', () => {
})
it('sets modelValue to true when all files are selected', async () => {
- const wrapper = createWrapper(2, { selected: [1, 2] })
+ const wrapper = createWrapper(2)
+ const selectionStore = useSelectionStore()
+
+ selectionStore.set([1, 2])
await wrapper.vm.$nextTick()
expect(wrapper.findComponent(NcCheckboxRadioSwitchStub).props('modelValue')).toBe(true)
})
it('sets indeterminate when only some files are selected', async () => {
- const wrapper = createWrapper(2, { selected: [1] })
+ const wrapper = createWrapper(2)
+ const selectionStore = useSelectionStore()
+
+ selectionStore.set([1])
await wrapper.vm.$nextTick()
const stub = wrapper.findComponent(NcCheckboxRadioSwitchStub)
@@ -262,22 +276,24 @@ describe('FilesListTableHeader.vue', () => {
expect(vm.ariaSortForMode('actions', false)).toBeNull()
})
- it('returns descending when the active mode is descending', () => {
- const wrapper = createWrapper(2, {
- sortingMode: 'created_at',
- sortingDirection: 'desc',
- })
+ it('returns descending when the active mode is descending', async () => {
+ const wrapper = createWrapper()
const vm = wrapper.vm as FilesListTableHeaderVm
+ const sortingStore = useFilesSortingStore()
+ sortingStore.sortingMode = 'created_at'
+ sortingStore.sortingDirection = 'desc'
+ await wrapper.vm.$nextTick()
expect(vm.ariaSortForMode('created_at')).toBe('descending')
})
- it('returns ascending when the active mode is ascending', () => {
- const wrapper = createWrapper(2, {
- sortingMode: 'status',
- sortingDirection: 'asc',
- })
+ it('returns ascending when the active mode is ascending', async () => {
+ const wrapper = createWrapper()
const vm = wrapper.vm as FilesListTableHeaderVm
+ const sortingStore = useFilesSortingStore()
+ sortingStore.sortingMode = 'status'
+ sortingStore.sortingDirection = 'asc'
+ await wrapper.vm.$nextTick()
expect(vm.ariaSortForMode('status')).toBe('ascending')
})
diff --git a/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts b/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts
index bef2f55146..c9e6479f9d 100644
--- a/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts
+++ b/src/tests/views/FilesList/FilesListTableHeaderButton.spec.ts
@@ -5,7 +5,6 @@
import { createTestingPinia } from '@pinia/testing'
import { mount } from '@vue/test-utils'
-import { setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import FilesListTableHeaderButton from '../../../views/FilesList/FilesListTableHeaderButton.vue'
@@ -59,26 +58,13 @@ const NcButtonStub = {
template: '',
}
-type FilesSortingState = {
- sortingMode?: string
- sortingDirection?: string
-}
-
-/**
- * Mount the header button with isolated sorting-store state.
- *
- * @param mode Sort key represented by the button.
- * @param name Visible label for the button.
- * @param sortingState Initial state for the sorting store.
- */
-function createWrapper(mode = 'size', name = 'Size', sortingState: FilesSortingState = {}) {
+function createWrapper(mode = 'size', name = 'Size', sortingState: { sortingMode?: string, sortingDirection?: string } = {}) {
const pinia = createTestingPinia({
createSpy: vi.fn,
initialState: {
filesSorting: sortingState,
},
})
- setActivePinia(pinia)
return mount(FilesListTableHeaderButton, {
props: { name, mode },