mirror of
https://github.com/nextcloud/server.git
synced 2026-06-11 09:42:09 -04:00
Merge pull request #61152 from nextcloud/test/migrate-files-actions-playwright
test(files): migrate files actions e2e from Cypress to Playwright
This commit is contained in:
commit
954fc50274
3 changed files with 78 additions and 74 deletions
|
|
@ -1,70 +0,0 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { User } from '@nextcloud/e2e-test-server/cypress'
|
||||
|
||||
import { getActionButtonForFileId, getActionEntryForFileId, getRowForFile, getSelectionActionButton, getSelectionActionEntry, selectRowForFile } from './FilesUtils.ts'
|
||||
|
||||
const ACTION_DELETE = 'delete'
|
||||
const ACTION_COPY_MOVE = 'move-copy'
|
||||
const ACTION_DETAILS = 'details'
|
||||
|
||||
// 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,
|
||||
]
|
||||
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')
|
||||
// Close the menu
|
||||
cy.get('body').click({ force: true })
|
||||
})
|
||||
})
|
||||
|
||||
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')
|
||||
})
|
||||
})
|
||||
})
|
||||
41
tests/playwright/e2e/files/files-actions.spec.ts
Normal file
41
tests/playwright/e2e/files/files-actions.spec.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { test, expect } from '../../support/fixtures/files-page.ts'
|
||||
import { rm, uploadContent } from '../../support/utils/dav.ts'
|
||||
|
||||
// A representative subset of the default actions, not the full feature set.
|
||||
const expectedRowActions = ['move-copy', 'delete', 'details']
|
||||
const expectedSelectionActions = ['move-copy', 'delete']
|
||||
|
||||
test.describe('Files: Actions', () => {
|
||||
test.beforeEach(async ({ page, user, filesListPage }) => {
|
||||
// New users get welcome.txt — remove it so the list contains only our test file
|
||||
await rm(page.request, user, '/welcome.txt')
|
||||
await uploadContent(page.request, user, Buffer.alloc(0), 'image/jpeg', '/image.jpg')
|
||||
await filesListPage.open()
|
||||
})
|
||||
|
||||
test('shows the standard row actions', async ({ filesListPage }) => {
|
||||
await expect(filesListPage.getRowForFile('image.jpg')).toBeVisible()
|
||||
|
||||
const menu = await filesListPage.openActionsMenuForFile('image.jpg')
|
||||
for (const actionId of expectedRowActions) {
|
||||
await expect(filesListPage.getActionButtonInMenu(menu, actionId)).toBeVisible()
|
||||
}
|
||||
})
|
||||
|
||||
test('shows the standard actions for a selection', async ({ filesListPage }) => {
|
||||
await expect(filesListPage.getRowForFile('image.jpg')).toBeVisible()
|
||||
|
||||
await filesListPage.selectRowForFile('image.jpg')
|
||||
await expect(filesListPage.getSelectionActionsToolbar()).toBeVisible()
|
||||
|
||||
await filesListPage.openSelectionActionsMenu()
|
||||
for (const actionId of expectedSelectionActions) {
|
||||
await expect(filesListPage.getSelectionActionEntry(actionId)).toBeVisible()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -68,12 +68,45 @@ export class FilesListPage {
|
|||
.click({ force: true })
|
||||
}
|
||||
|
||||
async selectRowForFile(filename: string): Promise<void> {
|
||||
// The checkbox is visually hidden inside NcCheckboxRadioSwitch, so force the check
|
||||
await this.getRowForFile(filename)
|
||||
.getByRole('checkbox', { name: /Toggle selection/ })
|
||||
.check({ force: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* The toolbar that replaces the list header once one or more rows are selected.
|
||||
*/
|
||||
getSelectionActionsToolbar(): Locator {
|
||||
return this.page.locator('[data-cy-files-list-selection-actions]')
|
||||
}
|
||||
|
||||
private getSelectionActionsButton(): Locator {
|
||||
return this.getSelectionActionsToolbar().getByRole('button', { name: 'Actions' })
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the bulk-selection actions menu. Pair with {@link getSelectionActionEntry}
|
||||
* to inspect an entry (e.g. assert it is visible) before acting; for a plain
|
||||
* "open and click" use {@link triggerSelectionAction}.
|
||||
*/
|
||||
async openSelectionActionsMenu(): Promise<void> {
|
||||
await this.getSelectionActionsButton().click({ force: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* A selection action entry. Matched at page level on the product-owned
|
||||
* attribute because selection actions can render inline or inside the menu popover.
|
||||
*/
|
||||
getSelectionActionEntry(actionId: string): Locator {
|
||||
return this.page.locator(`[data-cy-files-list-selection-action="${actionId}"]`)
|
||||
}
|
||||
|
||||
async triggerSelectionAction(actionId: string): Promise<void> {
|
||||
const actionsButton = this.page.locator('[data-cy-files-list-selection-actions]')
|
||||
.getByRole('button', { name: 'Actions' })
|
||||
await actionsButton.click({ force: true })
|
||||
await this.openSelectionActionsMenu()
|
||||
// NcActionButton renders as <li data-cy-...><button role="menuitem">
|
||||
const actionButton = this.page.locator(`[data-cy-files-list-selection-action="${actionId}"] button`)
|
||||
const actionButton = this.getSelectionActionEntry(actionId).locator('button')
|
||||
await actionButton.waitFor({ state: 'visible' })
|
||||
await actionButton.click()
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue