Skip to content

Commit 07c66c5

Browse files
committed
chore(files): add actions cypress tests
Signed-off-by: skjnldsv <[email protected]>
1 parent fcf5286 commit 07c66c5

File tree

2 files changed

+237
-6
lines changed

2 files changed

+237
-6
lines changed

cypress/e2e/files/FilesUtils.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,33 @@ export const getActionsForFile = (filename: string) => getRowForFile(filename).f
1414
export const getActionButtonForFileId = (fileid: number) => getActionsForFileId(fileid).findByRole('button', { name: 'Actions' })
1515
export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).findByRole('button', { name: 'Actions' })
1616

17+
export const getActionEntryForFileId = (fileid: number, actionId: string) => {
18+
return cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
19+
}
20+
export const getActionEntryForFile = (filename: string, actionId: string) => {
21+
return cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
22+
}
23+
1724
export const triggerActionForFileId = (fileid: number, actionId: string) => {
25+
// Even if it's inline, we open the action menu to get all actions visible
1826
getActionButtonForFileId(fileid).click({ force: true })
19-
// Getting the last button to avoid the one from popup fading out
20-
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last()
27+
getActionEntryForFileId(fileid, actionId)
28+
.find('button').last()
2129
.should('exist').click({ force: true })
2230
}
2331
export const triggerActionForFile = (filename: string, actionId: string) => {
32+
// Even if it's inline, we open the action menu to get all actions visible
2433
getActionButtonForFile(filename).click({ force: true })
25-
// Getting the last button to avoid the one from popup fading out
26-
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last()
34+
getActionEntryForFile(filename, actionId)
35+
.find('button').last()
2736
.should('exist').click({ force: true })
2837
}
2938

