Skip to content

Commit

Permalink
test: Add end-to-end tests for new public share Vue UI
Browse files Browse the repository at this point in the history
Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Sep 6, 2024
1 parent be884ee commit 4a90d53
Show file tree
Hide file tree
Showing 21 changed files with 879 additions and 120 deletions.
6 changes: 1 addition & 5 deletions __tests__/mock-window.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { beforeEach } from 'vitest'

window.OC = { ...window.OC }
window.OCA = { ...window.OCA }
window.OCP = { ...window.OCP }

beforeEach(() => {
window.location = new URL('http://nextcloud.local')
})
window._oc_webroot = ''
3 changes: 2 additions & 1 deletion apps/files/src/actions/editLocallyAction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ describe('Edit locally action execute tests', () => {
data: { ocs: { data: { token: 'foobar' } } },
}))
const showError = vi.spyOn(nextcloudDialogs, 'showError')
const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null)

const file = new File({
id: 1,
Expand All @@ -138,7 +139,7 @@ describe('Edit locally action execute tests', () => {
expect(axios.post).toBeCalledTimes(1)
expect(axios.post).toBeCalledWith('http://nextcloud.local/ocs/v2.php/apps/files/api/v1/openlocaleditor?format=json', { path: '/foobar.txt' })
expect(showError).toBeCalledTimes(0)
expect(window.location.href).toBe('nc://open/[email protected]/foobar.txt?token=foobar')
expect(windowOpenSpy).toBeCalledWith('nc://open/[email protected]/foobar.txt?token=foobar', '_self')
})

test('Edit locally fails and shows error', async () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/files/src/actions/editLocallyAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const openLocalClient = async function(path: string) {
let url = `nc://open/${uid}@` + window.location.host + encodePath(path)
url += '?token=' + result.data.ocs.data.token

window.location.href = url
window.open(url, '_self')
} catch (error) {
showError(t('files', 'Failed to redirect to client'))
}
Expand Down
13 changes: 13 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ export default defineConfig({

on('task', { removeDirectory })

// This allows to store global data (e.g. the name of a snapshot)
// because Cypress.env() and other options are local to the current spec file.
const data = {}
on('task', {
setVariable({ key, value }) {
data[key] = value
return null
},
getVariable({ key }) {
return data[key] ?? null
},
})

// Disable spell checking to prevent rendering differences
on('before:browser:launch', (browser, launchOptions) => {
if (browser.family === 'chromium' && browser.name !== 'electron') {
Expand Down
6 changes: 5 additions & 1 deletion cypress/dockerNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ export const configureNextcloud = async function() {
// Saving DB state
console.log('├─ Creating init DB snapshot...')
await runExec(container, ['cp', '/var/www/html/data/owncloud.db', '/var/www/html/data/owncloud.db-init'], true)
console.log('├─ Creating init data backup...')
await runExec(container, ['tar', 'cf', 'data-init.tar', 'admin'], true, undefined, '/var/www/html/data')

console.log('└─ Nextcloud is now ready to use 🎉')
}
Expand Down Expand Up @@ -277,9 +279,11 @@ const runExec = async function(
command: string[],
verbose = false,
user = 'www-data',
workdir?: string,
): Promise<string> {
const exec = await container.exec({
Cmd: command,
WorkingDir: workdir,
AttachStdout: true,
AttachStderr: true,
User: user,
Expand All @@ -296,7 +300,7 @@ const runExec = async function(
stream.on('data', str => {
str = str.trim()
// Remove non printable characters
.replace(/[^\x20-\x7E]+/g, '')
.replace(/[^\x0A\x0D\x20-\x7E]+/g, '')
// Remove non alphanumeric leading characters
.replace(/^[^a-z]/gi, '')
output += str
Expand Down
10 changes: 5 additions & 5 deletions cypress/e2e/files/FilesUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export const getRowForFile = (filename: string) => cy.get(`[data-cy-files-list-r
export const getActionsForFileId = (fileid: number) => getRowForFileId(fileid).find('[data-cy-files-list-row-actions]')
export const getActionsForFile = (filename: string) => getRowForFile(filename).find('[data-cy-files-list-row-actions]')

export const getActionButtonForFileId = (fileid: number) => getActionsForFileId(fileid).find('button[aria-label="Actions"]')
export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).find('button[aria-label="Actions"]')
export const getActionButtonForFileId = (fileid: number) => getActionsForFileId(fileid).findByRole('button', { name: 'Actions' })
export const getActionButtonForFile = (filename: string) => getActionsForFile(filename).findByRole('button', { name: 'Actions' })

export const triggerActionForFileId = (fileid: number, actionId: string) => {
getActionButtonForFileId(fileid).click()
Expand All @@ -34,7 +34,7 @@ export const moveFile = (fileName: string, dirPath: string) => {

cy.get('.file-picker').within(() => {
// intercept the copy so we can wait for it
cy.intercept('MOVE', /\/remote.php\/dav\/files\//).as('moveFile')
cy.intercept('MOVE', /\/(remote|public)\.php\/dav\/files\//).as('moveFile')

if (dirPath === '/') {
// select home folder
Expand Down Expand Up @@ -65,7 +65,7 @@ export const copyFile = (fileName: string, dirPath: string) => {

cy.get('.file-picker').within(() => {
// intercept the copy so we can wait for it
cy.intercept('COPY', /\/remote.php\/dav\/files\//).as('copyFile')
cy.intercept('COPY', /\/(remote|public)\.php\/dav\/files\//).as('copyFile')

if (dirPath === '/') {
// select home folder
Expand Down Expand Up @@ -95,7 +95,7 @@ export const renameFile = (fileName: string, newFileName: string) => {
triggerActionForFile(fileName, 'rename')

// intercept the move so we can wait for it
cy.intercept('MOVE', /\/remote.php\/dav\/files\//).as('moveFile')
cy.intercept('MOVE', /\/(remote|public)\.php\/dav\/files\//).as('moveFile')

getRowForFile(fileName).find('[data-cy-files-list-row-name] input').clear()
getRowForFile(fileName).find('[data-cy-files-list-row-name] input').type(`${newFileName}{enter}`)
Expand Down
11 changes: 0 additions & 11 deletions cypress/e2e/files_sharing/FilesSharingUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,3 @@ export const createFileRequest = (path: string, options: FileRequestOptions = {}
// Close
cy.get('[data-cy-file-request-dialog-controls="finish"]').click()
}

export const enterGuestName = (name: string) => {
cy.get('[data-cy-public-auth-prompt-dialog]').should('be.visible')
cy.get('[data-cy-public-auth-prompt-dialog-name]').should('be.visible')
cy.get('[data-cy-public-auth-prompt-dialog-submit]').should('be.visible')

cy.get('[data-cy-public-auth-prompt-dialog-name]').type(`{selectall}${name}`)
cy.get('[data-cy-public-auth-prompt-dialog-submit]').click()

cy.get('[data-cy-public-auth-prompt-dialog]').should('not.exist')
}
44 changes: 33 additions & 11 deletions cypress/e2e/files_sharing/file-request.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,31 @@

import type { User } from '@nextcloud/cypress'
import { createFolder, getRowForFile, navigateToFolder } from '../files/FilesUtils'
import { createFileRequest, enterGuestName } from './FilesSharingUtils'
import { createFileRequest } from './FilesSharingUtils'

const enterGuestName = (name: string) => {
cy.findByRole('dialog', { name: /Upload files to/ })
.should('be.visible')
.within(() => {
cy.findByRole('textbox', { name: 'Nickname' })
.should('be.visible')

cy.findByRole('textbox', { name: 'Nickname' })
.type(`{selectall}${name}`)

cy.findByRole('button', { name: 'Submit name' })
.should('be.visible')
.click()
})

cy.findByRole('dialog', { name: /Upload files to/ })
.should('not.exist')
}

describe('Files', { testIsolation: true }, () => {
const folderName = 'test-folder'
let user: User
let url = ''
let folderName = 'test-folder'

it('Login with a user and create a file request', () => {
cy.createRandomUser().then((_user) => {
Expand All @@ -33,19 +52,22 @@ describe('Files', { testIsolation: true }, () => {
enterGuestName('Guest')

// Check various elements on the page
cy.get('#public-upload .emptycontent').should('be.visible')
cy.get('#public-upload h2').contains(`Upload files to ${folderName}`)
cy.get('#public-upload input[type="file"]').as('fileInput').should('exist')
cy.contains(`Upload files to ${folderName}`)
.should('be.visible')
cy.findByRole('button', { name: 'Upload' })
.should('be.visible')

cy.intercept('PUT', '/public.php/dav/files/*/*').as('uploadFile')

// Upload a file
cy.get('@fileInput').selectFile({
contents: Cypress.Buffer.from('abcdef'),
fileName: 'file.txt',
mimeType: 'text/plain',
lastModified: Date.now(),
}, { force: true })
cy.get('[data-cy-files-sharing-file-drop] input[type="file"]')
.should('exist')
.selectFile({
contents: Cypress.Buffer.from('abcdef'),
fileName: 'file.txt',
mimeType: 'text/plain',
lastModified: Date.now(),
}, { force: true })

cy.wait('@uploadFile').its('response.statusCode').should('eq', 201)
})
Expand Down
49 changes: 49 additions & 0 deletions cypress/e2e/files_sharing/public-share/copy-move-files.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*!
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { copyFile, getRowForFile, moveFile, navigateToFolder } from '../../files/FilesUtils.ts'
import { getShareUrl, setupPublicShare } from './setup-public-share.ts'

describe('files_sharing: Public share - copy and move files', { testIsolation: true }, () => {

beforeEach(() => {
setupPublicShare()
.then(() => cy.logout())
.then(() => cy.visit(getShareUrl()))
})

it('Can copy a file to new folder', () => {
getRowForFile('foo.txt').should('be.visible')
getRowForFile('subfolder').should('be.visible')

copyFile('foo.txt', 'subfolder')

// still visible
getRowForFile('foo.txt').should('be.visible')
navigateToFolder('subfolder')

cy.url().should('contain', 'dir=/subfolder')
getRowForFile('foo.txt').should('be.visible')
getRowForFile('bar.txt').should('be.visible')
getRowForFile('subfolder').should('not.exist')
})

it('Can move a file to new folder', () => {
getRowForFile('foo.txt').should('be.visible')
getRowForFile('subfolder').should('be.visible')

moveFile('foo.txt', 'subfolder')

// wait until visible again
getRowForFile('subfolder').should('be.visible')

// file should be moved -> not exist anymore
getRowForFile('foo.txt').should('not.exist')
navigateToFolder('subfolder')

cy.url().should('contain', 'dir=/subfolder')
getRowForFile('foo.txt').should('be.visible')
getRowForFile('subfolder').should('not.exist')
})
})
Loading

0 comments on commit 4a90d53

Please sign in to comment.