Browse Source

chore(files): add actions cypress tests

Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
pull/50364/head
skjnldsv 10 months ago
committed by John Molakvoæ (skjnldsv)
parent
commit
73e4a13a1c
No known key found for this signature in database GPG Key ID: 60C25B8C072916CF
  1. 2
      apps/files/src/actions/moveOrCopyAction.ts
  2. 34
      cypress/e2e/files/FilesUtils.ts
  3. 214
      cypress/e2e/files/files-actions.cy.ts
  4. 5
      cypress/e2e/files_sharing/files-copy-move.cy.ts
  5. 1
      cypress/e2e/systemtags/files-bulk-action.cy.ts

2
apps/files/src/actions/moveOrCopyAction.ts

@ -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[]) {

34
cypress/e2e/files/FilesUtils.ts

@ -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

@ -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')
})
})

5
cypress/e2e/files_sharing/files-copy-move.cy.ts

@ -10,10 +10,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
@ -32,7 +33,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

1
cypress/e2e/systemtags/files-bulk-action.cy.ts

@ -57,7 +57,6 @@ function triggerTagManagementDialogAction() {
}
describe('Systemtags: Files bulk action', { testIsolation: false }, () => {
let snapshot: string
let user1: User
let user2: User

Loading…
Cancel
Save