3039
export const triggerInlineActionForFileId = (fileid: number, actionId: string) => {
3140
getActionsForFileId(fileid).find(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click()
3241
}
3342
export const triggerInlineActionForFile = (filename: string, actionId: string) => {
34-
getActionsForFile(filename).get(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click()
43+
getActionsForFile(filename).find(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click()
3544
}
3645

3746
export const selectAllFiles = () => {
@@ -58,8 +67,14 @@ export const selectRowForFile = (filename: string, options: Partial<Cypress.Clic
5867

5968
}
6069

70+
export const getSelectionActionButton = () => cy.get('[data-cy-files-list-selection-actions]').findByRole('button', { name: 'Actions' })
71+
export const getSelectionActionEntry = (actionId: string) => cy.get(`[data-cy-files-list-selection-action="${CSS.escape(actionId)}"]`)
6172
export const triggerSelectionAction = (actionId: string) => {
62-
cy.get(`button[data-cy-files-list-selection-action="${CSS.escape(actionId)}"]`).should('exist').click()
73+
// Even if it's inline, we open the action menu to get all actions visible
74+
getSelectionActionButton().click({ force: true })
75+
getSelectionActionEntry(actionId)
76+
.find('button').last()
77+
.should('exist').click()
6378
}
6479

6580
export const moveFile = (fileName: string, dirPath: string) => {

cypress/e2e/files/files-actions.cy.ts

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
/**
2+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
3+
* SPDX-License-Identifier: AGPL-3.0-or-later
4+
*/
5+
6+
import type { User } from '@nextcloud/cypress'
7+
import { FileAction } from '@nextcloud/files'
8+
9+
import { getActionButtonForFileId, getActionEntryForFileId, getRowForFile, getSelectionActionButton, getSelectionActionEntry, selectRowForFile, triggerActionForFile, triggerActionForFileId } from './FilesUtils'
10+
import { ACTION_COPY_MOVE } from '../../../apps/files/src/actions/moveOrCopyAction'
11+
import { ACTION_DELETE } from '../../../apps/files/src/actions/deleteAction'
12+
import { ACTION_DETAILS } from '../../../apps/files/src/actions/sidebarAction'
13+
import { ACTION_SHARING_STATUS } from '../../../apps/files_sharing/src/files_actions/sharingStatusAction'
14+
15+
declare global {
16+
interface Window {
17+
_nc_fileactions: FileAction[]
18+
}
19+
}
20+
21+
// Those two arrays doesn't represent the full list of actions
22+
// the goal is to test a few, we're not trying to match the full feature set
23+
const expectedDefaultActionsIDs = [
24+
ACTION_COPY_MOVE,
25+
ACTION_DELETE,
26+
ACTION_DETAILS,
27+
ACTION_SHARING_STATUS,
28+
]
29+
const expectedDefaultSelectionActionsIDs = [
30+
ACTION_COPY_MOVE,
31+
ACTION_DELETE,
32+
]
33+
34+
describe('Files: Actions', { testIsolation: true }, () => {
35+
let user: User
36+
let fileId: number = 0
37+
38+
beforeEach(() => cy.createRandomUser().then(($user) => {
39+
user = $user
40+
41+
cy.uploadContent(user, new Blob([]), 'image/jpeg', '/image.jpg').then((response) => {
42+
fileId = Number.parseInt(response.headers['oc-fileid'] ?? '0')
43+
})
44+
cy.login(user)
45+
}))
46+
47+
it('Show some standard actions', () => {
48+
cy.visit('/apps/files')
49+
getRowForFile('image.jpg').should('be.visible')
50+
51+
expectedDefaultActionsIDs.forEach((actionId) => {
52+
// Open the menu
53+
getActionButtonForFileId(fileId).click({ force: true })
54+
// Check the action is visible
55+
getActionEntryForFileId(fileId, actionId).should('be.visible')
56+
})
57+
})
58+
59+
it('Show some nested actions', () => {
60+
const parent = new FileAction({
61+
id: 'nested-action',
62+
displayName: () => 'Nested Action',
63+
exec: cy.spy(),
64+
iconSvgInline: () => '<svg></svg>',
65+
})
66+
67+
const child1 = new FileAction({
68+
id: 'nested-child-1',
69+
displayName: () => 'Nested Child 1',
70+
exec: cy.spy(),
71+
iconSvgInline: () => '<svg></svg>',
72+
parent: 'nested-action',
73+
})
74+
75+
const child2 = new FileAction({
76+
id: 'nested-child-2',
77+
displayName: () => 'Nested Child 2',
78+
exec: cy.spy(),
79+
iconSvgInline: () => '<svg></svg>',
80+
parent: 'nested-action',
81+
})
82+
83+
cy.visit('/apps/files', {
84+
// Cannot use registerFileAction here
85+
onBeforeLoad: (win) => {
86+
if (!win._nc_fileactions) win._nc_fileactions = []
87+
// Cannot use registerFileAction here
88+
win._nc_fileactions.push(parent)
89+
win._nc_fileactions.push(child1)
90+
win._nc_fileactions.push(child2)
91+
}
92+
})
93+
94+
// Open the menu
95+
getActionButtonForFileId(fileId).click({ force: true })
96+
97+
// Check we have the parent action but not the children
98+
getActionEntryForFileId(fileId, 'nested-action').should('be.visible')
99+
getActionEntryForFileId(fileId, 'menu-back').should('not.exist')
100+
getActionEntryForFileId(fileId, 'nested-child-1').should('not.exist')
101+
getActionEntryForFileId(fileId, 'nested-child-2').should('not.exist')
102+
103+
// Click on the parent action
104+
getActionEntryForFileId(fileId, 'nested-action')
105+
.find('button').last()
106+
.should('exist').click({ force: true })
107+
108+
// Check we have the children and the back button but not the parent
109+
getActionEntryForFileId(fileId, 'nested-action').should('not.exist')
110+
getActionEntryForFileId(fileId, 'menu-back').should('be.visible')
111+
getActionEntryForFileId(fileId, 'nested-child-1').should('be.visible')
112+
getActionEntryForFileId(fileId, 'nested-child-2').should('be.visible')
113+
114+
// Click on the back button
115+
getActionEntryForFileId(fileId, 'menu-back')
116+
.find('button').last()
117+
.should('exist').click({ force: true })
118+
119+
// Check we have the parent action but not the children
120+
getActionEntryForFileId(fileId, 'nested-action').should('be.visible')
121+
getActionEntryForFileId(fileId, 'menu-back').should('not.exist')
122+
getActionEntryForFileId(fileId, 'nested-child-1').should('not.exist')
123+
getActionEntryForFileId(fileId, 'nested-child-2').should('not.exist')
124+
})
125+
126+
it('Show some actions for a selection', () => {
127+
cy.visit('/apps/files')
128+
getRowForFile('image.jpg').should('be.visible')
129+
130+
selectRowForFile('image.jpg')
131+
132+
cy.get('[data-cy-files-list-selection-actions]').should('be.visible')
133+
// We show 3 actions for the selection by default, then the menu button
134+
cy.get('[data-cy-files-list-selection-action]').should('have.length', 3)
135+
getSelectionActionButton().should('be.visible')
136+
137+
// Open the menu
138+
getSelectionActionButton().click({ force: true })
139+
140+
// Check the action is visible
141+
expectedDefaultSelectionActionsIDs.forEach((actionId) => {
142+
getActionEntryForFileId(fileId, actionId).should('be.visible')
143+
})
144+
})
145+
146+
it('Show some nested actions for a selection', () => {
147+
const parent = new FileAction({
148+
id: 'nested-action',
149+
displayName: () => 'Nested Action',
150+
exec: cy.spy(),
151+
iconSvgInline: () => '<svg></svg>',
152+
})
153+
154+
const child1 = new FileAction({
155+
id: 'nested-child-1',
156+
displayName: () => 'Nested Child 1',
157+
exec: cy.spy(),
158+
execBatch: cy.spy(),
159+
iconSvgInline: () => '<svg></svg>',
160+
parent: 'nested-action',
161+
})
162+
163+
const child2 = new FileAction({
164+
id: 'nested-child-2',
165+
displayName: () => 'Nested Child 2',
166+
exec: cy.spy(),
167+
execBatch: cy.spy(),
168+
iconSvgInline: () => '<svg></svg>',
169+
parent: 'nested-action',
170+
})
171+
172+
cy.visit('/apps/files', {
173+
// Cannot use registerFileAction here
174+
onBeforeLoad: (win) => {
175+
if (!win._nc_fileactions) win._nc_fileactions = []
176+
// Cannot use registerFileAction here
177+
win._nc_fileactions.push(parent)
178+
win._nc_fileactions.push(child1)
179+
win._nc_fileactions.push(child2)
180+
}
181+
})
182+
183+
selectRowForFile('image.jpg')
184+
185+
// Open the menu
186+
getSelectionActionButton().click({ force: true })
187+
188+
// Check we have the parent action but not the children
189+
getSelectionActionEntry('nested-action').should('be.visible')
190+
getSelectionActionEntry('menu-back').should('not.exist')
191+
getSelectionActionEntry('nested-child-1').should('not.exist')
192+
getSelectionActionEntry('nested-child-2').should('not.exist')
193+
194+
// Click on the parent action
195+
getSelectionActionEntry('nested-action')
196+
.find('button').last()
197+
.should('exist').click({ force: true })
198+
199+
// Check we have the children and the back button but not the parent
200+
getSelectionActionEntry('nested-action').should('not.exist')
201+
getSelectionActionEntry('menu-back').should('be.visible')
202+
getSelectionActionEntry('nested-child-1').should('be.visible')
203+
getSelectionActionEntry('nested-child-2').should('be.visible')
204+
205+
// Click on the back button
206+
getSelectionActionEntry('menu-back')
207+
.find('button').last()
208+
.should('exist').click({ force: true })
209+
210+
// Check we have the parent action but not the children
211+
getSelectionActionEntry('nested-action').should('be.visible')
212+
getSelectionActionEntry('menu-back').should('not.exist')
213+
getSelectionActionEntry('nested-child-1').should('not.exist')
214+
getSelectionActionEntry('nested-child-2').should('not.exist')
215+
})
216+
})

0 commit comments

Comments
 (0)