Skip to content

Commit c3ab3cd

Browse files
test(FileListFilterModified): add component tests
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent 7d55d26 commit c3ab3cd

1 file changed

Lines changed: 185 additions & 0 deletions

File tree

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2026 LibreCode coop and LibreCode contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { beforeEach, describe, expect, it, vi } from 'vitest'
7+
import { mount } from '@vue/test-utils'
8+
import { setActivePinia } from 'pinia'
9+
import { createTestingPinia } from '@pinia/testing'
10+
11+
import FileListFilterModified from '../../../../views/FilesList/FileListFilter/FileListFilterModified.vue'
12+
import { useFiltersStore } from '../../../../store/filters.js'
13+
14+
vi.mock('@nextcloud/l10n', () => ({
15+
t: vi.fn((_app: string, text: string, vars?: Record<string, unknown>) => {
16+
if (vars) {
17+
return Object.entries(vars).reduce(
18+
(acc, [key, val]) => acc.replace(`{${key}}`, String(val)),
19+
text
20+
)
21+
}
22+
return text
23+
}),
24+
}))
25+
26+
vi.mock('@nextcloud/logger', () => ({
27+
getLogger: vi.fn(() => ({
28+
error: vi.fn(),
29+
warn: vi.fn(),
30+
info: vi.fn(),
31+
debug: vi.fn(),
32+
})),
33+
getLoggerBuilder: vi.fn(() => ({
34+
setApp: vi.fn().mockReturnThis(),
35+
detectUser: vi.fn().mockReturnThis(),
36+
build: vi.fn(() => ({
37+
error: vi.fn(),
38+
warn: vi.fn(),
39+
info: vi.fn(),
40+
debug: vi.fn(),
41+
})),
42+
})),
43+
}))
44+
45+
vi.mock('@nextcloud/axios', () => ({
46+
default: { get: vi.fn(), post: vi.fn(), put: vi.fn(), delete: vi.fn(), patch: vi.fn() },
47+
}))
48+
49+
vi.mock('@nextcloud/router', () => ({
50+
generateOcsUrl: vi.fn((path: string) => `/ocs/v2.php${path}`),
51+
}))
52+
53+
vi.mock('@nextcloud/initial-state', () => ({
54+
loadState: vi.fn((_app: string, _key: string, defaultValue: unknown) => defaultValue),
55+
}))
56+
57+
vi.mock('@nextcloud/event-bus', () => ({
58+
emit: vi.fn(),
59+
subscribe: vi.fn(),
60+
}))
61+
62+
vi.mock('@nextcloud/vue/components/NcButton', () => ({
63+
default: {
64+
name: 'NcButton',
65+
props: ['variant', 'alignment', 'wide', 'pressed'],
66+
emits: ['click'],
67+
template: '<button class="nc-button-stub" :data-variant="variant" :data-pressed="pressed" @click="$emit(\'click\')"><slot /><slot name="icon" /></button>',
68+
},
69+
}))
70+
71+
vi.mock('@nextcloud/vue/components/NcIconSvgWrapper', () => ({
72+
default: {
73+
name: 'NcIconSvgWrapper',
74+
props: ['path', 'svg', 'size'],
75+
template: '<i class="nc-icon" />',
76+
},
77+
}))
78+
79+
vi.mock('../../../../views/FilesList/FileListFilter/FileListFilter.vue', () => ({
80+
default: {
81+
name: 'FileListFilter',
82+
props: ['isActive', 'filterName'],
83+
emits: ['reset-filter'],
84+
template: '<div class="file-list-filter-stub" :data-is-active="isActive"><slot /><slot name="icon" /></div>',
85+
},
86+
}))
87+
88+
describe('FileListFilterModified.vue', () => {
89+
beforeEach(() => {
90+
setActivePinia(createTestingPinia({ createSpy: vi.fn }))
91+
})
92+
93+
function mountComponent() {
94+
return mount(FileListFilterModified)
95+
}
96+
97+
/** Finds a preset option button by its visible label */
98+
function findPresetButton(wrapper: ReturnType<typeof mountComponent>, label: string) {
99+
return wrapper.findAll('.nc-button-stub').find((b) => b.text() === label)
100+
}
101+
102+
it('selectedOption is null when filter_modified is not set', () => {
103+
const wrapper = mountComponent()
104+
expect(wrapper.vm.selectedOption).toBeNull()
105+
})
106+
107+
it('isActive is false when no preset is selected', () => {
108+
const wrapper = mountComponent()
109+
expect(wrapper.vm.isActive).toBe(false)
110+
})
111+
112+
it('passes isActive=false to FileListFilter when no preset selected', () => {
113+
const wrapper = mountComponent()
114+
expect(wrapper.find('.file-list-filter-stub').attributes('data-is-active')).toBe('false')
115+
})
116+
117+
it('renders 5 preset option buttons', () => {
118+
const wrapper = mountComponent()
119+
const buttons = wrapper.findAll('.nc-button-stub')
120+
expect(buttons).toHaveLength(5)
121+
})
122+
123+
it('clicking a preset button sets selectedOption to that preset id', async () => {
124+
const wrapper = mountComponent()
125+
await findPresetButton(wrapper, 'Today')!.trigger('click')
126+
expect(wrapper.vm.selectedOption).toBe('today')
127+
})
128+
129+
it('isActive becomes true after a preset is selected', async () => {
130+
const wrapper = mountComponent()
131+
await findPresetButton(wrapper, 'Today')!.trigger('click')
132+
expect(wrapper.vm.isActive).toBe(true)
133+
})
134+
135+
it('selected button reports pressed=true', async () => {
136+
const wrapper = mountComponent()
137+
const todayButton = findPresetButton(wrapper, 'Today')!
138+
await todayButton.trigger('click')
139+
expect(todayButton.attributes('data-pressed')).toBe('true')
140+
})
141+
142+
it('clicking the same preset again deselects it (radio toggle)', async () => {
143+
const wrapper = mountComponent()
144+
const todayButton = findPresetButton(wrapper, 'Today')!
145+
await todayButton.trigger('click')
146+
expect(wrapper.vm.selectedOption).toBe('today')
147+
await todayButton.trigger('click')
148+
expect(wrapper.vm.selectedOption).toBeNull()
149+
})
150+
151+
it('isActive goes back to false after deselecting', async () => {
152+
const wrapper = mountComponent()
153+
const todayButton = findPresetButton(wrapper, 'Today')!
154+
await todayButton.trigger('click')
155+
await todayButton.trigger('click')
156+
expect(wrapper.vm.isActive).toBe(false)
157+
})
158+
159+
it('initialises selectedOption from filtersStore.filter_modified when set', () => {
160+
const filtersStore = useFiltersStore()
161+
filtersStore.$patch({ filter_modified: 'last-7' })
162+
163+
const wrapper = mountComponent()
164+
expect(wrapper.vm.selectedOption).toBe('last-7')
165+
})
166+
167+
it('resetFilter clears selectedOption when it is set', async () => {
168+
const wrapper = mountComponent()
169+
await findPresetButton(wrapper, 'Last 7 days')!.trigger('click')
170+
expect(wrapper.vm.selectedOption).toBe('last-7')
171+
172+
wrapper.vm.resetFilter()
173+
await wrapper.vm.$nextTick()
174+
175+
expect(wrapper.vm.selectedOption).toBeNull()
176+
})
177+
178+
// createTestingPinia auto-spies all store actions — no vi.spyOn needed
179+
it('watch triggers onFilterUpdateChips when selectedOption changes', async () => {
180+
const filtersStore = useFiltersStore()
181+
const wrapper = mountComponent()
182+
await findPresetButton(wrapper, 'Today')!.trigger('click')
183+
expect(filtersStore.onFilterUpdateChips).toHaveBeenCalled()
184+
})
185+
})

0 commit comments

Comments
 (0)