From a20d1690463bb39e2eea75ebf7ba18c4dad94af7 Mon Sep 17 00:00:00 2001 From: skjnldsv Date: Tue, 2 Apr 2024 15:35:09 +0200 Subject: [PATCH] fix: cypress test issues with trimmed strings + forbidden characters tests Signed-off-by: skjnldsv --- cypress/components/UploadPicker.cy.ts | 79 +++++++++++++++++++++++++-- cypress/cypress.d.ts | 16 ++++++ cypress/support/commands.ts | 9 +++ cypress/tsconfig.json | 5 +- 4 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 cypress/cypress.d.ts diff --git a/cypress/components/UploadPicker.cy.ts b/cypress/components/UploadPicker.cy.ts index efc37496..690cc1f6 100644 --- a/cypress/components/UploadPicker.cy.ts +++ b/cypress/components/UploadPicker.cy.ts @@ -2,8 +2,8 @@ // dist file might not be built when running eslint only // eslint-disable-next-line import/no-unresolved,n/no-missing-import import { Folder, Permission, addNewFileMenuEntry, type Entry } from '@nextcloud/files' -import { UploadPicker, getUploader } from '../../lib/index.ts' import { generateRemoteUrl } from '@nextcloud/router' +import { UploadPicker, getUploader } from '../../lib/index.ts' describe('UploadPicker rendering', () => { afterEach(() => { @@ -25,7 +25,7 @@ describe('UploadPicker rendering', () => { } cy.mount(UploadPicker, { propsData }) cy.get('[data-cy-upload-picker]').should('be.visible') - cy.get('[data-cy-upload-picker]').should('have.text', ' New ') + cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') cy.get('[data-cy-upload-picker] [data-cy-upload-picker-input]').should('exist') }) @@ -54,7 +54,7 @@ describe('UploadPicker valid uploads', () => { cy.mount(UploadPicker, { propsData }).as('uploadPicker') // Label is displayed before upload - cy.get('[data-cy-upload-picker]').should('have.text', ' New ') + cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') // Check and init aliases cy.get('[data-cy-upload-picker] [data-cy-upload-picker-input]').as('input').should('exist') @@ -99,8 +99,79 @@ describe('UploadPicker valid uploads', () => { .should('not.be.visible') // Label is displayed again after upload - cy.get('[data-cy-upload-picker] button').should('have.text', ' New ') + cy.get('[data-cy-upload-picker] button').shouldHaveTrimmedText('New') + }) + }) +}) + +describe('UploadPicker invalid uploads', () => { + + afterEach(() => { + // Make sure we clear the body + cy.window().then((win) => { + win.document.body.innerHTML = '
' + }) + }) + + it('Fails a file if forbidden character', () => { + // Make sure we reset the destination + // so other tests do not interfere + const propsData = { + destination: new Folder({ + id: 56, + owner: 'user', + source: generateRemoteUrl('dav/files/user'), + permissions: Permission.ALL, + root: '/files/user', + }), + forbiddenCharacters: '$#~&', + } + + // Mount picker + cy.mount(UploadPicker, { propsData }).as('uploadPicker') + + // Label is displayed before upload + cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') + + // Check and init aliases + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-input]').as('input').should('exist') + cy.get('[data-cy-upload-picker] .upload-picker__progress').as('progress').should('exist') + + // Intercept single upload + cy.intercept('PUT', '/remote.php/dav/files/*/*', (req) => { + req.reply({ + statusCode: 201, + delay: 2000, + }) + }).as('upload') + + // Upload 2 files + cy.get('@input').attachFile({ + // Fake file of 5 MB + fileContent: new Blob([new ArrayBuffer(2 * 1024 * 1024)]), + fileName: 'invalid-image$.jpg', + mimeType: 'image/jpeg', + encoding: 'utf8', + lastModified: new Date().getTime(), }) + + cy.get('@input').attachFile({ + // Fake file of 5 MB + fileContent: new Blob([new ArrayBuffer(2 * 1024 * 1024)]), + fileName: 'valid-image.jpg', + mimeType: 'image/jpeg', + encoding: 'utf8', + lastModified: new Date().getTime(), + }) + + cy.get('[data-cy-upload-picker] .upload-picker__progress') + .as('progress') + .should('not.be.visible') + + cy.wait('@upload') + // Should not have been called more than once as the first file is invalid + cy.get('@upload.all').should('have.length', 1) + cy.get('body').should('contain', '"$" is not allowed inside a file name.') }) }) diff --git a/cypress/cypress.d.ts b/cypress/cypress.d.ts new file mode 100644 index 00000000..241920b7 --- /dev/null +++ b/cypress/cypress.d.ts @@ -0,0 +1,16 @@ +import { mount } from 'cypress/vue' + +// Augment the Cypress namespace to include type definitions for +// your custom command. +// Alternatively, can be defined in cypress/support/component.d.ts +// with a at the top of your spec. +declare global { + namespace Cypress { + interface Chainable { + mount: typeof mount + shouldHaveTrimmedText: ( + text: string + ) => Chainable> + } + } +} diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index be54c257..e497993d 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -9,3 +9,12 @@ // https://on.cypress.io/custom-commands // *********************************************** import 'cypress-file-upload' + +Cypress.Commands.add( + 'shouldHaveTrimmedText', + { prevSubject: true }, + (subject: JQuery, text: string) => { + cy.wrap(subject) + .should(element => expect(element.text().trim()).to.equal(text)) + }, +) diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json index a4a6d089..73d30021 100644 --- a/cypress/tsconfig.json +++ b/cypress/tsconfig.json @@ -3,7 +3,10 @@ "@tsconfig/cypress/tsconfig.json", "../tsconfig.json" ], - "include": ["./**/*.ts"], + "include": [ + "./**/*.ts", + "./cypress.d.ts" + ], "compilerOptions": { "types": ["cypress"], "rootDir": "..",