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 { mount } from '@vue/test-utils'
8+
9+ import FilesListVirtual from '../../../views/FilesList/FilesListVirtual.vue'
10+
11+ const filesStoreMock = { }
12+ const selectionStoreMock = {
13+ selected : [ ] as Array < { id : number } > ,
14+ }
15+ const userConfigStoreMock = {
16+ files_list_grid_view : false ,
17+ }
18+
19+ vi . mock ( '@nextcloud/l10n' , ( ) => ( {
20+ t : vi . fn ( ( _app : string , text : string ) => text ) ,
21+ n : vi . fn ( ( _app : string , singular : string , plural : string , count : number , params ?: Record < string , number > ) => {
22+ const template = count === 1 ? singular : plural
23+ return template . replace ( '{count}' , String ( params ?. count ?? count ) )
24+ } ) ,
25+ } ) )
26+
27+ vi . mock ( '../../../store/files.js' , ( ) => ( {
28+ useFilesStore : vi . fn ( ( ) => filesStoreMock ) ,
29+ } ) )
30+
31+ vi . mock ( '../../../store/selection.js' , ( ) => ( {
32+ useSelectionStore : vi . fn ( ( ) => selectionStoreMock ) ,
33+ } ) )
34+
35+ vi . mock ( '../../../store/userconfig.js' , ( ) => ( {
36+ useUserConfigStore : vi . fn ( ( ) => userConfigStoreMock ) ,
37+ } ) )
38+
39+ vi . mock ( '../../../views/FilesList/FileEntry/FileEntry.vue' , ( ) => ( {
40+ default : {
41+ name : 'FileEntry' ,
42+ template : '<div class="file-entry-stub" />' ,
43+ } ,
44+ } ) )
45+
46+ vi . mock ( '../../../views/FilesList/FileEntry/FileEntryGrid.vue' , ( ) => ( {
47+ default : {
48+ name : 'FileEntryGrid' ,
49+ template : '<div class="file-entry-grid-stub" />' ,
50+ } ,
51+ } ) )
52+
53+ vi . mock ( '../../../views/FilesList/FileListFilter/FileListFilterChips.vue' , ( ) => ( {
54+ default : {
55+ name : 'FileListFilterChips' ,
56+ template : '<div class="file-list-filter-chips-stub" />' ,
57+ } ,
58+ } ) )
59+
60+ vi . mock ( '../../../views/FilesList/FilesListTableFooter.vue' , ( ) => ( {
61+ default : {
62+ name : 'FilesListTableFooter' ,
63+ template : '<div class="files-list-table-footer-stub" />' ,
64+ } ,
65+ } ) )
66+
67+ vi . mock ( '../../../views/FilesList/FilesListTableHeader.vue' , ( ) => ( {
68+ default : {
69+ name : 'FilesListTableHeader' ,
70+ props : [ 'nodes' ] ,
71+ template : '<div class="files-list-table-header-stub">{{ nodes.length }}</div>' ,
72+ } ,
73+ } ) )
74+
75+ vi . mock ( '../../../views/FilesList/FilesListTableHeaderActions.vue' , ( ) => ( {
76+ default : {
77+ name : 'FilesListTableHeaderActions' ,
78+ template : '<div class="files-list-table-header-actions-stub" />' ,
79+ } ,
80+ } ) )
81+
82+ vi . mock ( '../../../views/FilesList/VirtualList.vue' , ( ) => ( {
83+ default : {
84+ name : 'VirtualList' ,
85+ props : [ 'dataComponent' , 'loading' , 'caption' ] ,
86+ template : `
87+ <div class="virtual-list-stub"
88+ :data-component="dataComponent?.name"
89+ :data-loading="String(loading)"
90+ :data-caption="caption">
91+ <div class="filters-slot"><slot name="filters" /></div>
92+ <div class="header-overlay-slot"><slot name="header-overlay" /></div>
93+ <div class="header-slot"><slot name="header" /></div>
94+ <div class="empty-slot"><slot name="empty" /></div>
95+ <div class="footer-slot"><slot name="footer" /></div>
96+ </div>
97+ ` ,
98+ } ,
99+ } ) )
100+
101+ describe ( 'FilesListVirtual.vue' , ( ) => {
102+ const nodes = [ { id : 1 , basename : 'contract.pdf' } ]
103+
104+ const createWrapper = ( ) => mount ( FilesListVirtual , {
105+ props : {
106+ nodes,
107+ loading : false ,
108+ } ,
109+ slots : {
110+ empty : '<div class="empty-content">Nothing here</div>' ,
111+ } ,
112+ } )
113+
114+ beforeEach ( ( ) => {
115+ selectionStoreMock . selected = [ ]
116+ userConfigStoreMock . files_list_grid_view = false
117+ } )
118+
119+ it ( 'renders the table row component when grid view is disabled' , ( ) => {
120+ const wrapper = createWrapper ( )
121+
122+ expect ( wrapper . find ( '.virtual-list-stub' ) . attributes ( 'data-component' ) ) . toBe ( 'FileEntry' )
123+ expect ( wrapper . vm . selectedNodes ) . toEqual ( [ ] )
124+ expect ( wrapper . vm . isNoneSelected ) . toBe ( true )
125+ } )
126+
127+ it ( 'renders the grid row component when grid view is enabled' , ( ) => {
128+ userConfigStoreMock . files_list_grid_view = true
129+
130+ const wrapper = createWrapper ( )
131+
132+ expect ( wrapper . find ( '.virtual-list-stub' ) . attributes ( 'data-component' ) ) . toBe ( 'FileEntryGrid' )
133+ } )
134+
135+ it ( 'shows the header overlay when files are selected' , ( ) => {
136+ selectionStoreMock . selected = [ { id : 7 } , { id : 8 } ]
137+
138+ const wrapper = createWrapper ( )
139+
140+ expect ( wrapper . vm . selectedNodes ) . toHaveLength ( 2 )
141+ expect ( wrapper . find ( '.files-list__selected' ) . text ( ) ) . toContain ( 'selected' )
142+ expect ( wrapper . find ( '.files-list-table-header-actions-stub' ) . exists ( ) ) . toBe ( true )
143+ } )
144+
145+ it ( 'passes caption, header, footer, and empty slots to VirtualList' , ( ) => {
146+ const wrapper = createWrapper ( )
147+
148+ expect ( wrapper . vm . caption ) . toBe ( 'List of files. Column headers with buttons are sortable.' )
149+ expect ( wrapper . find ( '.virtual-list-stub' ) . attributes ( 'data-caption' ) ) . toBe ( wrapper . vm . caption )
150+ expect ( wrapper . find ( '.files-list-table-header-stub' ) . text ( ) ) . toBe ( '1' )
151+ expect ( wrapper . find ( '.files-list-table-footer-stub' ) . exists ( ) ) . toBe ( true )
152+ expect ( wrapper . find ( '.file-list-filter-chips-stub' ) . exists ( ) ) . toBe ( true )
153+ expect ( wrapper . find ( '.empty-content' ) . text ( ) ) . toBe ( 'Nothing here' )
154+ } )
155+ } )
0 commit comments