mirror of
https://github.com/nextcloud/server.git
synced 2026-06-23 07:30:41 -04:00
test(files): migrate files download e2e from Cypress to Playwright
Signed-off-by: Peter Ringelmann <peter.ringelmann@nextcloud.com>
This commit is contained in:
parent
692f5f3e30
commit
3e2100bf6d
4 changed files with 284 additions and 333 deletions
|
|
@ -1,333 +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 { zipFileContains } from '../../support/utils/assertions.ts'
|
||||
import { deleteDownloadsFolderBeforeEach } from '../../support/utils/deleteDownloadsFolder.ts'
|
||||
import { randomString } from '../../support/utils/randomString.ts'
|
||||
import { getRowForFile, navigateToFolder, triggerActionForFile, triggerSelectionAction } from './FilesUtils.ts'
|
||||
|
||||
describe('files: Download files using file actions', { testIsolation: true }, () => {
|
||||
let user: User
|
||||
|
||||
deleteDownloadsFolderBeforeEach()
|
||||
|
||||
beforeEach(() => {
|
||||
cy.createRandomUser().then(($user) => {
|
||||
user = $user
|
||||
})
|
||||
})
|
||||
|
||||
it('can download file', () => {
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
getRowForFile('file.txt').should('be.visible')
|
||||
|
||||
triggerActionForFile('file.txt', 'download')
|
||||
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/file.txt`, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 8)
|
||||
.and('equal', '<content>')
|
||||
})
|
||||
|
||||
it('can download folder', () => {
|
||||
cy.mkdir(user, '/subfolder')
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/subfolder/file.txt')
|
||||
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
getRowForFile('subfolder')
|
||||
.should('be.visible')
|
||||
|
||||
triggerActionForFile('subfolder', 'download')
|
||||
|
||||
// check a file is downloaded
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/subfolder.zip`, null, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 30)
|
||||
// Check all files are included
|
||||
.and(zipFileContains([
|
||||
'subfolder/',
|
||||
'subfolder/file.txt',
|
||||
]))
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
it('can download file with hash name', () => {
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/#file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
triggerActionForFile('#file.txt', 'download')
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/#file.txt`, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 8)
|
||||
.and('equal', '<content>')
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
it('can download file from folder with hash name', () => {
|
||||
cy.mkdir(user, '/#folder')
|
||||
.uploadContent(user, new Blob(['<content>']), 'text/plain', '/#folder/file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
navigateToFolder('#folder')
|
||||
// All are visible by default
|
||||
getRowForFile('file.txt').should('be.visible')
|
||||
|
||||
triggerActionForFile('file.txt', 'download')
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/file.txt`, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 8)
|
||||
.and('equal', '<content>')
|
||||
})
|
||||
})
|
||||
|
||||
describe('files: Download files using default action', { testIsolation: true }, () => {
|
||||
let user: User
|
||||
|
||||
deleteDownloadsFolderBeforeEach()
|
||||
|
||||
beforeEach(() => {
|
||||
cy.createRandomUser().then(($user) => {
|
||||
user = $user
|
||||
})
|
||||
})
|
||||
|
||||
it('can download file', () => {
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
getRowForFile('file.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('button', { name: 'Download' })
|
||||
.click()
|
||||
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/file.txt`, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 8)
|
||||
.and('equal', '<content>')
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
it('can download file with hash name', () => {
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/#file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
getRowForFile('#file.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('button', { name: 'Download' })
|
||||
.click()
|
||||
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/#file.txt`, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 8)
|
||||
.and('equal', '<content>')
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
it('can download file from folder with hash name', () => {
|
||||
cy.mkdir(user, '/#folder')
|
||||
.uploadContent(user, new Blob(['<content>']), 'text/plain', '/#folder/file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
|
||||
navigateToFolder('#folder')
|
||||
// All are visible by default
|
||||
getRowForFile('file.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('button', { name: 'Download' })
|
||||
.click()
|
||||
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/file.txt`, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 8)
|
||||
.and('equal', '<content>')
|
||||
})
|
||||
})
|
||||
|
||||
describe('files: Download files using selection', () => {
|
||||
deleteDownloadsFolderBeforeEach()
|
||||
|
||||
it('can download selected files', () => {
|
||||
cy.createRandomUser().then((user) => {
|
||||
cy.mkdir(user, '/subfolder')
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/subfolder/file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
})
|
||||
|
||||
getRowForFile('subfolder')
|
||||
.should('be.visible')
|
||||
|
||||
getRowForFile('subfolder')
|
||||
.findByRole('checkbox')
|
||||
.check({ force: true })
|
||||
|
||||
// see that two files are selected
|
||||
cy.get('[data-cy-files-list]').within(() => {
|
||||
cy.contains('1 selected').should('be.visible')
|
||||
})
|
||||
|
||||
// click download
|
||||
triggerSelectionAction('download')
|
||||
|
||||
// check a file is downloaded
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/subfolder.zip`, null, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 30)
|
||||
// Check all files are included
|
||||
.and(zipFileContains([
|
||||
'subfolder/',
|
||||
'subfolder/file.txt',
|
||||
]))
|
||||
})
|
||||
|
||||
it('can download multiple selected files', () => {
|
||||
cy.createRandomUser().then((user) => {
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/file.txt')
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/other file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
})
|
||||
|
||||
getRowForFile('file.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('checkbox')
|
||||
.check({ force: true })
|
||||
|
||||
getRowForFile('other file.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('checkbox')
|
||||
.check({ force: true })
|
||||
|
||||
cy.get('[data-cy-files-list]').within(() => {
|
||||
// see that two files are selected
|
||||
cy.contains('2 selected').should('be.visible')
|
||||
})
|
||||
|
||||
// click download
|
||||
triggerSelectionAction('download')
|
||||
|
||||
// check a file is downloaded
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/download.zip`, null, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 30)
|
||||
// Check all files are included
|
||||
.and(zipFileContains([
|
||||
'file.txt',
|
||||
'other file.txt',
|
||||
]))
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://help.nextcloud.com/t/unable-to-download-files-on-nextcloud-when-multiple-files-selected/221327/5
|
||||
*/
|
||||
it('can download selected files with special characters', () => {
|
||||
cy.createRandomUser().then((user) => {
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/1+1.txt')
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/some@other.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
})
|
||||
|
||||
getRowForFile('some@other.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('checkbox')
|
||||
.check({ force: true })
|
||||
|
||||
getRowForFile('1+1.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('checkbox')
|
||||
.check({ force: true })
|
||||
|
||||
cy.get('[data-cy-files-list]').within(() => {
|
||||
// see that two files are selected
|
||||
cy.contains('2 selected').should('be.visible')
|
||||
})
|
||||
|
||||
// click download
|
||||
triggerSelectionAction('download')
|
||||
|
||||
// check a file is downloaded
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/download.zip`, null, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 30)
|
||||
// Check all files are included
|
||||
.and(zipFileContains([
|
||||
'1+1.txt',
|
||||
'some@other.txt',
|
||||
]))
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://help.nextcloud.com/t/unable-to-download-files-on-nextcloud-when-multiple-files-selected/221327/5
|
||||
*/
|
||||
it('can download selected files with email uid', () => {
|
||||
const name = `${randomString(5)}@${randomString(3)}`
|
||||
const user: User = { userId: name, password: name, language: 'en' }
|
||||
|
||||
cy.createUser(user).then(() => {
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/file.txt')
|
||||
cy.uploadContent(user, new Blob(['<content>']), 'text/plain', '/other file.txt')
|
||||
cy.login(user)
|
||||
cy.visit('/apps/files')
|
||||
})
|
||||
|
||||
getRowForFile('file.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('checkbox')
|
||||
.check({ force: true })
|
||||
|
||||
getRowForFile('other file.txt')
|
||||
.should('be.visible')
|
||||
.findByRole('checkbox')
|
||||
.check({ force: true })
|
||||
|
||||
cy.get('[data-cy-files-list]').within(() => {
|
||||
// see that two files are selected
|
||||
cy.contains('2 selected').should('be.visible')
|
||||
})
|
||||
|
||||
// click download
|
||||
triggerSelectionAction('download')
|
||||
|
||||
// check a file is downloaded
|
||||
const downloadsFolder = Cypress.config('downloadsFolder')
|
||||
cy.readFile(`${downloadsFolder}/download.zip`, null, { timeout: 15000 })
|
||||
.should('exist')
|
||||
.and('have.length.gt', 30)
|
||||
// Check all files are included
|
||||
.and(zipFileContains([
|
||||
'file.txt',
|
||||
'other file.txt',
|
||||
]))
|
||||
})
|
||||
})
|
||||
248
tests/playwright/e2e/files/files-download.spec.ts
Normal file
248
tests/playwright/e2e/files/files-download.spec.ts
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Download, Page } from '@playwright/test'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { addUser, runOcc } from '@nextcloud/e2e-test-server/docker'
|
||||
import { login } from '@nextcloud/e2e-test-server/playwright'
|
||||
import { User } from '@nextcloud/e2e-test-server'
|
||||
import { test, expect } from '../../support/fixtures/files-page.ts'
|
||||
import { mkdir, uploadContent } from '../../support/utils/dav.ts'
|
||||
import { getZipEntries } from '../../support/utils/zip.ts'
|
||||
|
||||
/**
|
||||
* Register the download listener before running the trigger and return the
|
||||
* resulting download. Playwright requires `waitForEvent('download')` to be
|
||||
* pending before the action that starts the download (the Cypress original
|
||||
* instead read a file off the downloads folder afterwards).
|
||||
*/
|
||||
async function triggerDownload(page: Page, action: () => Promise<void>): Promise<Download> {
|
||||
const downloadPromise = page.waitForEvent('download')
|
||||
await action()
|
||||
return downloadPromise
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a download's body as UTF-8 text.
|
||||
*
|
||||
* @param download The Playwright download event payload
|
||||
*/
|
||||
async function readDownloadText(download: Download): Promise<string> {
|
||||
const path = await download.path()
|
||||
return readFile(path, 'utf-8')
|
||||
}
|
||||
|
||||
test.describe('Files: Download files using file actions', () => {
|
||||
test('can download file', async ({ page, user, filesListPage }) => {
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await expect(filesListPage.getRowForFile('file.txt')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerActionForFile('file.txt', 'download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('file.txt')
|
||||
expect(await readDownloadText(download)).toBe('<content>')
|
||||
})
|
||||
|
||||
test('can download folder', async ({ page, user, filesListPage }) => {
|
||||
await mkdir(page.request, user, '/subfolder')
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/subfolder/file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await expect(filesListPage.getRowForFile('subfolder')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerActionForFile('subfolder', 'download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('subfolder.zip')
|
||||
expect(await getZipEntries(download)).toEqual([
|
||||
'subfolder/',
|
||||
'subfolder/file.txt',
|
||||
])
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
test('can download file with hash name', async ({ page, user, filesListPage }) => {
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/#file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await expect(filesListPage.getRowForFile('#file.txt')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerActionForFile('#file.txt', 'download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('#file.txt')
|
||||
expect(await readDownloadText(download)).toBe('<content>')
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
test('can download file from folder with hash name', async ({ page, user, filesListPage }) => {
|
||||
await mkdir(page.request, user, '/#folder')
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/#folder/file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await filesListPage.navigateToFolder('#folder')
|
||||
// All are visible by default
|
||||
await expect(filesListPage.getRowForFile('file.txt')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerActionForFile('file.txt', 'download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('file.txt')
|
||||
expect(await readDownloadText(download)).toBe('<content>')
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Files: Download files using default action', () => {
|
||||
test('can download file', async ({ page, user, filesListPage }) => {
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await expect(filesListPage.getRowForFile('file.txt')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.getDownloadButtonForFile('file.txt').click())
|
||||
|
||||
expect(download.suggestedFilename()).toBe('file.txt')
|
||||
expect(await readDownloadText(download)).toBe('<content>')
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
test('can download file with hash name', async ({ page, user, filesListPage }) => {
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/#file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await expect(filesListPage.getRowForFile('#file.txt')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.getDownloadButtonForFile('#file.txt').click())
|
||||
|
||||
expect(download.suggestedFilename()).toBe('#file.txt')
|
||||
expect(await readDownloadText(download)).toBe('<content>')
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://github.com/nextcloud/server/issues/44855
|
||||
*/
|
||||
test('can download file from folder with hash name', async ({ page, user, filesListPage }) => {
|
||||
await mkdir(page.request, user, '/#folder')
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/#folder/file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await filesListPage.navigateToFolder('#folder')
|
||||
// All are visible by default
|
||||
await expect(filesListPage.getRowForFile('file.txt')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.getDownloadButtonForFile('file.txt').click())
|
||||
|
||||
expect(download.suggestedFilename()).toBe('file.txt')
|
||||
expect(await readDownloadText(download)).toBe('<content>')
|
||||
})
|
||||
})
|
||||
|
||||
test.describe('Files: Download files using selection', () => {
|
||||
test('can download selected files', async ({ page, user, filesListPage }) => {
|
||||
await mkdir(page.request, user, '/subfolder')
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/subfolder/file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await expect(filesListPage.getRowForFile('subfolder')).toBeVisible()
|
||||
await filesListPage.selectRowForFile('subfolder')
|
||||
|
||||
// see that one file is selected
|
||||
await expect(page.getByText('1 selected')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerSelectionAction('download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('subfolder.zip')
|
||||
expect(await getZipEntries(download)).toEqual([
|
||||
'subfolder/',
|
||||
'subfolder/file.txt',
|
||||
])
|
||||
})
|
||||
|
||||
test('can download multiple selected files', async ({ page, user, filesListPage }) => {
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/file.txt')
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/other file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await filesListPage.selectRowForFile('file.txt')
|
||||
await filesListPage.selectRowForFile('other file.txt')
|
||||
|
||||
// see that two files are selected
|
||||
await expect(page.getByText('2 selected')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerSelectionAction('download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('download.zip')
|
||||
expect(await getZipEntries(download)).toEqual([
|
||||
'file.txt',
|
||||
'other file.txt',
|
||||
])
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://help.nextcloud.com/t/unable-to-download-files-on-nextcloud-when-multiple-files-selected/221327/5
|
||||
*/
|
||||
test('can download selected files with special characters', async ({ page, user, filesListPage }) => {
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/1+1.txt')
|
||||
await uploadContent(page.request, user, '<content>', 'text/plain', '/some@other.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await filesListPage.selectRowForFile('some@other.txt')
|
||||
await filesListPage.selectRowForFile('1+1.txt')
|
||||
|
||||
// see that two files are selected
|
||||
await expect(page.getByText('2 selected')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerSelectionAction('download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('download.zip')
|
||||
expect(await getZipEntries(download)).toEqual([
|
||||
'1+1.txt',
|
||||
'some@other.txt',
|
||||
])
|
||||
})
|
||||
|
||||
/**
|
||||
* Regression test of https://help.nextcloud.com/t/unable-to-download-files-on-nextcloud-when-multiple-files-selected/221327/5
|
||||
*
|
||||
* This test does not use the shared `user` fixture: it needs an email-like
|
||||
* uid, which `createRandomUser()` cannot produce, so it provisions its own
|
||||
* user via the docker helper and logs in at the API level.
|
||||
*/
|
||||
test('can download selected files with email uid', async ({ page, context, filesListPage }) => {
|
||||
const randomString = (length: number) => Math.random().toString(36).slice(2, 2 + length)
|
||||
const uid = `${randomString(5)}@${randomString(3)}`
|
||||
const emailUser = new User(uid, uid, 'en')
|
||||
|
||||
await addUser(emailUser)
|
||||
await login(context.request, emailUser)
|
||||
|
||||
try {
|
||||
await uploadContent(page.request, emailUser, '<content>', 'text/plain', '/file.txt')
|
||||
await uploadContent(page.request, emailUser, '<content>', 'text/plain', '/other file.txt')
|
||||
await filesListPage.open()
|
||||
|
||||
await filesListPage.selectRowForFile('file.txt')
|
||||
await filesListPage.selectRowForFile('other file.txt')
|
||||
|
||||
// see that two files are selected
|
||||
await expect(page.getByText('2 selected')).toBeVisible()
|
||||
|
||||
const download = await triggerDownload(page, () => filesListPage.triggerSelectionAction('download'))
|
||||
|
||||
expect(download.suggestedFilename()).toBe('download.zip')
|
||||
expect(await getZipEntries(download)).toEqual([
|
||||
'file.txt',
|
||||
'other file.txt',
|
||||
])
|
||||
} finally {
|
||||
await runOcc(['user:delete', uid])
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
@ -66,6 +66,13 @@ export class FilesListPage {
|
|||
return this.getRowForFile(filename).getByRole('img', { name: 'Favorite' })
|
||||
}
|
||||
|
||||
/**
|
||||
* The inline "Download" button rendered on a row for the default download action.
|
||||
*/
|
||||
getDownloadButtonForFile(filename: string): Locator {
|
||||
return this.getRowForFile(filename).getByRole('button', { name: 'Download' })
|
||||
}
|
||||
|
||||
async selectAll(): Promise<void> {
|
||||
await this.page.locator('[data-cy-files-list-selection-checkbox]')
|
||||
.getByRole('checkbox')
|
||||
|
|
|
|||
29
tests/playwright/support/utils/zip.ts
Normal file
29
tests/playwright/support/utils/zip.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Download } from '@playwright/test'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { Uint8ArrayReader, ZipReader } from '@zip.js/zip.js'
|
||||
|
||||
/**
|
||||
* Read a downloaded zip and return its entry names, sorted.
|
||||
*
|
||||
* Ports the Cypress `zipFileContains` assertion onto the Playwright Download
|
||||
* object: the download is saved to a temp path, read back, and parsed with the
|
||||
* same @zip.js/zip.js reader the Cypress util used.
|
||||
*
|
||||
* @param download The Playwright download event payload
|
||||
*/
|
||||
export async function getZipEntries(download: Download): Promise<string[]> {
|
||||
const path = await download.path()
|
||||
const buffer = await readFile(path)
|
||||
const zip = new ZipReader(new Uint8ArrayReader(buffer))
|
||||
try {
|
||||
const entries = await zip.getEntries()
|
||||
return entries.map((entry) => entry.filename).sort()
|
||||
} finally {
|
||||
await zip.close()
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue