From 465404bfc46eb192bbaa7923a7a12820acddd207 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Wed, 16 Oct 2024 01:07:31 +0200 Subject: [PATCH] test: Add proper styles for Cypress component tests This also fixes Typescript issue but requires to slightly adjust the Navigation test as the progress bar is not visible (because it is overlayed by another element). Signed-off-by: Ferdinand Thiessen --- apps/files/src/views/Navigation.cy.ts | 4 +- cypress/support/commands.ts | 75 +----------------------- cypress/support/component.ts | 35 +++++------- cypress/support/cypress-component.d.ts | 17 ++++++ cypress/support/cypress-e2e.d.ts | 79 ++++++++++++++++++++++++++ cypress/tsconfig.json | 3 +- tsconfig.json | 1 + 7 files changed, 115 insertions(+), 99 deletions(-) create mode 100644 cypress/support/cypress-component.d.ts create mode 100644 cypress/support/cypress-e2e.d.ts diff --git a/apps/files/src/views/Navigation.cy.ts b/apps/files/src/views/Navigation.cy.ts index 46360a2357aa9..6f5db978980a1 100644 --- a/apps/files/src/views/Navigation.cy.ts +++ b/apps/files/src/views/Navigation.cy.ts @@ -216,7 +216,7 @@ describe('Quota rendering', () => { cy.get('[data-cy-files-navigation-settings-quota]').should('be.visible') cy.get('[data-cy-files-navigation-settings-quota]').should('contain.text', '1 GB of 5 GB used') - cy.get('[data-cy-files-navigation-settings-quota] progress').should('be.visible') + cy.get('[data-cy-files-navigation-settings-quota] progress').should('exist') cy.get('[data-cy-files-navigation-settings-quota] progress').should('have.attr', 'value', '20') }) @@ -237,7 +237,7 @@ describe('Quota rendering', () => { cy.get('[data-cy-files-navigation-settings-quota]').should('be.visible') cy.get('[data-cy-files-navigation-settings-quota]').should('contain.text', '5 GB of 1 GB used') - cy.get('[data-cy-files-navigation-settings-quota] progress').should('be.visible') + cy.get('[data-cy-files-navigation-settings-quota] progress').should('exist') cy.get('[data-cy-files-navigation-settings-quota] progress').should('have.attr', 'value', '100') // progress max is 100 }) }) diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 23f93ea14d958..28bd335eecfb0 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-or-later */ // eslint-disable-next-line n/no-extraneous-import -import axios, { type AxiosResponse } from 'axios' +import axios from 'axios' import { addCommands, User } from '@nextcloud/cypress' import { basename } from 'path' @@ -13,79 +13,6 @@ import 'cypress-if' import 'cypress-wait-until' addCommands() -// Register this file's custom commands types -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Cypress { - // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars - interface Chainable { - /** - * Enable or disable a given user - */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any - enableUser(user: User, enable?: boolean): Cypress.Chainable>, - - /** - * Upload a file from the fixtures folder to a given user storage. - * **Warning**: Using this function will reset the previous session - */ - uploadFile(user: User, fixture?: string, mimeType?: string, target?: string): Cypress.Chainable, - - /** - * Upload a raw content to a given user storage. - * **Warning**: Using this function will reset the previous session - */ - uploadContent(user: User, content: Blob, mimeType: string, target: string, mtime?: number): Cypress.Chainable, - - /** - * Create a new directory - * **Warning**: Using this function will reset the previous session - */ - mkdir(user: User, target: string): Cypress.Chainable, - - /** - * Set a file as favorite (or remove from favorite) - */ - setFileAsFavorite(user: User, target: string, favorite?: boolean): Cypress.Chainable, - - /** - * Reset the admin theming entirely. - * **Warning**: Using this function will reset the previous session - */ - resetAdminTheming(): Cypress.Chainable, - - /** - * Reset the user theming settings. - * If provided, will clear session and login as the given user. - * **Warning**: Providing a user will reset the previous session. - */ - resetUserTheming(user?: User): Cypress.Chainable, - - /** - * Run an occ command in the docker container. - */ - runOccCommand(command: string, options?: Partial): Cypress.Chainable, - - userFileExists(user: string, path: string): Cypress.Chainable - - /** - * Create a snapshot of the current database - */ - backupDB(): Cypress.Chainable, - - /** - * Restore a snapshot of the database - * Default is the post-setup state - */ - restoreDB(snapshot?: string): Cypress.Chainable - - backupData(users?: string[]): Cypress.Chainable - - restoreData(snapshot?: string): Cypress.Chainable - } - } -} - const url = (Cypress.config('baseUrl') || '').replace(/\/index.php\/?$/g, '') Cypress.env('baseUrl', url) diff --git a/cypress/support/component.ts b/cypress/support/component.ts index 765ed6155f945..0e2b59c0ff69e 100644 --- a/cypress/support/component.ts +++ b/cypress/support/component.ts @@ -2,34 +2,25 @@ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ + +import '../../apps/theming/css/default.css' +import '../../core/css/server.css' + +import '@testing-library/cypress/add-commands' import 'cypress-axe' -/* eslint-disable */ import { mount } from '@cypress/vue2' -// Example use: -// cy.mount(MyComponent) -Cypress.Commands.add('mount', (component, optionsOrProps) => { - let instance = null - const oldMounted = component?.mounted || false - - // Override the mounted method to expose - // the component instance to cypress - component.mounted = function() { - // eslint-disable-next-line - instance = this - if (oldMounted) { - oldMounted.call(instance) - } - } +Cypress.Commands.add('mount', (component, options = {}) => { + // Setup options object + options.extensions = options.extensions || {} + options.extensions.plugins = options.extensions.plugins || [] + options.extensions.components = options.extensions.components || {} - // Expose the component with cy.get('@component') - return mount(component, optionsOrProps).then(() => { - return cy.wrap(instance).as('component') - }) + return mount(component, options) }) -Cypress.Commands.add('mockInitialState', (app: string, key: string, value: any) => { +Cypress.Commands.add('mockInitialState', (app: string, key: string, value: unknown) => { cy.document().then(($document) => { const input = $document.createElement('input') input.setAttribute('type', 'hidden') @@ -44,4 +35,4 @@ Cypress.Commands.add('unmockInitialState', (app?: string, key?: string) => { $document.querySelectorAll('body > input[type="hidden"]' + (app ? `[id="initial-state-${app}-${key}"]` : '')) .forEach((node) => $document.body.removeChild(node)) }) -}) \ No newline at end of file +}) diff --git a/cypress/support/cypress-component.d.ts b/cypress/support/cypress-component.d.ts new file mode 100644 index 0000000000000..735db871e3503 --- /dev/null +++ b/cypress/support/cypress-component.d.ts @@ -0,0 +1,17 @@ +/*! + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import type { mount } from '@cypress/vue2' + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + interface Chainable { + mount: typeof mount + mockInitialState: (app: string, key: string, value: unknown) => Cypress.Chainable + unmockInitialState: (app?: string, key?: string) => Cypress.Chainable + } + } +} diff --git a/cypress/support/cypress-e2e.d.ts b/cypress/support/cypress-e2e.d.ts new file mode 100644 index 0000000000000..13b181e6db621 --- /dev/null +++ b/cypress/support/cypress-e2e.d.ts @@ -0,0 +1,79 @@ +/*! + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +// eslint-disable-next-line n/no-extraneous-import +import type { AxiosResponse } from 'axios' + +declare global { + // eslint-disable-next-line @typescript-eslint/no-namespace + namespace Cypress { + // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars + interface Chainable { + /** + * Enable or disable a given user + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + enableUser(user: User, enable?: boolean): Cypress.Chainable>, + + /** + * Upload a file from the fixtures folder to a given user storage. + * **Warning**: Using this function will reset the previous session + */ + uploadFile(user: User, fixture?: string, mimeType?: string, target?: string): Cypress.Chainable, + + /** + * Upload a raw content to a given user storage. + * **Warning**: Using this function will reset the previous session + */ + uploadContent(user: User, content: Blob, mimeType: string, target: string, mtime?: number): Cypress.Chainable, + + /** + * Create a new directory + * **Warning**: Using this function will reset the previous session + */ + mkdir(user: User, target: string): Cypress.Chainable, + + /** + * Set a file as favorite (or remove from favorite) + */ + setFileAsFavorite(user: User, target: string, favorite?: boolean): Cypress.Chainable, + + /** + * Reset the admin theming entirely. + * **Warning**: Using this function will reset the previous session + */ + resetAdminTheming(): Cypress.Chainable, + + /** + * Reset the user theming settings. + * If provided, will clear session and login as the given user. + * **Warning**: Providing a user will reset the previous session. + */ + resetUserTheming(user?: User): Cypress.Chainable, + + /** + * Run an occ command in the docker container. + */ + runOccCommand(command: string, options?: Partial): Cypress.Chainable, + + userFileExists(user: string, path: string): Cypress.Chainable + + /** + * Create a snapshot of the current database + */ + backupDB(): Cypress.Chainable, + + /** + * Restore a snapshot of the database + * Default is the post-setup state + */ + restoreDB(snapshot?: string): Cypress.Chainable + + backupData(users?: string[]): Cypress.Chainable + + restoreData(snapshot?: string): Cypress.Chainable + } + } +} diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json index 002fdb4f63e21..510c64d633cb6 100644 --- a/cypress/tsconfig.json +++ b/cypress/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "../tsconfig.json", - "include": ["./**/*.ts"], + "include": ["./**/*.ts", "../**/*.cy.ts", "./cypress-e2e.d.ts", "./cypress-component.d.ts"], + "exclude": [], "compilerOptions": { "types": [ "@testing-library/cypress", diff --git a/tsconfig.json b/tsconfig.json index 432217993fd31..0db24242419cd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "@vue/tsconfig/tsconfig.json", "include": ["./apps/**/*.ts", "./apps/**/*.vue", "./core/**/*.ts", "./core/**/*.vue", "./*.d.ts"], + "exclude": ["./**/*.cy.ts"], "compilerOptions": { "types": ["node", "vue", "vue-router"], "outDir": "./dist/",