Skip to content

Commit f1e1239

Browse files
committed
test(files-list): add FilesList rendering regression spec
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
1 parent 957a8fa commit f1e1239

File tree

1 file changed

+196
-0
lines changed

1 file changed

+196
-0
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2026 LibreCode coop and contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import { beforeEach, describe, expect, it, vi } from 'vitest'
7+
import { flushPromises, mount } from '@vue/test-utils'
8+
import { createPinia, setActivePinia } from 'pinia'
9+
10+
import FilesList from '../../../views/FilesList/FilesList.vue'
11+
import { useFilesStore } from '../../../store/files.js'
12+
import { useUserConfigStore } from '../../../store/userconfig.js'
13+
14+
vi.mock('@nextcloud/l10n', () => ({
15+
t: vi.fn((_app: string, text: string) => text),
16+
}))
17+
18+
vi.mock('@nextcloud/logger', () => ({
19+
getLogger: vi.fn(() => ({
20+
error: vi.fn(),
21+
warn: vi.fn(),
22+
info: vi.fn(),
23+
debug: vi.fn(),
24+
})),
25+
getLoggerBuilder: vi.fn(() => ({
26+
setApp: vi.fn().mockReturnThis(),
27+
detectUser: vi.fn().mockReturnThis(),
28+
build: vi.fn(() => ({
29+
error: vi.fn(),
30+
warn: vi.fn(),
31+
info: vi.fn(),
32+
debug: vi.fn(),
33+
})),
34+
})),
35+
}))
36+
37+
vi.mock('@nextcloud/axios', () => ({
38+
default: {
39+
get: vi.fn(),
40+
post: vi.fn(),
41+
delete: vi.fn(),
42+
patch: vi.fn(),
43+
},
44+
}))
45+
46+
vi.mock('@nextcloud/router', () => ({
47+
generateOcsUrl: vi.fn((path: string) => `/ocs/v2.php${path}`),
48+
}))
49+
50+
vi.mock('@nextcloud/auth', () => ({
51+
getCurrentUser: vi.fn(() => ({
52+
uid: 'testuser',
53+
displayName: 'Test User',
54+
})),
55+
}))
56+
57+
vi.mock('@nextcloud/event-bus', () => ({
58+
emit: vi.fn(),
59+
subscribe: vi.fn(),
60+
}))
61+
62+
vi.mock('@nextcloud/initial-state', () => ({
63+
loadState: vi.fn((_app: string, _key: string, defaultValue: unknown) => defaultValue),
64+
}))
65+
66+
vi.mock('@nextcloud/moment', () => ({
67+
default: vi.fn(() => ({
68+
format: () => 'date',
69+
fromNow: () => '2 days ago',
70+
})),
71+
}))
72+
73+
vi.mock('@nextcloud/vue/components/NcAppContent', () => ({
74+
default: { name: 'NcAppContent', template: '<div><slot /></div>' },
75+
}))
76+
vi.mock('@nextcloud/vue/components/NcBreadcrumb', () => ({
77+
default: { name: 'NcBreadcrumb', template: '<div><slot name="icon" /></div>' },
78+
}))
79+
vi.mock('@nextcloud/vue/components/NcBreadcrumbs', () => ({
80+
default: { name: 'NcBreadcrumbs', template: '<div><slot /><slot name="actions" /></div>' },
81+
}))
82+
vi.mock('@nextcloud/vue/components/NcButton', () => ({
83+
default: { name: 'NcButton', template: '<button><slot name="icon" /></button>' },
84+
}))
85+
vi.mock('@nextcloud/vue/components/NcEmptyContent', () => ({
86+
default: { name: 'NcEmptyContent', template: '<section><slot name="action" /><slot name="icon" /></section>' },
87+
}))
88+
vi.mock('@nextcloud/vue/components/NcIconSvgWrapper', () => ({
89+
default: {
90+
name: 'NcIconSvgWrapper',
91+
props: ['path', 'svg', 'size'],
92+
template: '<i class="nc-icon" :data-path="path" :data-svg="svg" />',
93+
},
94+
}))
95+
vi.mock('@nextcloud/vue/components/NcLoadingIcon', () => ({
96+
default: { name: 'NcLoadingIcon', template: '<span class="loading" />' },
97+
}))
98+
99+
vi.mock('../../../views/FilesList/FilesListVirtual.vue', () => ({
100+
default: {
101+
name: 'FilesListVirtual',
102+
props: ['nodes', 'loading'],
103+
template: '<div class="virtual-list"><slot name="empty" /></div>',
104+
},
105+
}))
106+
107+
vi.mock('../../../components/Request/RequestPicker.vue', () => ({
108+
default: {
109+
name: 'RequestPicker',
110+
template: '<div class="request-picker-stub" />',
111+
},
112+
}))
113+
114+
const routeMock = {
115+
query: {},
116+
}
117+
118+
describe('FilesList.vue rendering rules', () => {
119+
beforeEach(() => {
120+
setActivePinia(createPinia())
121+
vi.clearAllMocks()
122+
})
123+
124+
function mountComponent() {
125+
return mount(FilesList, {
126+
global: {
127+
mocks: {
128+
$route: routeMock,
129+
},
130+
stubs: {
131+
ListViewIcon: {
132+
template: '<i class="list-view-icon" />',
133+
},
134+
},
135+
},
136+
})
137+
}
138+
139+
it('exposes mdi icons from setup for template bindings', async () => {
140+
const filesStore = useFilesStore()
141+
vi.spyOn(filesStore, 'getAllFiles').mockResolvedValue({})
142+
143+
const wrapper = mountComponent()
144+
await flushPromises()
145+
146+
expect(wrapper.vm.mdiFolder).toBeTruthy()
147+
expect(wrapper.vm.mdiViewGrid).toBeTruthy()
148+
})
149+
150+
it('shows empty-state request action when user can request sign', async () => {
151+
const filesStore = useFilesStore()
152+
const userConfigStore = useUserConfigStore()
153+
154+
filesStore.canRequestSign = true
155+
filesStore.files = {}
156+
filesStore.ordered = []
157+
userConfigStore.files_list_grid_view = false
158+
vi.spyOn(filesStore, 'getAllFiles').mockResolvedValue({})
159+
160+
const wrapper = mountComponent()
161+
await flushPromises()
162+
163+
const pickers = wrapper.findAll('.request-picker-stub')
164+
expect(pickers).toHaveLength(2)
165+
})
166+
167+
it('hides empty-state request action when user cannot request sign', async () => {
168+
const filesStore = useFilesStore()
169+
const userConfigStore = useUserConfigStore()
170+
171+
filesStore.canRequestSign = false
172+
filesStore.files = {}
173+
filesStore.ordered = []
174+
userConfigStore.files_list_grid_view = false
175+
vi.spyOn(filesStore, 'getAllFiles').mockResolvedValue({})
176+
177+
const wrapper = mountComponent()
178+
await flushPromises()
179+
180+
const pickers = wrapper.findAll('.request-picker-stub')
181+
expect(pickers).toHaveLength(1)
182+
})
183+
184+
it('renders grid toggle icon path when in list mode', async () => {
185+
const filesStore = useFilesStore()
186+
const userConfigStore = useUserConfigStore()
187+
vi.spyOn(filesStore, 'getAllFiles').mockResolvedValue({})
188+
userConfigStore.files_list_grid_view = false
189+
190+
const wrapper = mountComponent()
191+
await flushPromises()
192+
193+
const iconWithPath = wrapper.findAll('.nc-icon').find((node) => !!node.attributes('data-path'))
194+
expect(iconWithPath?.attributes('data-path')).toBe(wrapper.vm.mdiViewGrid)
195+
})
196+
})

0 commit comments

Comments
 (0)