diff --git a/cypress/components/UploadPicker/UploadPicker.cy.ts b/cypress/components/UploadPicker/UploadPicker.cy.ts index 6368da0b..943c667c 100644 --- a/cypress/components/UploadPicker/UploadPicker.cy.ts +++ b/cypress/components/UploadPicker/UploadPicker.cy.ts @@ -3,9 +3,7 @@ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ -// 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 { Folder, Permission } from '@nextcloud/files' import { generateRemoteUrl } from '@nextcloud/router' import { UploadPicker, UploadStatus, getUploader } from '../../../lib/index.ts' @@ -39,8 +37,9 @@ describe('UploadPicker rendering', () => { } cy.mount(UploadPicker, { propsData }) cy.get('[data-cy-upload-picker]').should('be.visible') - cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') + cy.get('[data-cy-upload-picker]').should('contain.text', 'New') cy.get('[data-cy-upload-picker] [data-cy-upload-picker-input]').should('exist') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-progress]').should('not.be.visible') }) it('Does NOT render without a destination', () => { @@ -68,22 +67,22 @@ describe('UploadPicker valid uploads', () => { cy.mount(UploadPicker, { propsData }).as('uploadPicker') // Label is displayed before upload - cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') + cy.get('[data-cy-upload-picker]') + .contains('button', 'New') + .should('be.visible') // 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') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-progress]').as('progress').should('exist') }) afterEach(() => resetDocument()) it('Uploads a file', () => { - // Intercept single upload + const { promise, resolve } = Promise.withResolvers() cy.intercept('PUT', '/remote.php/dav/files/*/*', (req) => { - req.reply({ - statusCode: 201, - delay: 2000, - }) + req.reply({ statusCode: 201 }) + req.on('response', async () => await promise) }).as('upload') cy.get('@input').attachFile({ @@ -95,20 +94,24 @@ describe('UploadPicker valid uploads', () => { lastModified: new Date().getTime(), }) - cy.get('[data-cy-upload-picker] .upload-picker__progress') - .as('progress') - .should('be.visible') - - // Label gets hidden during upload - cy.get('[data-cy-upload-picker]').should('not.have.text', 'New') + cy.get('@progress').should('be.visible') + cy.get('[data-cy-upload-picker]') + .within(() => { + // Label gets hidden during upload + cy.contains('button', 'New').should('not.exist') + // but the button exists + cy.get('button[data-cy-upload-picker-add]') + .should('be.visible') + .and('have.attr', 'aria-label', 'New') + }) + .then(() => resolve()) cy.wait('@upload').then(() => { - cy.get('[data-cy-upload-picker] .upload-picker__progress') - .as('progress') + cy.get('@progress') .should('not.be.visible') // Label is displayed again after upload - cy.get('[data-cy-upload-picker] button').shouldHaveTrimmedText('New') + cy.get('[data-cy-upload-picker] button').should('contain.text', 'New') }) }) }) diff --git a/cypress/components/UploadPicker/invalid-filenames.cy.ts b/cypress/components/UploadPicker/invalid-filenames.cy.ts index decc5c62..90949d2b 100644 --- a/cypress/components/UploadPicker/invalid-filenames.cy.ts +++ b/cypress/components/UploadPicker/invalid-filenames.cy.ts @@ -59,7 +59,7 @@ describe('UploadPicker: invalid filenames (legacy prop)', { testIsolation: true cy.mount(UploadPicker, { propsData }).as('uploadPicker') // Label is displayed before upload - cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-add]').should('contain.text', 'New') // Check and init aliases cy.get('[data-cy-upload-picker] [data-cy-upload-picker-input]').as('input').should('exist') @@ -193,11 +193,11 @@ describe.only('UploadPicker: invalid filenames (server capabilities)', { testIso cy.mount(UploadPicker, { propsData }).as('uploadPicker') // Label is displayed before upload - cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-add]').should('contain.text', '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') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-progress]').as('progress').should('exist') // Upload cy.get('@input').attachFile({ @@ -208,8 +208,7 @@ describe.only('UploadPicker: invalid filenames (server capabilities)', { testIso lastModified: new Date().getTime(), }) - cy.get('[data-cy-upload-picker] .upload-picker__progress') - .as('progress') + cy.get('@progress') .should('not.be.visible') cy.contains('[role="dialog"]', 'Invalid filename') @@ -234,11 +233,11 @@ describe.only('UploadPicker: invalid filenames (server capabilities)', { testIso cy.mount(UploadPicker, { propsData }).as('uploadPicker') // Label is displayed before upload - cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-add]').should('contain.text', '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') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-progress]').as('progress').should('exist') // Upload cy.get('@input').attachFile({ @@ -249,8 +248,7 @@ describe.only('UploadPicker: invalid filenames (server capabilities)', { testIso lastModified: new Date().getTime(), }) - cy.get('[data-cy-upload-picker] .upload-picker__progress') - .as('progress') + cy.get('@progress') .should('not.be.visible') cy.contains('[role="dialog"]', 'Invalid filename') @@ -275,11 +273,11 @@ describe.only('UploadPicker: invalid filenames (server capabilities)', { testIso cy.mount(UploadPicker, { propsData }).as('uploadPicker') // Label is displayed before upload - cy.get('[data-cy-upload-picker]').shouldHaveTrimmedText('New') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-add]').should('contain.text', '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') + cy.get('[data-cy-upload-picker] [data-cy-upload-picker-progress]').as('progress').should('exist') // Upload cy.get('@input').attachFile({ @@ -290,8 +288,7 @@ describe.only('UploadPicker: invalid filenames (server capabilities)', { testIso lastModified: new Date().getTime(), }) - cy.get('[data-cy-upload-picker] .upload-picker__progress') - .as('progress') + cy.get('@progress') .should('not.be.visible') cy.contains('[role="dialog"]', 'Invalid filename') @@ -390,8 +387,7 @@ describe.only('UploadPicker: invalid filenames (server capabilities)', { testIso lastModified: new Date().getTime(), }]) - cy.get('[data-cy-upload-picker] .upload-picker__progress') - .as('progress') + cy.get('@progress') .should('not.be.visible') cy.contains('[role="dialog"]', 'Invalid filename') diff --git a/cypress/components/UploadPicker/progress.cy.ts b/cypress/components/UploadPicker/progress.cy.ts index 4ca16c2b..6fabbd4d 100644 --- a/cypress/components/UploadPicker/progress.cy.ts +++ b/cypress/components/UploadPicker/progress.cy.ts @@ -74,10 +74,45 @@ describe('UploadPicker: progress handling', () => { cy.get('[data-cy-upload-picker] [data-cy-upload-picker-progress-label]').as('progressLabel').should('exist') }) - it('has increasing progress bar during non-chunked upload', () => { - // Start in paused mode - const uploader = getUploader() + it('has upload speed information', () => { + cy.get('@input').attachFile({ + // file of 9 MiB + fileContent: new Blob([new ArrayBuffer(9 * 1024 * 1024)]), + fileName: 'file.txt', + mimeType: 'text/plain', + encoding: 'utf8', + lastModified: new Date().getTime(), + }) + cy.intercept('PUT', '/remote.php/dav/files/user/file.txt', { statusCode: 201 }) + + // 128 KB/s + throttleUpload(128 * 1024) + + // See there is no progress yet + cy.get('@progress') + .should('be.visible') + .should('have.value', 0) + cy.get('@progressLabel') + .should('contain.text', 'paused') + // start the uploader + .then(() => getUploader().start()) + + // See the upload has started + cy.get('@progressLabel', { timeout: 10000 }) + .should((el) => expect(el.text()).to.match(/\d+(\.\d+)?\s?KB∕s/)) + // increase speed to 1MiB/s + .then(() => throttleUpload(1024 * 1024)) + cy.get('@progressLabel') + .children('span') + .first({ timeout: 9000 }) + .should((el) => { + expect(el.text().trim()).to.equal('a few seconds left') + expect(el.attr('title')).to.match(/\d+(\.\d+)?\s?KB∕s/) + }) + }) + + it('has increasing progress bar during non-chunked upload', () => { cy.get('@input').attachFile({ // file of 5 MiB fileContent: new Blob([new ArrayBuffer(5 * 1024 * 1024)]), @@ -106,7 +141,7 @@ describe('UploadPicker: progress handling', () => { cy.get('@progressLabel') .should('contain.text', 'paused') // start the uploader - .then(() => uploader.start()) + .then(() => getUploader().start()) // See the upload has started cy.get('@progressLabel') @@ -150,9 +185,6 @@ describe('UploadPicker: progress handling', () => { rq.reply({ statusCode: 201 }) }).as('move') - // Start in paused mode - const uploader = getUploader() - // 3 MiB/s meaning upload will take 5 seconds throttleUpload(3 * 1024 * 1024) @@ -172,7 +204,7 @@ describe('UploadPicker: progress handling', () => { cy.get('@progressLabel') .should('contain.text', 'paused') // start the uploader - .then(() => uploader.start()) + .then(() => getUploader().start()) // See the upload has started cy.get('@progressLabel') @@ -197,10 +229,10 @@ describe('UploadPicker: progress handling', () => { cy.get('@progress') .should('have.value', 90) - // Now the upload (sending) is done - if we trigger the resolve the value will increase to 97% (or 95 if we resolve only chunk2) + // Now the upload (sending) is done - if we trigger the resolve the value will increase to 96% (or 95 if we resolve only chunk2) .then(() => resolveChunk1()) cy.get('@progress') - .should('have.value', 97) + .should((e) => expect(Math.round(e.val() as number)).to.be.eq(97)) .then(() => resolveChunk2()) // now the progress should be 100 meaning the progress bar is hidden cy.get('@progress') diff --git a/cypress/cypress.d.ts b/cypress/cypress.d.ts index b2b32db8..2365c5a1 100644 --- a/cypress/cypress.d.ts +++ b/cypress/cypress.d.ts @@ -12,9 +12,6 @@ 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 51f9b35d..772f5e75 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -13,12 +13,3 @@ // 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/lib/components/UploadPicker.vue b/lib/components/UploadPicker.vue index fde44638..3a479ccf 100644 --- a/lib/components/UploadPicker.vue +++ b/lib/components/UploadPicker.vue @@ -10,6 +10,7 @@ data-cy-upload-picker> - {{ buttonName }} +