mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 08:44:07 -04:00
chore(files): add actions cypress tests
Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
This commit is contained in:
parent
d8b6e83805
commit
738447bcd5
5 changed files with 244 additions and 12 deletions
|
|
@ -294,7 +294,7 @@ async function openFilePickerForAction(
|
|||
return promise
|
||||
}
|
||||
|
||||
export const ACTION_COPY_MOVE = 'copy-move'
|
||||
export const ACTION_COPY_MOVE = 'move-copy'
|
||||
export const action = new FileAction({
|
||||
id: ACTION_COPY_MOVE,
|
||||
displayName(nodes: Node[]) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
*/
|
||||
|
||||
import type { User } from '@nextcloud/cypress'
|
||||
import { ACTION_COPY_MOVE } from "../../../apps/files/src/actions/moveOrCopyAction"
|
||||
|
||||
export const getRowForFileId = (fileid: number) => cy.get(`[data-cy-files-list-row-fileid="${fileid}"]`)
|
||||
export const getRowForFile = (filename: string) => cy.get(`[data-cy-files-list-row-name="${CSS.escape(filename)}"]`)
|
||||
|
|
@ -14,16 +15,25 @@ export const getActionsForFile = (filename: string) => getRowForFile(filename).f
|
|||
export const getActionButtonForFileId = (fileid: number) => getActionsForFileId(fileid).findByRole('button', { name: 'Actions' })
|
||||
export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).findByRole('button', { name: 'Actions' })
|
||||
|
||||
export const getActionEntryForFileId = (fileid: number, actionId: string) => {
|
||||
return cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
|
||||
}
|
||||
export const getActionEntryForFile = (filename: string, actionId: string) => {
|
||||
return cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`)
|
||||
}
|
||||
|
||||
export const triggerActionForFileId = (fileid: number, actionId: string) => {
|
||||
// Even if it's inline, we open the action menu to get all actions visible
|
||||
getActionButtonForFileId(fileid).click({ force: true })
|
||||
// Getting the last button to avoid the one from popup fading out
|
||||
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last()
|
||||
getActionEntryForFileId(fileid, actionId)
|
||||
.find('button').last()
|
||||
.should('exist').click({ force: true })
|
||||
}
|
||||
export const triggerActionForFile = (filename: string, actionId: string) => {
|
||||
// Even if it's inline, we open the action menu to get all actions visible
|
||||
getActionButtonForFile(filename).click({ force: true })
|
||||
// Getting the last button to avoid the one from popup fading out
|
||||
cy.get(`[data-cy-files-list-row-action="${CSS.escape(actionId)}"] > button`).last()
|
||||
getActionEntryForFile(filename, actionId)
|
||||
.find('button').last()
|
||||
.should('exist').click({ force: true })
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +41,7 @@ export const triggerInlineActionForFileId = (fileid: number, actionId: string) =
|
|||
getActionsForFileId(fileid).find(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click()
|
||||
}
|
||||
export const triggerInlineActionForFile = (filename: string, actionId: string) => {
|
||||
getActionsForFile(filename).get(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click()
|
||||
getActionsForFile(filename).find(`button[data-cy-files-list-row-action="${CSS.escape(actionId)}"]`).should('exist').click()
|
||||
}
|
||||
|
||||
export const selectAllFiles = () => {
|
||||
|
|
@ -58,13 +68,21 @@ export const selectRowForFile = (filename: string, options: Partial<Cypress.Clic
|
|||
|
||||
}
|
||||
|
||||
export const getSelectionActionButton = () => cy.get('[data-cy-files-list-selection-actions]').findByRole('button', { name: 'Actions' })
|
||||
export const getSelectionActionEntry = (actionId: string) => cy.get(`[data-cy-files-list-selection-action="${CSS.escape(actionId)}"]`)
|
||||
export const triggerSelectionAction = (actionId: string) => {
|
||||
cy.get(`button[data-cy-files-list-selection-action="${CSS.escape(actionId)}"]`).should('exist').click()
|
||||
// Even if it's inline, we open the action menu to get all actions visible
|
||||
getSelectionActionButton().click({ force: true })
|
||||
// the entry might already be a button or a button might its child
|
||||
getSelectionActionEntry(actionId)
|
||||
.then($el => $el.is('button') ? cy.wrap($el) : cy.wrap($el).findByRole('button').last())
|
||||
.should('exist')
|
||||
.click()
|
||||
}
|
||||
|
||||
export const moveFile = (fileName: string, dirPath: string) => {
|
||||
getRowForFile(fileName).should('be.visible')
|
||||
triggerActionForFile(fileName, 'move-copy')
|
||||
triggerActionForFile(fileName, ACTION_COPY_MOVE)
|
||||
|
||||
cy.get('.file-picker').within(() => {
|
||||
// intercept the copy so we can wait for it
|
||||
|
|
@ -95,7 +113,7 @@ export const moveFile = (fileName: string, dirPath: string) => {
|
|||
|
||||
export const copyFile = (fileName: string, dirPath: string) => {
|
||||
getRowForFile(fileName).should('be.visible')
|
||||
triggerActionForFile(fileName, 'move-copy')
|
||||
triggerActionForFile(fileName, ACTION_COPY_MOVE)
|
||||
|
||||
cy.get('.file-picker').within(() => {
|
||||
// intercept the copy so we can wait for it
|
||||
|
|
|
|||
214
cypress/e2e/files/files-actions.cy.ts
Normal file
214
cypress/e2e/files/files-actions.cy.ts
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { User } from '@nextcloud/cypress'
|
||||
import { FileAction } from '@nextcloud/files'
|
||||
|
||||
import { getActionButtonForFileId, getActionEntryForFileId, getRowForFile, getSelectionActionButton, getSelectionActionEntry, selectRowForFile, triggerActionForFile, triggerActionForFileId } from './FilesUtils'
|
||||
import { ACTION_COPY_MOVE } from '../../../apps/files/src/actions/moveOrCopyAction'
|
||||
import { ACTION_DELETE } from '../../../apps/files/src/actions/deleteAction'
|
||||
import { ACTION_DETAILS } from '../../../apps/files/src/actions/sidebarAction'
|
||||
import { ACTION_SHARING_STATUS } from '../../../apps/files_sharing/src/files_actions/sharingStatusAction'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
_nc_fileactions: FileAction[]
|
||||
}
|
||||
}
|
||||
|
||||
// Those two arrays doesn't represent the full list of actions
|
||||
// the goal is to test a few, we're not trying to match the full feature set
|
||||
const expectedDefaultActionsIDs = [
|
||||
ACTION_COPY_MOVE,
|
||||
ACTION_DELETE,
|
||||
ACTION_DETAILS,
|
||||
ACTION_SHARING_STATUS,
|
||||
]
|
||||
const expectedDefaultSelectionActionsIDs = [
|
||||
ACTION_COPY_MOVE,
|
||||
ACTION_DELETE,
|
||||
]
|
||||
|
||||
describe('Files: Actions', { testIsolation: true }, () => {
|
||||
let user: User
|
||||
let fileId: number = 0
|
||||
|
||||
beforeEach(() => cy.createRandomUser().then(($user) => {
|
||||
user = $user
|
||||
|
||||
cy.uploadContent(user, new Blob([]), 'image/jpeg', '/image.jpg').then((response) => {
|
||||
fileId = Number.parseInt(response.headers['oc-fileid'] ?? '0')
|
||||
})
|
||||
cy.login(user)
|
||||
}))
|
||||
|
||||
it('Show some standard actions', () => {
|
||||
cy.visit('/apps/files')
|
||||
getRowForFile('image.jpg').should('be.visible')
|
||||
|
||||
expectedDefaultActionsIDs.forEach((actionId) => {
|
||||
// Open the menu
|
||||
getActionButtonForFileId(fileId).click({ force: true })
|
||||
// Check the action is visible
|
||||
getActionEntryForFileId(fileId, actionId).should('be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
it('Show some nested actions', () => {
|
||||
const parent = new FileAction({
|
||||
id: 'nested-action',
|
||||
displayName: () => 'Nested Action',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
})
|
||||
|
||||
const child1 = new FileAction({
|
||||
id: 'nested-child-1',
|
||||
displayName: () => 'Nested Child 1',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
|
||||
const child2 = new FileAction({
|
||||
id: 'nested-child-2',
|
||||
displayName: () => 'Nested Child 2',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
|
||||
cy.visit('/apps/files', {
|
||||
// Cannot use registerFileAction here
|
||||
onBeforeLoad: (win) => {
|
||||
if (!win._nc_fileactions) win._nc_fileactions = []
|
||||
// Cannot use registerFileAction here
|
||||
win._nc_fileactions.push(parent)
|
||||
win._nc_fileactions.push(child1)
|
||||
win._nc_fileactions.push(child2)
|
||||
}
|
||||
})
|
||||
|
||||
// Open the menu
|
||||
getActionButtonForFileId(fileId).click({ force: true })
|
||||
|
||||
// Check we have the parent action but not the children
|
||||
getActionEntryForFileId(fileId, 'nested-action').should('be.visible')
|
||||
getActionEntryForFileId(fileId, 'menu-back').should('not.exist')
|
||||
getActionEntryForFileId(fileId, 'nested-child-1').should('not.exist')
|
||||
getActionEntryForFileId(fileId, 'nested-child-2').should('not.exist')
|
||||
|
||||
// Click on the parent action
|
||||
getActionEntryForFileId(fileId, 'nested-action')
|
||||
.find('button').last()
|
||||
.should('exist').click({ force: true })
|
||||
|
||||
// Check we have the children and the back button but not the parent
|
||||
getActionEntryForFileId(fileId, 'nested-action').should('not.exist')
|
||||
getActionEntryForFileId(fileId, 'menu-back').should('be.visible')
|
||||
getActionEntryForFileId(fileId, 'nested-child-1').should('be.visible')
|
||||
getActionEntryForFileId(fileId, 'nested-child-2').should('be.visible')
|
||||
|
||||
// Click on the back button
|
||||
getActionEntryForFileId(fileId, 'menu-back')
|
||||
.find('button').last()
|
||||
.should('exist').click({ force: true })
|
||||
|
||||
// Check we have the parent action but not the children
|
||||
getActionEntryForFileId(fileId, 'nested-action').should('be.visible')
|
||||
getActionEntryForFileId(fileId, 'menu-back').should('not.exist')
|
||||
getActionEntryForFileId(fileId, 'nested-child-1').should('not.exist')
|
||||
getActionEntryForFileId(fileId, 'nested-child-2').should('not.exist')
|
||||
})
|
||||
|
||||
it('Show some actions for a selection', () => {
|
||||
cy.visit('/apps/files')
|
||||
getRowForFile('image.jpg').should('be.visible')
|
||||
|
||||
selectRowForFile('image.jpg')
|
||||
|
||||
cy.get('[data-cy-files-list-selection-actions]').should('be.visible')
|
||||
getSelectionActionButton().should('be.visible')
|
||||
|
||||
// Open the menu
|
||||
getSelectionActionButton().click({ force: true })
|
||||
|
||||
// Check the action is visible
|
||||
expectedDefaultSelectionActionsIDs.forEach((actionId) => {
|
||||
getSelectionActionEntry(actionId).should('be.visible')
|
||||
})
|
||||
})
|
||||
|
||||
it('Show some nested actions for a selection', () => {
|
||||
const parent = new FileAction({
|
||||
id: 'nested-action',
|
||||
displayName: () => 'Nested Action',
|
||||
exec: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
})
|
||||
|
||||
const child1 = new FileAction({
|
||||
id: 'nested-child-1',
|
||||
displayName: () => 'Nested Child 1',
|
||||
exec: cy.spy(),
|
||||
execBatch: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
|
||||
const child2 = new FileAction({
|
||||
id: 'nested-child-2',
|
||||
displayName: () => 'Nested Child 2',
|
||||
exec: cy.spy(),
|
||||
execBatch: cy.spy(),
|
||||
iconSvgInline: () => '<svg></svg>',
|
||||
parent: 'nested-action',
|
||||
})
|
||||
|
||||
cy.visit('/apps/files', {
|
||||
// Cannot use registerFileAction here
|
||||
onBeforeLoad: (win) => {
|
||||
if (!win._nc_fileactions) win._nc_fileactions = []
|
||||
// Cannot use registerFileAction here
|
||||
win._nc_fileactions.push(parent)
|
||||
win._nc_fileactions.push(child1)
|
||||
win._nc_fileactions.push(child2)
|
||||
}
|
||||
})
|
||||
|
||||
selectRowForFile('image.jpg')
|
||||
|
||||
// Open the menu
|
||||
getSelectionActionButton().click({ force: true })
|
||||
|
||||
// Check we have the parent action but not the children
|
||||
getSelectionActionEntry('nested-action').should('be.visible')
|
||||
getSelectionActionEntry('menu-back').should('not.exist')
|
||||
getSelectionActionEntry('nested-child-1').should('not.exist')
|
||||
getSelectionActionEntry('nested-child-2').should('not.exist')
|
||||
|
||||
// Click on the parent action
|
||||
getSelectionActionEntry('nested-action')
|
||||
.find('button').last()
|
||||
.should('exist').click({ force: true })
|
||||
|
||||
// Check we have the children and the back button but not the parent
|
||||
getSelectionActionEntry('nested-action').should('not.exist')
|
||||
getSelectionActionEntry('menu-back').should('be.visible')
|
||||
getSelectionActionEntry('nested-child-1').should('be.visible')
|
||||
getSelectionActionEntry('nested-child-2').should('be.visible')
|
||||
|
||||
// Click on the back button
|
||||
getSelectionActionEntry('menu-back')
|
||||
.find('button').last()
|
||||
.should('exist').click({ force: true })
|
||||
|
||||
// Check we have the parent action but not the children
|
||||
getSelectionActionEntry('nested-action').should('be.visible')
|
||||
getSelectionActionEntry('menu-back').should('not.exist')
|
||||
getSelectionActionEntry('nested-child-1').should('not.exist')
|
||||
getSelectionActionEntry('nested-child-2').should('not.exist')
|
||||
})
|
||||
})
|
||||
|
|
@ -11,10 +11,11 @@ import {
|
|||
navigateToFolder,
|
||||
triggerActionForFile,
|
||||
} from '../files/FilesUtils.ts'
|
||||
import { ACTION_COPY_MOVE } from '../../../apps/files/src/actions/moveOrCopyAction.ts'
|
||||
|
||||
export const copyFileForbidden = (fileName: string, dirPath: string) => {
|
||||
getRowForFile(fileName).should('be.visible')
|
||||
triggerActionForFile(fileName, 'move-copy')
|
||||
triggerActionForFile(fileName, ACTION_COPY_MOVE)
|
||||
|
||||
cy.get('.file-picker').within(() => {
|
||||
// intercept the copy so we can wait for it
|
||||
|
|
@ -33,7 +34,7 @@ export const copyFileForbidden = (fileName: string, dirPath: string) => {
|
|||
|
||||
export const moveFileForbidden = (fileName: string, dirPath: string) => {
|
||||
getRowForFile(fileName).should('be.visible')
|
||||
triggerActionForFile(fileName, 'move-copy')
|
||||
triggerActionForFile(fileName, ACTION_COPY_MOVE)
|
||||
|
||||
cy.get('.file-picker').within(() => {
|
||||
// intercept the copy so we can wait for it
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ function triggerTagManagementDialogAction() {
|
|||
}
|
||||
|
||||
describe('Systemtags: Files bulk action', { testIsolation: false }, () => {
|
||||
let snapshot: string
|
||||
let user1: User
|
||||
let user2: User
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue