From 437ec766124bdd6aa68739874ea0d2d391e48c5a Mon Sep 17 00:00:00 2001 From: William Phetsinorath Date: Fri, 20 Mar 2026 12:38:23 +0100 Subject: [PATCH 1/2] chore: add e2e tests run on change Signed-off-by: William Phetsinorath Change-Id: I2307b3df39a2cc9a99822fb6da2858f86a6a6964 --- .../workflow-continuous-integration.yml | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/.github/workflows/workflow-continuous-integration.yml b/.github/workflows/workflow-continuous-integration.yml index dbf580958..905206535 100644 --- a/.github/workflows/workflow-continuous-integration.yml +++ b/.github/workflows/workflow-continuous-integration.yml @@ -124,6 +124,30 @@ jobs: NAMESPACE: ${{ needs.expose-vars.outputs.NAMESPACE }} TAG: pr-${{ github.event.pull_request.number || github.event.number }} + playwright-tests: + uses: ./.github/workflows/job-playwright.yml + if: ${{ needs.path-filter.outputs.apps == 'true' || needs.path-filter.outputs.packages == 'true' || needs.path-filter.outputs.ci == 'true' || needs.path-filter.outputs.e2e == 'true' }} + needs: + - path-filter + - expose-vars + - build + with: + NODE_VERSION: ${{ needs.expose-vars.outputs.NODE_VERSION }} + TAG: pr-${{ github.event.pull_request.number || github.event.number }} + + cypress-tests: + uses: ./.github/workflows/job-tests-e2e.yml + if: ${{ needs.path-filter.outputs.apps == 'true' || needs.path-filter.outputs.packages == 'true' || needs.path-filter.outputs.ci == 'true' || needs.path-filter.outputs.e2e == 'true' }} + needs: + - playwright-tests + - path-filter + - expose-vars + - build + with: + NODE_VERSION: ${{ needs.expose-vars.outputs.NODE_VERSION }} + TAG: pr-${{ github.event.pull_request.number || github.event.number }} + BROWSERS: "${{ github.base_ref == 'main' && 'chrome,firefox' || 'firefox' }}" + # Workaround for required status check in protection branches (see. https://github.com/orgs/community/discussions/13690) all-jobs-passed: name: Check jobs status @@ -135,6 +159,8 @@ jobs: - lint - unit-tests - build + - playwright-tests + - cypress-tests - scan-vuln steps: - name: Check status of all required jobs From 9dd40188e89ce2a47b775c36f2200835864fb09c Mon Sep 17 00:00:00 2001 From: William Phetsinorath Date: Fri, 20 Mar 2026 16:14:20 +0100 Subject: [PATCH 2/2] chore: remove component testing Signed-off-by: William Phetsinorath --- apps/client/cypress.config.ts | 80 -- .../components/specs/choice-selector.ct.ts | 150 --- .../components/specs/cluster-form.ct.ts | 192 ---- .../components/specs/config-param.ct.ts | 68 -- .../components/specs/pagination-ct.ct.ts | 53 -- .../components/specs/project-settings.ct.ts | 24 - .../cypress/components/specs/repo-form.ct.ts | 327 ------- .../components/specs/services-config.ct.ts | 114 --- .../cypress/components/specs/stage-form.ct.ts | 102 -- .../components/specs/suggestion-input.ct.ts | 29 - .../cypress/components/specs/team-ct.ct.ts | 110 --- .../cypress/components/specs/token-form.ct.ts | 72 -- .../cypress/components/specs/zone-form.ct.ts | 125 --- .../cypress/components/support/commands.ts | 27 - .../components/support/component-index.html | 13 - .../cypress/components/support/index.ts | 23 - apps/client/cypress/e2e/specs/03-modal.e2e.ts | 60 -- .../cypress/e2e/specs/admin/logs.e2e.ts | 82 -- .../cypress/e2e/specs/admin/projects.e2e.ts | 372 -------- .../e2e/specs/admin/system-settings.e2e.ts | 93 -- .../cypress/e2e/specs/admin/users.e2e.ts | 55 -- .../cypress/e2e/specs/create-project.e2e.ts | 49 - apps/client/cypress/e2e/specs/home.e2e.ts | 31 - .../client/cypress/e2e/specs/not-found.e2e.ts | 8 - .../cypress/e2e/specs/redirection.e2e.ts | 87 -- apps/client/cypress/e2e/specs/roles.e2e.ts | 172 ---- .../cypress/e2e/specs/services-health.e2e.ts | 26 - apps/client/cypress/e2e/specs/services.e2e.ts | 21 - apps/client/cypress/e2e/specs/sidemenu.e2e.ts | 52 - apps/client/cypress/e2e/specs/team.e2e.ts | 166 ---- apps/client/cypress/e2e/support/commands.ts | 466 --------- apps/client/cypress/e2e/support/func.ts | 37 - apps/client/cypress/e2e/support/index.ts | 273 ------ apps/client/cypress/tsconfig.json | 15 - apps/client/cypress/types.ts | 14 - apps/client/package.json | 11 - apps/client/vite.config.ts | 3 - ci/scripts/run-tests.sh | 30 +- package.json | 7 +- pnpm-lock.yaml | 885 +----------------- 40 files changed, 47 insertions(+), 4477 deletions(-) delete mode 100644 apps/client/cypress.config.ts delete mode 100644 apps/client/cypress/components/specs/choice-selector.ct.ts delete mode 100644 apps/client/cypress/components/specs/cluster-form.ct.ts delete mode 100644 apps/client/cypress/components/specs/config-param.ct.ts delete mode 100644 apps/client/cypress/components/specs/pagination-ct.ct.ts delete mode 100644 apps/client/cypress/components/specs/project-settings.ct.ts delete mode 100644 apps/client/cypress/components/specs/repo-form.ct.ts delete mode 100644 apps/client/cypress/components/specs/services-config.ct.ts delete mode 100644 apps/client/cypress/components/specs/stage-form.ct.ts delete mode 100644 apps/client/cypress/components/specs/suggestion-input.ct.ts delete mode 100644 apps/client/cypress/components/specs/team-ct.ct.ts delete mode 100644 apps/client/cypress/components/specs/token-form.ct.ts delete mode 100644 apps/client/cypress/components/specs/zone-form.ct.ts delete mode 100644 apps/client/cypress/components/support/commands.ts delete mode 100644 apps/client/cypress/components/support/component-index.html delete mode 100644 apps/client/cypress/components/support/index.ts delete mode 100644 apps/client/cypress/e2e/specs/03-modal.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/admin/logs.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/admin/projects.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/admin/system-settings.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/admin/users.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/create-project.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/home.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/not-found.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/redirection.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/roles.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/services-health.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/services.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/sidemenu.e2e.ts delete mode 100644 apps/client/cypress/e2e/specs/team.e2e.ts delete mode 100644 apps/client/cypress/e2e/support/commands.ts delete mode 100644 apps/client/cypress/e2e/support/func.ts delete mode 100644 apps/client/cypress/e2e/support/index.ts delete mode 100644 apps/client/cypress/tsconfig.json delete mode 100644 apps/client/cypress/types.ts diff --git a/apps/client/cypress.config.ts b/apps/client/cypress.config.ts deleted file mode 100644 index 882cc0c35..000000000 --- a/apps/client/cypress.config.ts +++ /dev/null @@ -1,80 +0,0 @@ -import path from 'node:path' -import { defineConfig } from 'cypress' -import vitePreprocessor from 'cypress-vite' -import viteConfig from './vite.config.js' - -const argocdUrl = process.env.ARGOCD_URL ?? 'https://argo-cd.readthedocs.io' -const gitlabUrl = process.env.GITLAB_URL ?? 'https://gitlab.com' -const harborUrl = process.env.HARBOR_URL ?? 'https://goharbor.io' -const nexusUrl = process.env.NEXUS_URL ?? 'https://sonatype.com/products/nexus-repository' -const sonarqubeUrl = process.env.SONARQUBE_URL ?? 'https://www.sonarqube.org' -const vaultUrl = process.env.VAULT_URL ?? 'https://www.vaultproject.io' -const clientHost = process.env.CLIENT_HOST ?? 'localhost' -const clientPort = process.env.CLIENT_PORT ?? '8080' - -if (viteConfig.server) { - viteConfig.server.host = '127.0.0.1' - viteConfig.server.port = 9000 -} - -export default defineConfig({ - e2e: { - setupNodeEvents(on, config) { - on('file:preprocessor', vitePreprocessor({ - configFile: path.resolve('./vite.config.ts'), - mode: 'development', - })) - on('before:browser:launch', (browser, launchOptions) => { - if (browser.family === 'chromium') { - launchOptions.args.push('--disable-background-networking') - launchOptions.args.push('--disable-service-worker') - launchOptions.args.push('--disable-extensions') - launchOptions.args.push('--disable-sync') - } - if (browser.family === 'firefox') { - launchOptions.preferences['network.proxy.testing_localhost_is_secure_when_hijacked'] = true - launchOptions.preferences['dom.serviceWorkers.enabled'] = false - } - return launchOptions - }) - return config - }, - viewportHeight: 1024, - viewportWidth: 1280, - baseUrl: `http://${clientHost}:${clientPort}`, - fixturesFolder: 'cypress/e2e/fixtures', - specPattern: 'cypress/e2e/specs/**/*.{cy,e2e}.{j,t}s', - supportFile: 'cypress/e2e/support/index.ts', - video: false, - screenshotsFolder: 'cypress/e2e/screenshots', - numTestsKeptInMemory: 2, - chromeWebSecurity: false, - experimentalModifyObstructiveThirdPartyCode: true, - experimentalCspAllowList: true, - experimentalWebKitSupport: false, - env: { - argocdUrl, - gitlabUrl, - nexusUrl, - harborUrl, - sonarqubeUrl, - vaultUrl, - clientHost, - clientPort, - }, - }, - - component: { - specPattern: 'cypress/components/specs/**/*.{cy,ct}.{j,t}s', - supportFile: 'cypress/components/support/index.ts', - indexHtmlFile: 'cypress/components/support/component-index.html', - video: false, - screenshotsFolder: 'cypress/components/screenshots', - numTestsKeptInMemory: 1, - devServer: { - framework: 'vue', - bundler: 'vite', - viteConfig, - }, - }, -}) diff --git a/apps/client/cypress/components/specs/choice-selector.ct.ts b/apps/client/cypress/components/specs/choice-selector.ct.ts deleted file mode 100644 index 5fbebf7cd..000000000 --- a/apps/client/cypress/components/specs/choice-selector.ct.ts +++ /dev/null @@ -1,150 +0,0 @@ -import ChoiceSelector from '@/components/ChoiceSelector.vue' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -describe('ChoiceSelector.vue', () => { - const options = [ - { id: '1', name: 'Option 1' }, - { id: '2', name: 'Option 2' }, - { id: '3', name: 'Option 3' }, - { id: '4', name: 'Option 4' }, - { id: '5', name: 'Option 5' }, - { id: '6', name: 'Option 6' }, - { id: '7', name: 'Option 7' }, - ] - - const selectedOptions = [ - { id: '1', name: 'Option 1' }, - ] - - beforeEach(() => { - cy.mount(ChoiceSelector, { - props: { - options, - optionsSelected: selectedOptions, - label: 'Test Title', - description: 'Test Description', - disabled: false, - id: 'test-multi-select', - valueKey: 'id', - labelKey: 'name', - wrapped: false, - }, - }) - }) - - it('Should mount and display correctly', () => { - cy.get('[data-testid="choice-selector-title-test-multi-select"]').should('exist').and('contain', 'Test Title') - cy.get('[data-testid="choice-selector-description-test-multi-select"]').should('exist').and('contain', 'Test Description') - }) - - it('Should display options correctly', () => { - cy.get('[data-testid="1-test-multi-select-tag"]').should('exist').and('contain', 'Option 1') - cy.get('[data-testid="2-test-multi-select-tag"]').should('exist').and('contain', 'Option 2') - cy.get('[data-testid="3-test-multi-select-tag"]').should('exist').and('contain', 'Option 3') - }) - - it('Should search and filter options', () => { - cy.get('[data-testid="choice-selector-search-test-multi-select"]').type('Option 2') - cy.get('[data-testid="2-test-multi-select-tag"]').should('be.visible') - cy.get('[data-testid="1-test-multi-select-tag"]').should('not.exist') - cy.get('[data-testid="3-test-multi-select-tag"]').should('not.exist') - }) - - it('Should add and remove options', () => { - cy.get('[data-testid="2-test-multi-select-tag"]').click() - cy.get('[data-testid="2-test-multi-select-tag"]').should('have.class', 'fr-tag--dismiss') - cy.get('[data-testid="1-test-multi-select-tag"]').click() - cy.get('[data-testid="1-test-multi-select-tag"]').should('not.have.class', 'fr-tag--dismiss') - }) - - it('Should handle add all and remove all', () => { - cy.get('[data-testid="choice-selector-add-all-test-multi-select"]').click() - cy.get('[data-testid="1-test-multi-select-tag"]').should('have.class', 'fr-tag--dismiss') - cy.get('[data-testid="2-test-multi-select-tag"]').should('have.class', 'fr-tag--dismiss') - cy.get('[data-testid="3-test-multi-select-tag"]').should('have.class', 'fr-tag--dismiss') - - cy.get('[data-testid="choice-selector-remove-all-test-multi-select"]').click() - cy.get('[data-testid="1-test-multi-select-tag"]').should('not.have.class', 'fr-tag--dismiss') - cy.get('[data-testid="2-test-multi-select-tag"]').should('not.have.class', 'fr-tag--dismiss') - cy.get('[data-testid="3-test-multi-select-tag"]').should('not.have.class', 'fr-tag--dismiss') - }) - - it('Should handle add visible and remove visible', () => { - cy.get('[data-testid="choice-selector-search-test-multi-select"]').type('Option 2') - cy.get('[data-testid="choice-selector-add-visible-test-multi-select"]').click() - cy.get('[data-testid="2-test-multi-select-tag"]').should('have.class', 'fr-tag--dismiss') - - cy.get('[data-testid="choice-selector-search-test-multi-select"]').clear() - cy.get('[data-testid="choice-selector-remove-visible-test-multi-select"]').click() - cy.get('[data-testid="1-test-multi-select-tag"]').should('not.have.class', 'fr-tag--dismiss') - cy.get('[data-testid="2-test-multi-select-tag"]').should('not.have.class', 'fr-tag--dismiss') - cy.get('[data-testid="3-test-multi-select-tag"]').should('not.have.class', 'fr-tag--dismiss') - }) - - it('Should display correct message when no options available', () => { - // Remount the component with no options - cy.mount(ChoiceSelector, { - props: { - options: [], - optionsSelected: [], - label: 'Test Title', - description: 'Test Description', - disabled: false, - id: 'test-multi-select', - valueKey: 'id', - labelKey: 'name', - wrapped: false, - }, - }) - - cy.contains('Aucun choix disponible').should('be.visible') - }) - - it('Should display correct wrapped message when no selected options', () => { - // Remount the component with no selected options - cy.mount(ChoiceSelector, { - props: { - options, - optionsSelected: [], - label: 'Test Title', - description: 'Test Description', - disabled: false, - id: 'test-multi-select', - valueKey: 'id', - labelKey: 'name', - wrapped: true, - }, - }) - - cy.contains('Aucune sélection, 7 choix disponibles').should('be.visible') - }) - it('Should display correct wrapped message when more than 3 selected options', () => { - // Remount the component with no selected options - const options = [ - { id: '1', name: 'Option 1' }, - { id: '2', name: 'Option 2' }, - { id: '3', name: 'Option 3' }, - { id: '4', name: 'Option 4' }, - { id: '5', name: 'Option 5' }, - ] - cy.mount(ChoiceSelector, { - props: { - options, - optionsSelected: options, - label: 'Test Title', - description: 'Test Description', - disabled: false, - id: 'test-multi-select', - valueKey: 'id', - labelKey: 'name', - wrapped: true, - }, - }) - - cy.contains('et 2 de +').should('be.visible') - }) -}) diff --git a/apps/client/cypress/components/specs/cluster-form.ct.ts b/apps/client/cypress/components/specs/cluster-form.ct.ts deleted file mode 100644 index c85034f54..000000000 --- a/apps/client/cypress/components/specs/cluster-form.ct.ts +++ /dev/null @@ -1,192 +0,0 @@ -import type { Pinia } from 'pinia' -import type { ComponentCustomProps } from 'vue' -import { ClusterPrivacy, deleteValidationInput } from '@cpn-console/shared' -import { getRandomCluster, getRandomEnv, getRandomStage, getRandomZone, repeatFn } from '@cpn-console/test-utils' - -import { faker } from '@faker-js/faker' -import { createPinia, setActivePinia } from 'pinia' -import ClusterForm from '@/components/ClusterForm.vue' -import { useSnackbarStore } from '@/stores/snackbar.js' -import '@gouvfr/dsfr/dist/dsfr.min.css' - -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -describe('ClusterForm.vue', () => { - let pinia: Pinia - - beforeEach(() => { - pinia = createPinia() - - setActivePinia(pinia) - }) - - it('Should mount a new cluster ClusterForm', () => { - useSnackbarStore() - - const allProjects = repeatFn(5)(() => { return { id: faker.string.uuid(), label: faker.lorem.word() } }) - const allStages = repeatFn(4)(getRandomStage) - const allZones = repeatFn(3)(getRandomZone) - - const props = { - allProjects, - allStages, - allZones, - associatedEnvironments: [], - } - - cy.mount(ClusterForm, { props } as ComponentCustomProps) - cy.getByDataTestid('tlsServerNameInput') - .type('tlsServerName') - cy.getByDataTestid('labelInput') - .type('label') - cy.get('#privacy-select') - .select(ClusterPrivacy.DEDICATED) - cy.get('#zone-select') - .select(1) - cy.get('#projects-select') - .click() - cy.getByDataTestid(`${allProjects[0].id}-projects-select-tag`) - .click() - cy.get('#stages-select') - .click() - cy.getByDataTestid(`${allStages[1].id}-stages-select-tag`) - .click() - cy.getByDataTestid('addClusterBtn').should('be.enabled') - cy.getByDataTestid('associatedEnvironmentsZone').should('not.exist') - cy.getByDataTestid('deleteClusterZone').should('not.exist') - }) - - it('Should mount an update cluster ClusterForm', () => { - useSnackbarStore() - const allProjects = repeatFn(5)(() => { return { id: faker.string.uuid(), label: faker.lorem.word() } }) - const allStages = repeatFn(2)(getRandomStage) - const allZones = repeatFn(1)(getRandomZone) - - const props = { - cluster: getRandomCluster({ projectIds: [allProjects[0].id], stageIds: [allStages[1].id], privacy: ClusterPrivacy.DEDICATED, zoneId: allZones[0].id }), - allProjects, - allStages, - allZones, - isNewCluster: false, - associatedEnvironments: [], - } - - cy.mount(ClusterForm, { props } as ComponentCustomProps) - - cy.getByDataTestid('user-json').should('be.visible') - cy.getByDataTestid('cluster-json').should('be.visible') - cy.getByDataTestid('tlsServerNameInput') - .should('have.value', props.cluster.kubeconfig.cluster.tlsServerName) - .and('be.enabled') - cy.getByDataTestid('labelInput') - .should('have.value', props.cluster.label) - .and('be.enabled') - cy.getByDataTestid('infosInput') - .should('have.value', props.cluster.infos) - .and('be.enabled') - cy.get('#privacy-select') - .should('have.value', props.cluster.privacy) - cy.get('#zone-select') - .should('have.value', props.cluster.zoneId) - .and('be.enabled') - cy.get('#projects-select') - .click() - cy.get('#projects-select .fr-tag--dismiss') - .should('have.length', props.cluster.projectIds?.length) - cy.get('#stages-select') - .click() - cy.get('#stages-select .fr-tag--dismiss') - .should('have.length', props.cluster.stageIds?.length) - cy.getByDataTestid('memoryInput') - .should('have.value', props.cluster.memory) - cy.getByDataTestid('cpuInput') - .should('have.value', props.cluster.cpu) - cy.getByDataTestid('gpuInput') - .should('have.value', props.cluster.gpu) - cy.getByDataTestid('updateClusterBtn').should('be.enabled') - cy.getByDataTestid('associatedEnvironmentsZone').should('not.exist') - cy.getByDataTestid('deleteClusterZone').should('exist') - cy.getByDataTestid('showDeleteClusterBtn').click() - cy.getByDataTestid('deleteClusterBtn').should('be.disabled') - cy.getByDataTestid('deleteClusterInput').clear().type(deleteValidationInput) - cy.getByDataTestid('deleteClusterBtn').should('be.enabled') - }) - - it('Should mount an update cluster ClusterForm with associated environments', () => { - useSnackbarStore() - const allProjects = repeatFn(5)(() => { return { id: faker.string.uuid(), label: faker.lorem.word() } }) - const allStages = repeatFn(2)(getRandomStage) - const allZones = repeatFn(2)(getRandomZone) - - const cluster = getRandomCluster({ projectIds: [allProjects[0].id], stageIds: [allStages[1].id], privacy: ClusterPrivacy.DEDICATED, zoneId: allZones[0].id }) - const env = getRandomEnv('integ-1', allProjects[0].id, 'qsId', cluster.id) - const associatedEnvironments = [{ project: allProjects[0].name, name: env.name, owner: 'owner@dso.fr' }] - - const props = { - cluster, - allProjects, - allStages, - allZones, - isNewCluster: false, - associatedEnvironments, - } - - cy.mount(ClusterForm, { props } as ComponentCustomProps) - - cy.getByDataTestid('user-json').should('be.visible') - cy.getByDataTestid('cluster-json').should('be.visible') - cy.getByDataTestid('tlsServerNameInput') - .should('have.value', props.cluster.kubeconfig.cluster.tlsServerName) - .and('be.enabled') - cy.getByDataTestid('labelInput') - .should('have.value', props.cluster.label) - .and('be.disabled') - cy.getByDataTestid('infosInput') - .should('have.value', props.cluster.infos) - .and('be.enabled') - cy.get('#privacy-select') - .should('have.value', props.cluster.privacy) - cy.get('#zone-select') - .should('have.value', props.cluster.zoneId) - .and('be.enabled') - cy.get('#projects-select') - .click() - cy.get('#projects-select .fr-tag--dismiss') - .should('have.length', props.cluster.projectIds?.length) - cy.get('#stages-select') - .click() - cy.get('#stages-select .fr-tag--dismiss') - .should('have.length', props.cluster.stageIds?.length) - cy.getByDataTestid('memoryInput') - .should('have.value', props.cluster.memory) - cy.getByDataTestid('cpuInput') - .should('have.value', props.cluster.cpu) - cy.getByDataTestid('gpuInput') - .should('have.value', props.cluster.gpu) - cy.getByDataTestid('updateClusterBtn').should('be.enabled') - cy.getByDataTestid('deleteClusterZone').should('not.exist') - cy.getByDataTestid('associatedEnvironmentsZone').should('exist') - }) - - it('Should disable project selector when privacy is public', () => { - useSnackbarStore() - - const allProjects = repeatFn(5)(() => { return { id: faker.string.uuid(), label: faker.lorem.word() } }) - - const props = { - allProjects, - associatedEnvironments: [], - } - - cy.mount(ClusterForm, { props } as ComponentCustomProps) - cy.get('#privacy-select') - .select('dedicated') - cy.get('#projects-select').should('be.visible') - cy.get('#privacy-select') - .select('public') - cy.get('#projects-select').should('not.to.exist') - }) -}) diff --git a/apps/client/cypress/components/specs/config-param.ct.ts b/apps/client/cypress/components/specs/config-param.ct.ts deleted file mode 100644 index 4d96d639a..000000000 --- a/apps/client/cypress/components/specs/config-param.ct.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ref } from 'vue' -import ConfigParamComponent from '@/components/ConfigParam.vue' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -describe('ConfigParamComponent.vue', () => { - it('Affiche correctement le composant avec un champ de texte', () => { - const props = { - options: { - value: ref('test'), - description: 'Description test', - name: 'Test Input', - disabled: false, - kind: 'text', - placeholder: 'Placeholder test', - }, - } - - cy.mount(ConfigParamComponent, { props }) - - cy.contains('Test Input') - cy.contains('Description test') - cy.get('[data-testid="input"]').should('have.attr', 'placeholder', 'Placeholder test') - }) - - it('Affiche correctement le composant avec un bouton de commutation', () => { - const props = { - options: { - value: ref('enabled'), - description: 'Description test', - name: 'Test Switch', - disabled: false, - kind: 'switch', - }, - } - - cy.mount(ConfigParamComponent, { props }) - - cy.contains('Test Switch') - cy.contains('Description test') - cy.get('[data-testid="switch"]').within(() => { - cy.get('input') - .should('have.length', 3) // Vérifie qu'il y a trois boutons de commutation - }) - }) - - it('Modifie correctement la valeur du composant', () => { - const props = { - options: { - value: ref('enabled'), - name: 'Test Switch', - disabled: false, - kind: 'switch', - }, - } - - cy.mount(ConfigParamComponent, { props }) - - // Vérifie que la valeur a été modifiée - cy.get('[data-testid="switch"]').within(() => { - cy.get('.fr-segmented__element').eq(1).click() // Sélectionne le bouton de commutation "Défaut" - cy.get('input').eq(1).should('be.checked') - }) - }) -}) diff --git a/apps/client/cypress/components/specs/pagination-ct.ct.ts b/apps/client/cypress/components/specs/pagination-ct.ct.ts deleted file mode 100644 index ecea3e5b2..000000000 --- a/apps/client/cypress/components/specs/pagination-ct.ct.ts +++ /dev/null @@ -1,53 +0,0 @@ -import PaginationCt from '@/components/PaginationCt.vue' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -describe('PaginationCt.vue', () => { - it('Should mount a PaginationCt, first page', () => { - const props = { - length: 15, - step: 2, - page: 0, - } - - cy.mount(PaginationCt, { props }) - cy.getByDataTestid('positionInfo').should('contain', `1 - 2 sur ${props.length}`) - cy.getByDataTestid('seeFirstPageBtn').should('be.disabled') - cy.getByDataTestid('seePreviousPageBtn').should('be.disabled') - cy.getByDataTestid('seeNextPageBtn').should('be.enabled') - cy.getByDataTestid('seeLastPageBtn').should('be.enabled') - }) - - it('Should mount a PaginationCt, page 1', () => { - const props = { - length: 20, - step: 5, - page: 1, - } - - cy.mount(PaginationCt, { props }) - cy.getByDataTestid('positionInfo').should('contain', `6 - 10 sur ${props.length}`) - cy.getByDataTestid('seeFirstPageBtn').should('be.enabled') - cy.getByDataTestid('seePreviousPageBtn').should('be.enabled') - cy.getByDataTestid('seeNextPageBtn').should('be.enabled') - cy.getByDataTestid('seeLastPageBtn').should('be.enabled') - }) - - it('Should mount a PaginationCt, last page', () => { - const props = { - length: 43, - step: 10, - page: 4, - } - - cy.mount(PaginationCt, { props }) - cy.getByDataTestid('positionInfo').should('contain', `41 - 43 sur ${props.length}`) - cy.getByDataTestid('seeFirstPageBtn').should('be.enabled') - cy.getByDataTestid('seePreviousPageBtn').should('be.enabled') - cy.getByDataTestid('seeNextPageBtn').should('be.disabled') - cy.getByDataTestid('seeLastPageBtn').should('be.disabled') - }) -}) diff --git a/apps/client/cypress/components/specs/project-settings.ct.ts b/apps/client/cypress/components/specs/project-settings.ct.ts deleted file mode 100644 index ec8ddb5dd..000000000 --- a/apps/client/cypress/components/specs/project-settings.ct.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { ComponentCustomProps } from 'vue' -import { createRandomDbSetup } from '@cpn-console/test-utils' -import ProjectSettings from '@/components/ProjectSettings.vue' -import '@gouvminint/vue-dsfr/styles' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@/main.css' - -describe('ProjectSettings.vue', () => { - it('Should mount a ProjectSettings', () => { - const randomDbSetup = createRandomDbSetup({}) - - const props = { - project: randomDbSetup.project, - } - - cy.mount(ProjectSettings, { props } as ComponentCustomProps) - - cy.getByDataTestid('limitlessProjectSwitch') - .should('be.visible') - .and('not.be.checked') - }) -}) diff --git a/apps/client/cypress/components/specs/repo-form.ct.ts b/apps/client/cypress/components/specs/repo-form.ct.ts deleted file mode 100644 index 0ef004ee4..000000000 --- a/apps/client/cypress/components/specs/repo-form.ct.ts +++ /dev/null @@ -1,327 +0,0 @@ -import type { Pinia } from 'pinia' -import type { ComponentCustomProps } from 'vue' -import { fakeToken, missingCredentials } from '@cpn-console/shared' -import { createRandomDbSetup } from '@cpn-console/test-utils' - -import { createPinia, setActivePinia } from 'pinia' -import RepoForm from '@/components/RepoForm.vue' -import { useProjectStore } from '@/stores/project.js' -import '@gouvminint/vue-dsfr/styles' -import '@gouvfr/dsfr/dist/dsfr.min.css' - -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@/main.css' - -describe('RepoForm.vue', () => { - let pinia: Pinia - - beforeEach(() => { - pinia = createPinia() - - setActivePinia(pinia) - }) - - it('Should mount a new repo RepoForm', () => { - const props = { - canManage: true, - } - - const randomDbSetup = createRandomDbSetup({}) - const projectStore = useProjectStore() - projectStore.myProjectsBySlug = { - [randomDbSetup.project.slug]: randomDbSetup.project, - } - - cy.mount(RepoForm, { props } as ComponentCustomProps) - - cy.get('h2').should('contain', 'Ajouter un dépôt au projet') - cy.getByDataTestid('repoFieldset').should('have.length', 1) - // Case 1 : no Git source - cy.getByDataTestid('internalRepoNameInput') - .should('have.value', '') - .type('candilib') - cy.getByDataTestid('standaloneRepoSwitch') - .find('input') - .check({ force: true }) - cy.getByDataTestid('externalRepoUrlInput').should('not.exist') - cy.getByDataTestid('input-checkbox-privateRepoCbx').should('not.exist') - cy.getByDataTestid('externalUserNameInput').should('not.exist') - cy.getByDataTestid('externalTokenInput').should('not.exist') - cy.getByDataTestid('input-checkbox-infraRepoCbx') - .should('not.be.checked') - .and('be.enabled') - cy.getByDataTestid('addRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - // Case 2 : no Git source, infra - cy.getByDataTestid('input-checkbox-infraRepoCbx').check({ force: true }) - cy.getByDataTestid('addRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - // Case 3 : Git source - cy.getByDataTestid('standaloneRepoSwitch') - .find('input') - .uncheck({ force: true }) - cy.getByDataTestid('externalRepoUrlInput') - .type('https://github.com/LAB-MI/candilibV2.git') - .blur() - cy.getByDataTestid('addRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - // Case 4 : Git source, private - cy.getByDataTestid('input-checkbox-privateRepoCbx') - .should('exist') - .and('be.enabled') - cy.getByDataTestid('input-checkbox-privateRepoCbx').check({ force: true }) - cy.getByDataTestid('externalUserNameInput').should('exist') - cy.getByDataTestid('externalTokenInput').should('exist') - cy.getByDataTestid('addRepoBtn').should('be.disabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - cy.getByDataTestid('externalUserNameInput').type('claire+nlet') - cy.getByDataTestid('externalTokenInput') - .type('aaaaaa') - .blur() - cy.getByDataTestid('addRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - }) - - it('Should mount an update repo RepoForm', () => { - const props = { - repo: { - id: '83833faf-f654-40dd-bcd5-cf2e944fc504', - projectId: '83833faf-f654-40dd-bcd5-cf2e944fc500', - internalRepoName: 'candilib', - externalRepoUrl: 'https://github.com/LAB-MI/candilibV2.git', - isPrivate: true, - isInfra: false, - externalUserName: 'claire+nlet', - deployRevision: 'fix/deploy', - deployPath: 'helm4/', - helmValuesFiles: 'values/prod.yaml,values/extra.yaml', - }, - canManage: true, - } - - const randomDbSetup = createRandomDbSetup({}) - const projectStore = useProjectStore() - projectStore.myProjectsBySlug = { - [randomDbSetup.project.slug]: randomDbSetup.project, - } - - cy.mount(RepoForm, { props } as ComponentCustomProps) - - cy.get('h2').should('contain', 'Modifier le dépôt') - cy.getByDataTestid('repoFieldset').should('have.length', 1) - cy.getByDataTestid('internalRepoNameInput').should('have.value', props.repo.internalRepoName) - .and('be.disabled') - cy.getByDataTestid('externalRepoUrlInput').should('have.value', props.repo.externalRepoUrl) - .and('be.enabled') - cy.getByDataTestid('input-checkbox-privateRepoCbx').should('be.checked') - .and('be.enabled') - cy.getByDataTestid('externalUserNameInput').should('have.value', props.repo.externalUserName) - .and('be.enabled') - cy.getByDataTestid('externalTokenInput').should('have.value', fakeToken) - .and('be.enabled') - cy.getByDataTestid('input-checkbox-infraRepoCbx').should('not.be.checked') - .and('be.enabled') - cy.getByDataTestid('standaloneRepoSwitch') - .find('input') - .should('not.be.checked') - .and('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('externalTokenInput') - .clear() - .type('aaaaaaa') - .blur() - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - - // Case 1 privacy handling - cy.getByDataTestid('input-checkbox-privateRepoCbx') - .uncheck({ force: true }) - cy.getByDataTestid('input-checkbox-privateRepoCbx').check({ force: true }) - cy.getByDataTestid('externalUserNameInput') - .should('exist') - .and('have.value', '') - cy.getByDataTestid('externalTokenInput') - .should('exist') - .and('have.value', '') - cy.getByDataTestid('updateRepoBtn').should('be.disabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - cy.getByDataTestid('externalUserNameInput').type(props.repo.externalUserName) - cy.getByDataTestid('externalTokenInput') - .type('aaaaaa') - .blur() - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - - // Case 2 : no Git source - cy.getByDataTestid('externalRepoUrlInput') - .clear() - .should('have.value', '') - .blur() - cy.getByDataTestid('standaloneRepoSwitch') - .find('input') - .check({ force: true }) - cy.getByDataTestid('input-checkbox-privateRepoCbx') - .should('not.exist') - cy.getByDataTestid('externalUserNameInput').should('not.exist') - cy.getByDataTestid('externalTokenInput').should('not.exist') - cy.getByDataTestid('input-checkbox-infraRepoCbx') - .should('not.be.checked') - .and('be.enabled') - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - - // Case 3 : no Git source, infra - cy.getByDataTestid('input-checkbox-infraRepoCbx').check({ force: true }) - cy.getByDataTestid('deployRevisionInput').should('have.value', props.repo.deployRevision) - .and('be.enabled') - cy.getByDataTestid('deployPathInput').should('have.value', props.repo.deployPath) - .and('be.enabled') - cy.getByDataTestid('helmValuesFilesTextarea').should('have.value', props.repo.helmValuesFiles.split(',').join('\n')) - .and('be.enabled') - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - - // Case 4 : Git source - cy.getByDataTestid('standaloneRepoSwitch') - .find('input') - .uncheck({ force: true }) - cy.getByDataTestid('externalRepoUrlInput') - .type(props.repo.externalRepoUrl) - .blur() - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('cancelRepoBtn').should('be.enabled') - }) - - it('Should handle token behaviors, create', () => { - const props = { - canManage: true, - } - - const randomDbSetup = createRandomDbSetup({}) - const projectStore = useProjectStore() - projectStore.myProjectsBySlug = { - [randomDbSetup.project.slug]: randomDbSetup.project, - } - - cy.mount(RepoForm, { props } as ComponentCustomProps) - - cy.getByDataTestid('repoFieldset').should('have.length', 1) - cy.getByDataTestid('internalRepoNameInput') - .should('have.value', '') - .type('candilib') - - cy.getByDataTestid('externalRepoUrlInput') - .type('https://github.com/LAB-MI/candilibV2.git') - .blur() - cy.getByDataTestid('addRepoBtn').should('be.enabled') - - cy.getByDataTestid('input-checkbox-privateRepoCbx').check({ force: true }) - cy.getByDataTestid('addRepoBtn').should('be.disabled') - cy.getByDataTestid('externalUserNameInput').should('exist') - cy.getByDataTestid('externalTokenInput') - .type('aaaaaa') - .blur() - cy.getByDataTestid('repo-form').should('not.contain', missingCredentials) - cy.getByDataTestid('addRepoBtn').should('be.enabled') - cy.getByDataTestid('externalTokenInput') - .clear() - .blur() - cy.getByDataTestid('repo-form').should('contain', missingCredentials) - cy.getByDataTestid('addRepoBtn').should('be.disabled') - }) - - it('Should handle token behaviors, update public', () => { - const props = { - repo: { - id: '83833faf-f654-40dd-bcd5-cf2e944fc504', - projectId: '83833faf-f654-40dd-bcd5-cf2e944fc500', - internalRepoName: 'candilib', - externalRepoUrl: 'https://github.com/LAB-MI/candilibV2.git', - isPrivate: false, - isInfra: false, - externalUserName: 'claire+nlet', - }, - canManage: true, - } - - const randomDbSetup = createRandomDbSetup({}) - const projectStore = useProjectStore() - projectStore.myProjectsBySlug = { - [randomDbSetup.project.slug]: randomDbSetup.project, - } - - cy.mount(RepoForm, { props } as ComponentCustomProps) - - cy.getByDataTestid('repoFieldset').should('have.length', 1) - - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - - cy.getByDataTestid('input-checkbox-privateRepoCbx').check({ force: true }) - cy.getByDataTestid('updateRepoBtn').should('be.disabled') - cy.getByDataTestid('externalUserNameInput').should('exist') - cy.getByDataTestid('externalTokenInput') - .type('aaaaaa') - .blur() - cy.getByDataTestid('repo-form').should('not.contain', missingCredentials) - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('externalTokenInput') - .clear() - .blur() - cy.getByDataTestid('repo-form').should('contain', missingCredentials) - cy.getByDataTestid('updateRepoBtn').should('be.disabled') - }) - - it('Should handle token behaviors, update private', () => { - const props = { - repo: { - id: '83833faf-f654-40dd-bcd5-cf2e944fc504', - projectId: '83833faf-f654-40dd-bcd5-cf2e944fc500', - internalRepoName: 'candilib', - externalRepoUrl: 'https://github.com/LAB-MI/candilibV2.git', - isPrivate: true, - isInfra: false, - externalUserName: 'claire+nlet', - }, - canManage: true, - } - - const randomDbSetup = createRandomDbSetup({}) - const projectStore = useProjectStore() - projectStore.myProjectsBySlug = { - [randomDbSetup.project.slug]: randomDbSetup.project, - } - - cy.mount(RepoForm, { props } as ComponentCustomProps) - - cy.getByDataTestid('repoFieldset').should('have.length', 1) - - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - - cy.getByDataTestid('input-checkbox-privateRepoCbx').check({ force: true }) - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('externalUserNameInput').should('exist') - cy.getByDataTestid('externalTokenInput') - .type('a') - .blur() - cy.getByDataTestid('warningSecretChanged') - .should('be.visible') - cy.getByDataTestid('repo-form').should('not.contain', missingCredentials) - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('resetTokenButton') - .click() - cy.getByDataTestid('warningSecretChanged') - .should('not.exist') - cy.getByDataTestid('repo-form').should('not.contain', missingCredentials) - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - // missing creds - cy.getByDataTestid('externalTokenInput') - .clear() - .blur() - cy.getByDataTestid('externalUserNameInput') - .clear() - .blur() - cy.getByDataTestid('repo-form').should('contain', missingCredentials) - cy.getByDataTestid('updateRepoBtn').should('be.disabled') - }) -}) diff --git a/apps/client/cypress/components/specs/services-config.ct.ts b/apps/client/cypress/components/specs/services-config.ct.ts deleted file mode 100644 index 2e9c8edde..000000000 --- a/apps/client/cypress/components/specs/services-config.ct.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { Pinia } from 'pinia' -import { faker } from '@faker-js/faker' -import { createPinia, setActivePinia } from 'pinia' -import ServicesConfig from '@/components/ServicesConfig.vue' -import { useProjectStore } from '@/stores/project.js' -import { useUserStore } from '@/stores/user.js' -import { Project } from '@/utils/project-utils.js' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -process.env.NODE_ENV = 'test' -process.env.CT = 'true' - -const argoto = { to: 'https://argocd.domain.com/applications?showFavorites=false&proj=&sync=&health=&namespace=&cluster=&labels=&search=org-project', name: '' } -const gitlabto = { to: 'https://gitlab.domain.com/forge-mi/projects/org/project', name: '' } -const services = [ - { imgSrc: '/img/argocd.svg', title: 'ArgoCD', name: 'argocd', urls: [argoto, argoto, argoto], manifest: {} }, - { imgSrc: '/img/gitlab.svg', title: 'Gitlab', name: 'gitlab', urls: [gitlabto, gitlabto], manifest: {} }, - { imgSrc: '/img/harbor.svg', title: 'Harbor', name: 'registry', urls: [{ to: 'https://harbor.domain.com/harbor/projects/254', name: '' }], manifest: { global: [{ permissions: { admin: { read: true, write: true }, user: { read: true, write: false } }, key: 'publish-ro-robot-by-default', kind: 'switch', title: 'Publier le robot RO par défaut', value: 'default', initialValue: 'disabled' }], project: [{ permissions: { admin: { read: true, write: true }, user: { read: true, write: false } }, key: 'view-robot', kind: 'switch', title: 'Publier le robot', initialValue: 'disabled', value: 'default', description: 'Autoriser un robot de lecture sur le projet' }] } }, - { imgSrc: '/img/sonarqube.svg', title: 'SonarQube', name: 'sonarqube', urls: [], manifest: {} }, -] - -const urlsLength = services.reduce((length, service) => length + service.urls.length, 0) - -const project = { - clusterIds: [], - createdAt: Date.now().toString(), - updatedAt: Date.now().toString(), - everyonePerms: '0', - id: faker.string.uuid(), - lastSuccessProvisionningVersion: null, - locked: false, - members: [], - name: 'projet-test', - owner: { - createdAt: Date.now().toString(), - updatedAt: Date.now().toString(), - email: faker.internet.email(), - firstName: faker.person.firstName(), - lastName: faker.person.lastName(), - id: faker.string.uuid(), - type: 'human' as const, - lastLogin: null, - }, - ownerId: faker.string.uuid(), - roles: [], - slug: faker.string.alphanumeric(10), - status: 'created' as const, -} - -describe('Service Configuration Component', () => { - let pinia: Pinia - - beforeEach(() => { - pinia = createPinia() - - setActivePinia(pinia) - }) - it('Affiche correctement les services et leurs configurations', () => { - const projectStore = useProjectStore() - projectStore.projectsBySlug[project.slug] = project - - useUserStore() - const instanceProject = new Project(project) - cy.intercept('GET', 'api/v1/projects/*/services*', { - body: services, - }).as('listServices') - cy.mount(ServicesConfig, { - propsData: { - project: instanceProject, - permissionTarget: 'user', - displayGlobal: true, - }, - }) - - // Vérifie que les services sont correctement affichés - cy.getByDataTestid('services-urls').find('a').should('have.length', urlsLength) - - cy.getByDataTestid('service-config-registry').should('exist') - - // Vérifie que les boutons de lien sont présents et fonctionnent - cy.getByDataTestid('service-config-registry').click() // Simule un clic sur le premier lien - - // Vérifie que les boutons de rechargement sont présents - cy.getByDataTestid('reloadBtn').should('exist') - }) - - it('Interagit correctement avec le bouton de dropdown', () => { - useProjectStore() - useUserStore() - const instanceProject = new Project(project) - cy.intercept('GET', 'api/v1/projects/*/services*', { - body: services, - }).as('listServices') - - cy.mount(ServicesConfig, { - propsData: { - project: instanceProject, - permissionTarget: 'user', - displayGlobal: true, - }, - }) - // Simule un clic sur le bouton d'extension - cy.getByDataTestid('service-config-registry') - .click() - cy.getByDataTestid('service-project-config-registry') - .should('exist') - cy.getByDataTestid('service-project-config-registry') - .should('exist') - }) -}) diff --git a/apps/client/cypress/components/specs/stage-form.ct.ts b/apps/client/cypress/components/specs/stage-form.ct.ts deleted file mode 100644 index a61ffcad9..000000000 --- a/apps/client/cypress/components/specs/stage-form.ct.ts +++ /dev/null @@ -1,102 +0,0 @@ -import type { Pinia } from 'pinia' -import type { ComponentCustomProps } from 'vue' -import { getRandomCluster, getRandomEnv, getRandomStage } from '@cpn-console/test-utils' -import { createPinia, setActivePinia } from 'pinia' -import StageForm from '@/components/StageForm.vue' -import { useSnackbarStore } from '@/stores/snackbar.js' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -describe('StageForm.vue', () => { - let pinia: Pinia - - beforeEach(() => { - pinia = createPinia() - - setActivePinia(pinia) - }) - it('Should mount a new StageForm', () => { - useSnackbarStore() - const allClusters = [getRandomCluster({}), getRandomCluster({})] - - const props = { - isNewStage: true, - allClusters, - } - - cy.mount(StageForm, { props } as ComponentCustomProps) - cy.get('h1').invoke('text').should('match', /^Informations du type d'environnement $/) - cy.getByDataTestid('updateStageBtn').should('not.exist') - cy.getByDataTestid('addStageBtn').should('be.visible').and('be.disabled') - cy.getByDataTestid('nameInput') - .type('integ') - cy.get('h1').invoke('text').should('match', /^Informations du type d'environnement integ$/) - cy.getByDataTestid('addStageBtn').should('be.enabled') - cy.getByDataTestid(`${allClusters[0].id}-clusters-select-tag`) - .click() - cy.getByDataTestid(`${allClusters[1].id}-clusters-select-tag`) - .click() - cy.getByDataTestid('addStageBtn').should('be.enabled') - }) - - it('Should mount an update stage StageForm', () => { - useSnackbarStore() - const allClusters = [getRandomCluster({}), getRandomCluster({})] - // @ts-ignore - const stageToUpdate = getRandomStage(undefined, { clusters: allClusters }) - const associatedEnvironments = [ - getRandomEnv('env1', 'projectId', 'stageId', allClusters[0].id), - getRandomEnv('env2', 'projectId', 'stageId', allClusters[1].id), - ] - - const props = { - stage: stageToUpdate, - allClusters, - associatedEnvironments, - isNewStage: false, - } - - cy.mount(StageForm, { props } as ComponentCustomProps) - cy.get('h1').invoke('text').should('contain', `Informations du type d'environnement ${stageToUpdate.name}`) - cy.getByDataTestid('addStageBtn').should('not.exist') - cy.getByDataTestid('updateStageBtn').should('be.visible').and('be.enabled') - cy.getByDataTestid('nameInput') - .should('have.value', stageToUpdate.name) - .and('be.disabled') - cy.getByDataTestid(`${allClusters[0].id}-clusters-select-tag`) - .should('have.class', 'fr-tag--dismiss') - cy.getByDataTestid('updateStageBtn').should('be.enabled') - cy.getByDataTestid('associatedEnvironmentsTable').should('exist') - .find('tbody > tr') - .should('have.length', associatedEnvironments.length) - }) - - it('Should mount an update StageForm without associatedEnvironments', () => { - useSnackbarStore() - const allClusters = [getRandomCluster({}), getRandomCluster({})] - // @ts-ignore - const stageToUpdate = getRandomStage(undefined, { clusters: [allClusters[0]] }) - - const props = { - stage: stageToUpdate, - allClusters, - isNewStage: false, - } - - cy.mount(StageForm, { props } as ComponentCustomProps) - cy.get('h1').invoke('text').should('contain', `Informations du type d'environnement ${stageToUpdate.name}`) - cy.getByDataTestid('addStageBtn').should('not.exist') - cy.getByDataTestid('updateStageBtn').should('be.visible').and('be.enabled') - cy.getByDataTestid('nameInput') - .should('have.value', stageToUpdate.name) - .and('be.disabled') - cy.getByDataTestid(`${allClusters[0].id}-clusters-select-tag`) - .should('have.class', 'fr-tag--dismiss') - cy.getByDataTestid('updateStageBtn').should('be.enabled') - cy.getByDataTestid('associatedEnvironmentsZone').should('not.exist') - cy.getByDataTestid('deleteStageZone').should('exist') - }) -}) diff --git a/apps/client/cypress/components/specs/suggestion-input.ct.ts b/apps/client/cypress/components/specs/suggestion-input.ct.ts deleted file mode 100644 index 9e829c933..000000000 --- a/apps/client/cypress/components/specs/suggestion-input.ct.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { createRandomDbSetup } from '@cpn-console/test-utils' -import SuggestionInput from '@/components/SuggestionInput.vue' -import '@gouvminint/vue-dsfr/styles' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@/main.css' - -describe('SuggestionInput.vue', () => { - it('Should mount a SuggestionInput', () => { - const randomDbSetup = createRandomDbSetup({ nbUsers: 5 }) - - const props = { - suggestions: randomDbSetup.users.map(user => user.email), - } - - cy.mount(SuggestionInput, { props }) - - cy.get('input[list="suggestionList"]') - .should('have.length', 1) - .and('have.value', '') - .clear() - .type(props.suggestions[0].slice(0, 2)) - cy.get('datalist#suggestionList') - .should('have.length', 1) - .find('option') - .should('have.length', props.suggestions.length) - }) -}) diff --git a/apps/client/cypress/components/specs/team-ct.ct.ts b/apps/client/cypress/components/specs/team-ct.ct.ts deleted file mode 100644 index 0b092b118..000000000 --- a/apps/client/cypress/components/specs/team-ct.ct.ts +++ /dev/null @@ -1,110 +0,0 @@ -import type { ProjectV2 } from '@cpn-console/shared' -import type { Pinia } from 'pinia' -import { faker } from '@faker-js/faker' -import { createPinia, setActivePinia } from 'pinia' -import TeamCt from '@/components/TeamCt.vue' -import { useProjectStore } from '@/stores/project.js' -import { useUserStore } from '@/stores/user.js' -import { useUsersStore } from '@/stores/users.js' -import '@gouvminint/vue-dsfr/styles' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@/main.css' - -const ownerId = faker.string.uuid() -const props: { - project: ProjectV2 - canManage: boolean - canTransfer: boolean -} = { - project: { - members: [{ - userId: faker.string.uuid(), - roleIds: [], - email: faker.internet.email(), - }], - owner: { - email: faker.internet.email(), - id: ownerId, - }, - ownerId, - roles: [], - }, - canManage: true, - canTransfer: true, -} - -describe('TeamCt.vue', () => { - let pinia: Pinia - - beforeEach(() => { - pinia = createPinia() - - setActivePinia(pinia) - }) - - it('Should mount a TeamCt for owner', () => { - useProjectStore() - useUsersStore() - - cy.mount(TeamCt, { props }) - - cy.getByDataTestid('teamTable').should('be.visible') - .within(() => { - cy.get('caption') - .should('contain', 'Membres du projet') - cy.get('tbody > tr') - .should('have.length', props.project.members.length + 1) // +1 cause owner is not a member - cy.get('thead > tr > th') - .should('have.length', 4) - }) - cy.getByDataTestid('showTransferProjectBtn') - .should('be.enabled') - .should('be.visible') - cy.getByDataTestid('addUserSuggestionInput') - .should('be.enabled') - .should('be.visible') - }) - it('Should mount a TeamCt for manage', () => { - useProjectStore() - cy.mount(TeamCt, { props: { ...props, canTransfer: false } }) - - cy.getByDataTestid('teamTable').should('be.visible') - .within(() => { - cy.get('caption') - .should('contain', 'Membres du projet') - cy.get('tbody > tr') - .should('have.length', props.project.members.length + 1) // +1 cause owner is not a member - cy.get('thead > tr > th') - .should('have.length', 4) - }) - cy.getByDataTestid('showTransferProjectBtn') - .should('not.exist') - cy.getByDataTestid('addUserSuggestionInput') - .should('be.enabled') - .should('be.visible') - }) - it('Should mount a TeamCt for user', () => { - useProjectStore() - const userStore = useUserStore() - // devrait tester que l'on peut toujours quitter un projet - userStore.userProfile = { id: props.project.members[0].id } - - cy.mount(TeamCt, { props: { ...props, canTransfer: false, canManage: false } }) - - cy.getByDataTestid('teamTable').should('be.visible') - .within(() => { - cy.get('caption') - .should('contain', 'Membres du projet') - cy.get('tbody > tr') - .should('have.length', props.project.members.length + 1) // +1 cause owner is not a member - cy.get('thead > tr > th') - .should('have.length', 4) - }) - cy.getByDataTestid('showTransferProjectBtn') - .should('not.exist') - cy.getByDataTestid('addUserSuggestionInput') - .should('not.exist') - }) -}) diff --git a/apps/client/cypress/components/specs/token-form.ct.ts b/apps/client/cypress/components/specs/token-form.ct.ts deleted file mode 100644 index 7c7737766..000000000 --- a/apps/client/cypress/components/specs/token-form.ct.ts +++ /dev/null @@ -1,72 +0,0 @@ -import type { Pinia } from 'pinia' -import { createPinia, setActivePinia } from 'pinia' - -import TokenForm from '@/components/TokenForm.vue' -import { useSnackbarStore } from '@/stores/snackbar.js' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' - -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -describe('TokenForm.vue', () => { - let pinia: Pinia - - beforeEach(() => { - pinia = createPinia() - - setActivePinia(pinia) - }) - - it('Should mount a TokenForm', () => { - useSnackbarStore() - // @ts-ignore - cy.mount(TokenForm, { props: { - exposedToken: undefined, - } }) - - cy.getByDataTestid('saveBtn') - .should('be.disabled') - - cy.getByDataTestid('newTokenName') - .type('test') - - cy.getByDataTestid('saveBtn') - .should('be.enabled') - .click() - }) - - it('Should mount a TokenForm', () => { - const password = 'dfvbjfdbvjkdbvdfb' - - useSnackbarStore() - // @ts-ignore - cy.mount(TokenForm, { props: { - exposedToken: password, - } }) - - cy.getByDataTestid('newTokenPassword') - .get('input') - .should('be.visible') - .should('contain.value', password) - .should('have.attr', 'type', 'password') - - cy.getByDataTestid('showNewTokenPassword') - .click() - - cy.getByDataTestid('newTokenPassword') - .get('input') - .should('have.attr', 'type', 'text') - - cy.getByDataTestid('showNewTokenPassword') - .click() - - cy.getByDataTestid('newTokenPassword') - .get('input') - .should('have.attr', 'type', 'password') - - cy.getByDataTestid('showNewTokenFormBtn') - .click() - }) -}) diff --git a/apps/client/cypress/components/specs/zone-form.ct.ts b/apps/client/cypress/components/specs/zone-form.ct.ts deleted file mode 100644 index 2b44e51c0..000000000 --- a/apps/client/cypress/components/specs/zone-form.ct.ts +++ /dev/null @@ -1,125 +0,0 @@ -import type { Pinia } from 'pinia' -import { getRandomCluster, getRandomZone } from '@cpn-console/test-utils' - -import { createPinia, setActivePinia } from 'pinia' -import ZoneForm from '@/components/ZoneForm.vue' -import { useSnackbarStore } from '@/stores/snackbar.js' -import '@gouvfr/dsfr/dist/dsfr.min.css' -import '@gouvfr/dsfr/dist/utility/icons/icons.min.css' - -import '@gouvfr/dsfr/dist/utility/utility.main.min.css' -import '@gouvminint/vue-dsfr/styles' -import '@/main.css' - -describe('ZoneForm.vue', () => { - let pinia: Pinia - - beforeEach(() => { - pinia = createPinia() - - setActivePinia(pinia) - }) - - it('Should mount a new zone ZoneForm', () => { - useSnackbarStore() - - const props = { - associatedClusters: [], - isNewZone: true, - allClusters: [getRandomCluster({})], - } - - cy.mount(ZoneForm, { props }) - - cy.getByDataTestid('addZoneBtn').should('be.disabled') - cy.getByDataTestid('deleteZoneZone').should('not.exist') - cy.getByDataTestid('slugInput') - .clear() - .type('zad') - cy.getByDataTestid('labelInput') - .clear() - .type('Zone à Défendre') - cy.getByDataTestid('argocdUrlInput') - .clear() - .type('https://vousetesici.fr') - cy.getByDataTestid('addZoneBtn').should('be.enabled') - cy.getByDataTestid('descriptionInput') - .clear() - .type('Cette zone de déploiement est publique.') - cy.getByDataTestid('addZoneBtn').should('be.enabled') - }) - - it('Should mount a new zone ZoneForm without clusters', () => { - useSnackbarStore() - - const props = { - associatedClusters: [], - isNewZone: true, - allClusters: [], - } - - cy.mount(ZoneForm, { props }) - - cy.getByDataTestid('addZoneBtn').should('be.disabled') - cy.getByDataTestid('deleteZoneZone').should('not.exist') - cy.getByDataTestid('slugInput') - .clear() - .type('zad') - cy.getByDataTestid('labelInput') - .clear() - .type('Zone à Défendre') - cy.getByDataTestid('argocdUrlInput') - .clear() - .type('https://vousetesici.fr') - cy.getByDataTestid('addZoneBtn').should('be.enabled') - cy.getByDataTestid('descriptionInput') - .clear() - .type('Cette zone de déploiement est publique.') - cy.getByDataTestid('addZoneBtn').should('be.enabled') - }) - - it('Should mount an update ZoneForm', () => { - const zone = getRandomZone() - const cluster = getRandomCluster({ zoneId: zone.id }) - useSnackbarStore() - - const props = { - associatedClusters: [cluster], - zone: { ...zone, clusterIds: [cluster.id] }, - allClusters: [cluster], - } - - cy.mount(ZoneForm, { props }) - - cy.getByDataTestid('updateZoneBtn').should('be.enabled') - cy.getByDataTestid('deleteZoneZone').should('not.exist') - cy.getByDataTestid('slugInput') - .should('have.value', props.zone.slug) - .and('be.disabled') - cy.getByDataTestid('labelInput') - .should('have.value', props.zone.label) - .and('be.enabled') - .clear() - .type('Zone à Détruire') - cy.getByDataTestid('argocdUrlInput') - .should('have.value', props.zone.argocdUrl) - .and('be.enabled') - .clear() - .type('https://vousetesici.fr') - cy.getByDataTestid('updateZoneBtn').should('be.enabled') - cy.getByDataTestid('descriptionInput') - .should('have.value', props.zone.description) - .and('be.enabled') - .clear() - .type('Cette zone de déploiement est privée.') - cy.getByDataTestid('updateZoneBtn').should('be.enabled') - cy.get('#clusters-select h6') - .click() - cy.getByDataTestid(`${props.allClusters[0].id}-clusters-select-tag`) - .should('be.visible') - .click() - cy.getByDataTestid(`${props.allClusters[0].id}-clusters-select-tag`) - .should('be.disabled') - cy.getByDataTestid('updateZoneBtn').should('be.enabled') - }) -}) diff --git a/apps/client/cypress/components/support/commands.ts b/apps/client/cypress/components/support/commands.ts deleted file mode 100644 index bb718ef14..000000000 --- a/apps/client/cypress/components/support/commands.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { mount } from '@cypress/vue' -import VueDsfr from '@gouvminint/vue-dsfr' - -import 'virtual:uno.css' -import 'uno.css' -import 'virtual:unocss-devtools' -import '@/main.css' -// import { ComponentOptions, ComponentOptionsWithObjectProps } from 'vue' - -Cypress.Commands.add('mount', (component, options = {}) => { - // Setup options object - options.global = options.global || {} - options.global.components = options.global.components || {} - options.global.plugins = options.global.plugins || [] - - options.global.plugins.push({ - install(app) { - app.use(VueDsfr) - }, - }) - - return mount(component, options) -}) - -Cypress.Commands.add('getByDataTestid', (dataTestid) => { - cy.get(`[data-testid="${dataTestid}"]`) -}) diff --git a/apps/client/cypress/components/support/component-index.html b/apps/client/cypress/components/support/component-index.html deleted file mode 100644 index 9757aea74..000000000 --- a/apps/client/cypress/components/support/component-index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - Components App - - -
- - diff --git a/apps/client/cypress/components/support/index.ts b/apps/client/cypress/components/support/index.ts deleted file mode 100644 index 92074a8c6..000000000 --- a/apps/client/cypress/components/support/index.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable ts/method-signature-style */ -import type { mount } from '@cypress/vue' -import './commands.js' - -type MountParams = Parameters -type OptionsParam = MountParams[1] - -declare global { - // eslint-disable-next-line ts/no-namespace - namespace Cypress { - interface Chainable { - /** - * Helper mount function for Vue Components - * @param component Vue Component or JSX Element to mount - * @param options Options passed to mount the component - */ - mount( - component: any, - options?: OptionsParam - ): Chainable - } - } -} diff --git a/apps/client/cypress/e2e/specs/03-modal.e2e.ts b/apps/client/cypress/e2e/specs/03-modal.e2e.ts deleted file mode 100644 index 1ed0741e1..000000000 --- a/apps/client/cypress/e2e/specs/03-modal.e2e.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { getModelById } from '../support/func.js' - -describe('Manage project environments', () => { - const project = getModelById('project', '011e7860-04d7-461f-912d-334c622d38c5') - - it('Test modal behaviour', () => { - cy.kcLogin('test') - - cy.intercept('GET', 'api/v1/clusters').as('getClusters') - cy.intercept('GET', 'api/v1/stages').as('listStages') - cy.intercept('GET', 'api/v1/quotas').as('listQuotas') - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - - cy.goToProjects() - .getByDataTestid(`projectTile-${project?.slug}`) - .click() - - cy.getByDataTestid('environmentTr-integration') - .as('envTr') - - // Open the modal - cy.get('@envTr').click() - cy.get('#fr-modal-1').should('be.visible') - - // close by clickOutside - cy.get('#fr-modal-1') - .click('right') - cy.getByDataTestid('resource-modal') - .should('not.exist') - - // Open the modal - cy.get('@envTr').click() - cy.get('#fr-modal-1').should('be.visible') - - // close by native button - cy.get('div.fr-modal__header > button.fr-btn--close') - .click() - cy.getByDataTestid('resource-modal') - .should('not.exist') - - // Open the modal - cy.get('@envTr').click() - cy.get('#fr-modal-1').should('be.visible') - - // cancel by form button - cy.getByDataTestid('cancelEnvironmentBtn') - .click() - cy.getByDataTestid('resource-modal') - .should('not.exist') - - // Open the modal - cy.get('@envTr').click() - cy.get('#fr-modal-1').should('be.visible') - - // cancel by pressing escape - cy.get('body').type('{esc}') - cy.getByDataTestid('resource-modal') - .should('not.exist') - }) -}) diff --git a/apps/client/cypress/e2e/specs/admin/logs.e2e.ts b/apps/client/cypress/e2e/specs/admin/logs.e2e.ts deleted file mode 100644 index b94d408cd..000000000 --- a/apps/client/cypress/e2e/specs/admin/logs.e2e.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { Log } from '@cpn-console/shared' - -describe('Administration logs', () => { - let logCount: number - let logs: Log[] - - beforeEach(() => { - cy.intercept('GET', 'api/v1/logs*').as('getAllLogs') - - cy.kcLogin('tcolin') - cy.visit('/admin/logs') - cy.url().should('contain', '/admin/logs') - cy.wait('@getAllLogs', { timeout: 10_000 }).its('response').then((response) => { - logs = response?.body?.logs - logCount = response?.body?.total - }) - }) - - it('Should display logs list, loggedIn as admin', () => { - cy.getByDataTestid('logCountInfo').should('contain', `Total : ${logCount} événements`) - cy.getByDataTestid('positionInfo').should('contain', `1 - 10 sur ${logCount}`) - - cy.getByDataTestid('seePreviousPageBtn').should('be.disabled') - cy.getByDataTestid('seeFirstPageBtn').should('be.disabled') - cy.getByDataTestid('seeNextPageBtn').should('be.enabled') - cy.getByDataTestid('seeLastPageBtn').should('be.enabled') - cy.get('[data-testid$="-json"]').should('have.length', 10) - logs.slice(0, 10).forEach((log) => { - cy.getByDataTestid(`${log.id}-json`) - .should('be.visible') - }) - - cy.getByDataTestid('seeNextPageBtn').first().click() - cy.getByDataTestid('seePreviousPageBtn').should('be.enabled') - cy.getByDataTestid('seeFirstPageBtn').should('be.enabled') - cy.getByDataTestid('seeNextPageBtn').should('be.enabled') - cy.getByDataTestid('seeLastPageBtn').should('be.enabled') - cy.get('[data-testid$="-json"]').should('have.length', 10) - logs.slice(10, 10).forEach((log) => { - cy.getByDataTestid(`${log.id}-json`) - .should('be.visible') - }) - - cy.getByDataTestid('seeLastPageBtn').first().click() - cy.getByDataTestid('seePreviousPageBtn').should('be.enabled') - cy.getByDataTestid('seeFirstPageBtn').should('be.enabled') - cy.getByDataTestid('seeNextPageBtn').should('be.disabled') - cy.getByDataTestid('seeLastPageBtn').should('be.disabled') - cy.get('[data-testid$="-json"]') - .should('have.length.of.at.least', 1) - .and('have.length.at.most', 10) - logs.slice(20, logCount - 20).forEach((log) => { - cy.getByDataTestid(`${log.id}-json`) - .should('be.visible') - }) - - cy.getByDataTestid('seeFirstPageBtn').first().click() - cy.getByDataTestid('seePreviousPageBtn').should('be.disabled') - cy.getByDataTestid('seeFirstPageBtn').should('be.disabled') - cy.getByDataTestid('seeNextPageBtn').should('be.enabled') - cy.getByDataTestid('seeLastPageBtn').should('be.enabled') - cy.get('[data-testid$="-json"]').should('have.length', 10) - logs.slice(0, 10).forEach((log) => { - cy.getByDataTestid(`${log.id}-json`) - .should('be.visible') - }) - }) - - it('Should display compact logs list, loggedIn as admin', () => { - cy.get('h1') - .should('contain', ' Journaux des services associés à la chaîne DSO ') - cy.getByDataTestid('showLogsBtn') - .click() - logs.forEach((log) => { - cy.getByDataTestid(`${log.id}-json`).should('not.exist') - }) - cy.getByDataTestid('showLogsBtn').click() - logs.forEach((log) => { - cy.getByDataTestid(`${log.id}-json`).should('exist') - }) - }) -}) diff --git a/apps/client/cypress/e2e/specs/admin/projects.e2e.ts b/apps/client/cypress/e2e/specs/admin/projects.e2e.ts deleted file mode 100644 index 486319dcb..000000000 --- a/apps/client/cypress/e2e/specs/admin/projects.e2e.ts +++ /dev/null @@ -1,372 +0,0 @@ -import type { ProjectV2 } from '@cpn-console/shared' -import type { Project } from '@/utils/project-utils.js' -import { sortArrByObjKeyAsc, statusDict } from '@cpn-console/shared' -import { getModelById } from '../../support/func.js' - -describe('Administration projects', () => { - const admin = getModelById('user', 'cb8e5b4b-7b7b-40f5-935f-594f48ae6566') - let projects: ProjectV2[] - - const mapProjects = (body: Project[]) => { - return sortArrByObjKeyAsc(body, 'name') - } - - beforeEach(() => { - cy.intercept('GET', 'api/v1/projects*').as('getProjects') - - cy.kcLogin((admin.firstName.slice(0, 1) + admin.lastName).toLowerCase()) - cy.visit('/admin/projects') - cy.url().should('contain', '/admin/projects') - cy.wait('@getProjects', { timeout: 10_000 }).its('response').then((response) => { - projects = mapProjects(response?.body) - }) - }) - - it('Should display projects table, loggedIn as admin', () => { - cy.intercept('GET', 'api/v1/projects*').as('getAllProjects') - cy.wait('@getAllProjects') - cy.get('select#projectSearchFilter').select('Tous') - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.wait('@getAllProjects').its('response').then((response) => { - const projects = response.body - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody tr') - .should('have.length.at.least', 2) - projects.forEach((project: Project) => { - cy.getByDataTestid(`tr-${project.id}`) - .within(() => { - cy.get('td:nth-of-type(2)').should('contain', project.slug) - cy.get('td:nth-of-type(3)').should('contain', project.name) - cy.get('td:nth-of-type(4)').should('contain', project.owner.email) - cy.get('td:nth-of-type(5)').invoke('attr', 'title').should('contain', statusDict.status[project.status].wording) - cy.get('td:nth-of-type(5)').invoke('attr', 'title').should('contain', statusDict.locked[String(!!project.locked)].wording) - cy.get('td:nth-of-type(6)').should('contain.text', project.lastSuccessProvisionningVersion) - cy.get('td:nth-of-type(7)').should('contain.text', 'il y a') - }) - }) - }) - }) - - it('Should display handle multi-select and bulk actions, loggedIn as admin', () => { - cy.intercept('GET', 'api/v1/projects*').as('getAllProjects') - cy.wait('@getAllProjects') - - // attente que les lignes soient bien rendus - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody > tr') - .should('not.have.text', 'Chargement...') - - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody > tr') - .should('not.have.attr', 'selected') - cy.getByDataTestid('select-all-cbx') - .check() - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody > tr') - .should('have.attr', 'selected') - cy.getByDataTestid('select-all-cbx') - .check() - cy.getByDataTestid(`tr-${projects[1].id}`) - .click() - .should('not.have.attr', 'selected') - cy.getByDataTestid('select-all-cbx') - .should('not.be.checked') - cy.getByDataTestid(`tr-${projects[1].id}`) - .click() - .should('have.attr', 'selected') - cy.getByDataTestid('select-all-cbx') - .should('be.checked') - - // count must appear - cy.getByDataTestid('projectSelectedCount') - .should('contain.text', 'projets') - // filter by partial name - cy.getByDataTestid('projectsSearchInput') - .clear() - .type('li') - cy.getByDataTestid('projectsSearchBtn') - .click() - // count must equal only displayed element - cy.getByDataTestid('projectSelectedCount') - .should('contain.text', '3 projets') - // verrouillage des projets - cy.getByDataTestid('selectBulkAction') - .select('lock') - cy.getByDataTestid('validateBulkAction') - .click() - cy.getByDataTestid('snackbar').should('contain', `Traitement en cours`) - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody > tr') - .should('not.have.attr', 'selected') - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody > tr > td:nth-of-type(5)') - .invoke('attr', 'title') - .should('contain', statusDict.locked.true.wording) - // annulation de la modification - cy.getByDataTestid('select-all-cbx') - .check() - cy.getByDataTestid('projectSelectedCount') - .should('contain.text', '3 projets') - cy.getByDataTestid('selectBulkAction') - .select('unlock') - cy.getByDataTestid('validateBulkAction') - .click() - cy.getByDataTestid('snackbar').should('contain', `Traitement en cours`) - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody > tr') - .should('not.have.attr', 'selected') - cy.getByDataTestid('tableAdministrationProjects') - .get('tbody > tr > td:nth-of-type(5)') - .invoke('attr', 'title') - .should('contain', statusDict.locked.false.wording) - }) - - it('Should display filtered projects, loggedIn as admin', () => { - cy.intercept('GET', /api\/v1\/projects\?filter=all$/).as('getAllProjects') - cy.intercept('GET', /api\/v1\/projects\?filter=all&search=pr$/).as('searchInputProjects') - cy.intercept('GET', 'api/v1/projects?filter=all&statusNotIn=archived').as('getActiveProjects') - cy.intercept('GET', 'api/v1/projects?filter=all&statusIn=archived').as('getArchivedProjects') - cy.intercept('GET', 'api/v1/projects?filter=all&statusIn=failed').as('getFailedProjects') - cy.intercept('GET', 'api/v1/projects?filter=all&locked=true&statusNotIn=archived').as('getLockedProjects') - - cy.get('select#projectSearchFilter').select('Tous') - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.wait('@getAllProjects').its('response').then((response) => { - cy.checkTableBody('tableAdministrationProjects', response.body.length, 'Aucun projet trouvé') - }) - - cy.get('select#projectSearchFilter').select('Archivés') - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.wait('@getArchivedProjects').its('response').then((response) => { - cy.checkTableBody('tableAdministrationProjects', response.body.length, 'Aucun projet trouvé') - }) - - cy.get('select#projectSearchFilter').select('Non archivés') - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.wait('@getActiveProjects').its('response').then((response) => { - cy.checkTableBody('tableAdministrationProjects', response.body.length, 'Aucun projet trouvé') - }) - - cy.get('select#projectSearchFilter').select('Échoués') - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.wait('@getFailedProjects').its('response').then((response) => { - cy.checkTableBody('tableAdministrationProjects', response.body.length, 'Aucun projet trouvé') - }) - - cy.get('select#projectSearchFilter').select('Verrouillés') - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.wait('@getLockedProjects').its('response').then((response) => { - cy.checkTableBody('tableAdministrationProjects', response.body.length, 'Aucun projet trouvé') - }) - - cy.get('select#projectSearchFilter').select('Tous') - cy.getByDataTestid('projectsSearchInput') - .clear() - .type('pr') - cy.getByDataTestid('projectsSearchBtn') - .click() - cy.wait('@searchInputProjects').its('response').then((response) => { - cy.checkTableBody('tableAdministrationProjects', response.body.length, 'Aucun projet trouvé') - }) - }) - - it('Should replay hooks for a project, loggedIn as admin', () => { - const project = projects.find(p => p.name === 'candilib') - - cy.intercept('PUT', `/api/v1/projects/${project.id}/hooks`).as('replayHooks') - - cy.getByDataTestid('tableAdministrationProjects').within(() => { - cy.get('tr').contains(project.name) - .click() - }) - cy.get('.fr-callout__title') - .should('contain', project.name) - cy.getByDataTestid('replayHooksBtn') - .should('contain', 'Reprovisionner le projet') - .click() - - cy.wait('@replayHooks').its('response.statusCode').should('match', /^20\d$/) - }) - - it('Should lock and unlock a project, loggedIn as admin', () => { - const project = projects[0] - - cy.intercept('PUT', `/api/v1/projects/${project.id}`).as('handleProjectLocking') - - cy.getByDataTestid('tableAdministrationProjects').within(() => { - cy.get('tr').contains(project.name) - .click() - }) - cy.get('.fr-callout__title') - .should('contain', project.name) - cy.getByDataTestid('handleProjectLockingBtn') - .should('contain', project.locked ? 'Déverrouiller le projet' : 'Verrouiller le projet') - .click() - cy.wait('@handleProjectLocking') - .its('response.statusCode') - .should('match', /^20\d$/) - cy.getByDataTestid('handleProjectLockingBtn') - .should('contain', 'Déverrouiller le projet') - .click() - cy.wait('@handleProjectLocking') - .its('response.statusCode') - .should('match', /^20\d$/) - }) - - it('Should remove and add a user from a project, loggedIn as admin', () => { - const project = projects.find(project => project.name === 'betaapp') as ProjectV2 - const member = project.members[0] - - cy.intercept('GET', 'api/v1/projects*').as('getAllProjects') - cy.intercept('DELETE', `api/v1/projects/${project.id}/members/${member.userId}`).as('removeUser') - cy.intercept('POST', `api/v1/projects/${project.id}/members`).as('addUser') - - cy.getByDataTestid('tableAdministrationProjects').within(() => { - cy.get('tr').contains(project.name) - .click() - }) - cy.getByDataTestid('test-tab-team').click() - cy.get('.fr-callout__title') - .should('contain', project.name) - cy.get(`div[title="Quitter le projet"]`) - .click() - cy.wait('@removeUser') - .its('response.statusCode') - .should('match', /^20\d$/) - cy.get(`div[title="Quitter le projet"]`) - .should('not.exist') - cy.getByDataTestid('addUserSuggestionInput') - .find('input') - .as('inputAddUser') - cy.get('@inputAddUser') - .clear() - cy.get('@inputAddUser') - .type(member.email) - cy.getByDataTestid('addUserBtn') - .click() - cy.wait('@addUser') - .its('response.statusCode') - .should('match', /^20\d$/) - cy.get(`div[title="Quitter le projet"]`) - .should('exist') - }) - - it('Should transfert owner role to a team member, loggedIn as admin', () => { - const project = projects.find(project => project.name === 'betaapp') as ProjectV2 - const owner = project.owner - const userToTransfer = project.members[0] - - cy.intercept('GET', 'api/v1/projects*').as('getAllProjects') - cy.intercept('GET', `api/v1/projects/${project.id}/services?permissionTarget=admin`).as('getServices') - cy.intercept('GET', 'api/v1/repositories?projectId=*').as('listRepositories') - cy.intercept('GET', 'api/v1/environments?projectId=*').as('listEnvironments') - cy.intercept('PUT', `/api/v1/projects/${project.id}`).as('transferOwnership') - - cy.getByDataTestid('tableAdministrationProjects').within(() => { - cy.get('tr').contains(project.name) - .click() - }) - cy.getByDataTestid('test-tab-team').click() - - cy.wait('@getServices') - cy.wait('@listRepositories') - cy.wait('@listEnvironments') - - cy.get('.fr-callout__title') - .should('contain', project.name) - - cy.wait(500) - cy.getByDataTestid('showTransferProjectBtn') - .click() - cy.getByDataTestid('transferProjectBtn') - .should('exist') - .should('be.disabled') - cy.get('#nextOwnerSelect').select(userToTransfer.userId) - cy.getByDataTestid('transferProjectBtn') - .should('be.enabled') - .click() - cy.wait('@transferOwnership') - .its('response.statusCode') - .should('match', /^20\d$/) - - cy.getByDataTestid('tableAdministrationProjects').within(() => { - cy.get('tr').contains(project.name) - .click() - }) - cy.getByDataTestid('test-tab-team').click() - - cy.getByDataTestid('teamTable').get('tr').contains('Propriétaire') - .should('have.length', 1) - .parent() - .parent() - .should('contain', userToTransfer.email) - - cy.getByDataTestid('showTransferProjectBtn').click() - cy.getByDataTestid('transferProjectBtn') - .should('exist') - .should('be.disabled') - cy.get('#nextOwnerSelect').select(owner.id) - cy.getByDataTestid('transferProjectBtn') - .should('be.enabled') - .click() - cy.wait('@transferOwnership') - .its('response.statusCode') - .should('match', /^20\d$/) - - cy.getByDataTestid('tableAdministrationProjects').within(() => { - cy.get('tr').contains(project.name) - .click() - }) - cy.getByDataTestid('test-tab-team').click() - - cy.getByDataTestid('teamTable').get('tr').contains('Propriétaire') - .should('have.length', 1) - .parent() - .parent() - .should('contain', owner.email) - }) - - it('Should access project services, loggedIn as admin', () => { - const project = projects.find(project => project.name === 'betaapp') - - cy.intercept('GET', 'api/v1/projects*').as('getAllProjects') - - cy.getByDataTestid('tableAdministrationProjects', 15_000).within(() => { - cy.get('tr').contains(project.name) - .click() - }) - cy.getByDataTestid('test-tab-services').click() - cy.get('.fr-callout__title') - .should('contain', project.name) - cy.get('#servicesTable').should('exist') - cy.getByDataTestid('service-config-argocd') - .click() - .within(() => { - cy.get('input') - .should('have.length', 1) - }) - }) - - it('Should download projects informations, loggedIn as admin', () => { - cy.intercept('GET', 'api/v1/projects*').as('getAllProjects') - cy.get('.fr-link--download').should('not.exist') - cy.getByDataTestid('download-btn') - .click() - cy.get('.fr-link--download').should('exist') - .click() - .find('span').should(($span) => { - const text = $span.text() - expect(text).to.match(/CSV – \d* bytes/) - }) - }) -}) diff --git a/apps/client/cypress/e2e/specs/admin/system-settings.e2e.ts b/apps/client/cypress/e2e/specs/admin/system-settings.e2e.ts deleted file mode 100644 index 8a7b641f9..000000000 --- a/apps/client/cypress/e2e/specs/admin/system-settings.e2e.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type { SystemSettings } from '@cpn-console/shared' -import { getModel } from '../../support/func.js' - -describe('Administration system settings', () => { - const systemSettings = getModel('systemSetting') as SystemSettings - const contactEmail = Cypress.env('CONTACT_EMAIL') || 'cloudpinative-relations@interieur.gouv.fr' - - beforeEach(() => { - cy.intercept('GET', 'api/v1/system/settings').as('listSystemSettings') - cy.intercept('POST', 'api/v1/system/settings').as('upsertSystemSetting') - - cy.kcLogin('tcolin') - cy.visit('/admin/system-settings') - cy.url().should('contain', '/admin/system-settings') - cy.wait('@listSystemSettings', { timeout: 5_000 }).its('response').then(($response) => { - expect($response?.statusCode).to.match(/^20\d$/) - }) - }) - - it('Should turn on maintenance mode', () => { - cy.intercept('GET', 'api/v1/admin/roles').as('listRoles') - - systemSettings.forEach((setting) => { - cy.getByDataTestid(`toggle-${setting.key}`) - .find('input') - .should('be.enabled') - }) - - cy.getByDataTestid(`toggle-maintenance`) - .find('input') - .check({ force: true }) - cy.wait('@upsertSystemSetting').its('response').then(($response) => { - expect($response?.statusCode).to.match(/^20\d$/) - expect(JSON.stringify($response?.body)).to.equal(JSON.stringify({ - key: 'maintenance', - value: 'on', - })) - }) - - cy.visit('/projects') - cy.url().should('contain', '/projects') - cy.getByDataTestid('maintenance-notice') - .should('be.visible') - cy.kcLogout() - - cy.visit('/') - cy.getByDataTestid('maintenance-notice') - .should('not.exist') - - cy.kcLogin('test') - cy.getByDataTestid('maintenance-notice') - .should('not.exist') - cy.visit('/projects') - cy.wait('@listRoles') - cy.getByDataTestid('maintenance-notice') - .should('be.visible') - cy.visit('/projects') - cy.url().should('contain', '/maintenance') - cy.getByDataTestid('contact-us') - .should('have.attr', 'title', contactEmail) - }) - - it('Should turn off maintenance mode', () => { - systemSettings.forEach((setting) => { - cy.getByDataTestid(`toggle-${setting.key}`) - .find('input') - .should('be.enabled') - }) - - cy.getByDataTestid(`toggle-maintenance`) - .find('input') - .uncheck({ force: true }) - cy.wait('@upsertSystemSetting').its('response').then(($response) => { - expect($response?.statusCode).to.match(/^20\d$/) - expect(JSON.stringify($response?.body)).to.equal(JSON.stringify({ - key: 'maintenance', - value: 'off', - })) - }) - - cy.visit('/projects') - cy.getByDataTestid('maintenance-notice') - .should('not.exist') - cy.url().should('contain', '/projects') - cy.kcLogout() - - cy.kcLogin('test') - cy.getByDataTestid('maintenance-notice') - .should('not.exist') - cy.visit('/projects') - cy.url().should('contain', '/projects') - }) -}) diff --git a/apps/client/cypress/e2e/specs/admin/users.e2e.ts b/apps/client/cypress/e2e/specs/admin/users.e2e.ts deleted file mode 100644 index 015453199..000000000 --- a/apps/client/cypress/e2e/specs/admin/users.e2e.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { User } from '@cpn-console/shared' -import { getModel } from '../../support/func.js' - -const users = getModel('user') as User[] -const anonUser = users.find(user => user.email === 'anon@user') as User - -describe('Administration users', () => { - beforeEach(() => { - cy.intercept('GET', 'api/v1/users').as('getAllUsers') - - cy.kcLogin('tcolin') - cy.visit('/admin/users') - - cy.wait('@getAllUsers', { timeout: 10_000 }).its('response.statusCode').should('match', /^20\d$/) - }) - - it('Should display admin users, loggedIn as admin', () => { - users.forEach((user) => { - cy.getByDataTestid(`user-${user.id}`) - .should('contain.text', user.email) - .should('contain.text', user.lastName) - .should('contain.text', user.firstName) - .parent() - .should('contain.text', '202') // test que la date s'affiche - }) - cy.getByDataTestid('input-checkbox-tableAdministrationUsersDisplayId') - .should('exist') - .click({ force: true }) - users.forEach((user) => { - cy.getByDataTestid(`user-${user.id}`) - .should('contain.text', user.id) - }) - - cy.getByDataTestid(`user-${anonUser.id}`).should('exist') - cy.getByDataTestid('input-checkbox-tableAdministrationUsersHideBots') - .should('exist') - .click({ force: true }) - cy.getByDataTestid(`user-${anonUser.id}`).should('not.exist') - cy.getByDataTestid('input-checkbox-tableAdministrationUsersHideBots') - .should('exist') - .click({ force: true }) - - cy.getByDataTestid('tableAdministrationUsers') - .find('tbody') - .find('tr') - .should('have.length.at.least', users.length) - cy.getByDataTestid('tableAdministrationUsersSearch') - .clear() - .type(anonUser.email) - cy.getByDataTestid('tableAdministrationUsers') - .find('tbody') - .find('tr') - .should('have.length', 1) - }) -}) diff --git a/apps/client/cypress/e2e/specs/create-project.e2e.ts b/apps/client/cypress/e2e/specs/create-project.e2e.ts deleted file mode 100644 index 46354c856..000000000 --- a/apps/client/cypress/e2e/specs/create-project.e2e.ts +++ /dev/null @@ -1,49 +0,0 @@ -describe('Create Project', () => { - const project = { - name: 'project01', - slug: 'project01', - description: 'Application de prise de rendez-vous en préfécture.', - } - - beforeEach(() => { - cy.kcLogin('test') - }) - - it('Should create a project with minimal form informations', () => { - cy.intercept('POST', '/api/v1/projects').as('postProject') - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - - cy.goToProjects() - .getByDataTestid('createProjectLink').click() - .get('h1').should('contain', 'Commander un espace projet') - .get('[data-testid^="repoFieldset-"]').should('not.exist') - - cy.getByDataTestid('nameInput').type(`${project.name} ErrorSpace`) - .getByDataTestid('nameInput').should('have.class', 'fr-input--error') - .getByDataTestid('createProjectBtn').should('be.disabled') - .getByDataTestid('nameInput').clear().type(project.name) - .getByDataTestid('nameInput').should('not.have.class', 'fr-input--error') - .getByDataTestid('createProjectBtn').should('be.enabled') - .getByDataTestid('descriptionInput').clear().type(project.description) - cy.getByDataTestid('createProjectBtn').should('be.enabled').click() - - cy.wait('@postProject').its('response.statusCode').should('match', /^20\d$/) - cy.url().should('contain', `/projects/${project.slug}`) - - cy.wait('@listProjects').its('response.statusCode').should('match', /^20\d$/) - - cy.assertCreateProjects([project.slug]) - }) - - it('Should not create a project if name is already taken', () => { - cy.intercept('POST', '/api/v1/projects').as('postProject') - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - - cy.goToProjects() - .getByDataTestid('createProjectLink').click() - .getByDataTestid('nameInput').type(project.name) - cy.getByDataTestid('createProjectBtn').should('be.enabled').click() - cy.wait('@postProject').its('response.statusCode').should('match', /^20\d$/) - cy.url().should('contain', `/projects/${project.slug}-1`) - }) -}) diff --git a/apps/client/cypress/e2e/specs/home.e2e.ts b/apps/client/cypress/e2e/specs/home.e2e.ts deleted file mode 100644 index c61975105..000000000 --- a/apps/client/cypress/e2e/specs/home.e2e.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { swaggerUiPath } from '@cpn-console/shared' -import { getModelById } from '../support/func.js' - -const user = getModelById('user', 'cb8e5b4b-7b7b-40f5-935f-594f48ae6567') - -describe('Header', () => { - it('Should display application Header', () => { - cy.visit('/') - .get('.fr-header__service') - .should('contain', 'Console Cloud π Native') - .get('.fr-header__service-tagline') - .should('not.exist') - }) - - it('Should display name once logged', () => { - cy.kcLogin((user.firstName.slice(0, 1) + user.lastName).toLowerCase()) - .visit('/') - .getByDataTestid('menuUserList') - .should('contain', `${user.firstName} ${user.lastName}`) - }) - - it('Should display app version and swagger', () => { - cy.visit('/') - cy.getByDataTestid('swaggerUrl') - .should('have.attr', 'href', swaggerUiPath) - cy.getByDataTestid('appVersionUrl') - .contains('vpr-') - .invoke('attr', 'href') - .should('match', /https:\/\/github.com\/cloud-pi-native\/console\/releases\/tag\/vpr-/) - }) -}) diff --git a/apps/client/cypress/e2e/specs/not-found.e2e.ts b/apps/client/cypress/e2e/specs/not-found.e2e.ts deleted file mode 100644 index c19bdb27f..000000000 --- a/apps/client/cypress/e2e/specs/not-found.e2e.ts +++ /dev/null @@ -1,8 +0,0 @@ -describe('Redirect to 404 if page not found', () => { - it('should redirect loggedin user to 404 if page not found', () => { - cy.kcLogin('test') - cy.visit('/nowhere') - cy.get('.fr-h1') - .should('contain.text', 'Page non trouvée') - }) -}) diff --git a/apps/client/cypress/e2e/specs/redirection.e2e.ts b/apps/client/cypress/e2e/specs/redirection.e2e.ts deleted file mode 100644 index 51548170b..000000000 --- a/apps/client/cypress/e2e/specs/redirection.e2e.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { swaggerUiPath } from '@cpn-console/shared' -import { keycloakDomain } from '@/utils/env.js' -import { getModelById } from '../support/func.js' - -const project = getModelById('project', '011e7860-04d7-461f-912d-334c622d38b3') - -describe('Redirection', () => { - it('Should redirect to original page on reload', () => { - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - cy.intercept('POST', '/realms/cloud-pi-native/protocol/openid-connect/token').as('postToken') - - cy.kcLogin('test') - cy.visit('/') - cy.reload() - cy.url().should('match', /\/#state=/) - cy.goToProjects() - cy.reload() - cy.wait('@postToken') - cy.url().should('match', /projects#state=/) - cy.wait('@listProjects').its('response').then((response) => { - cy.get('[data-testid^="projectTile-"]') - cy.should('have.length', `${response?.body.length}`) - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.url().should('contain', `/projects/${project.slug}`) - }) - cy.reload() - cy.wait('@postToken') - cy.url().should('contain', `/projects/${project.slug}`) - cy.wait('@listProjects').its('response').then((_response) => { - cy.getByDataTestid('descriptionP') - cy.should('contain', project.description) - }) - }) - - it('Should redirect to login page if not logged in', () => { - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - cy.intercept('POST', '/realms/cloud-pi-native/protocol/openid-connect/token').as('postToken') - cy.intercept('GET', '/realms/cloud-pi-native/account').as('getAccount') - - cy.visit(`/projects/${project.slug}`) - cy.url().should('not.contain', `/projects/${project.slug}`) - cy.origin(`http://${keycloakDomain}`, () => { - cy.get('input#username').type('test') - .get('input#password').type('test') - .get('#kc-login').click() - }) - cy.wait('@postToken') - cy.url().should('contain', `/projects/${project.slug}`) - cy.wait('@listProjects', { timeout: 5_000 }).its('response').then((_response) => { - cy.getByDataTestid('descriptionP') - cy.should('contain', project.description) - }) - }) - - it('Should redirect to home if trying to access login page while logged', () => { - cy.intercept('POST', '/realms/cloud-pi-native/protocol/openid-connect/token').as('postToken') - cy.intercept('GET', '/realms/cloud-pi-native/account').as('getAccount') - - cy.visit('/login') - cy.url().should('not.contain', '/login') - cy.origin(`http://${keycloakDomain}`, () => { - cy.get('input#username').type('test') - .get('input#password').type('test') - .get('#kc-login').click() - }) - cy.wait('@postToken') - cy.url().should('contain', '/') - cy.get('h1').contains(' Cloud π Native ') - .should('exist') - }) - - it('Should redirect to swagger ui', () => { - cy.intercept('POST', '/realms/cloud-pi-native/protocol/openid-connect/token').as('postToken') - - cy.visit('/') - cy.get('h1').contains(' Cloud π Native ') - .should('exist') - - cy.getByDataTestid('swaggerUrl') - .should('have.attr', 'target', '_blank') - .invoke('attr', 'target', '_self') - .click() - cy.url().should('contain', swaggerUiPath) - cy.get('div.description') - .should('contain', 'API de gestion des ressources Cloud Pi Native.') - }) -}) diff --git a/apps/client/cypress/e2e/specs/roles.e2e.ts b/apps/client/cypress/e2e/specs/roles.e2e.ts deleted file mode 100644 index db110a20e..000000000 --- a/apps/client/cypress/e2e/specs/roles.e2e.ts +++ /dev/null @@ -1,172 +0,0 @@ -import type { Environment, ProjectPermsKeys, ProjectRole, ProjectV2, Repo, User } from '@cpn-console/shared' -import { getModel, getModelById } from '../support/func.js' - -const roles: ProjectRole[] = getModel('projectRole') -const user: User = getModelById('user', 'cb8e5b4b-7b7b-40f5-935f-594f48ae6569') -const repositories: Repo[] = getModel('repository') -const environments: Environment[] = getModel('environment') - -const newRole = { - name: 'elo hell', -} satisfies Partial - -const project = getModelById('project', '94c860ab-023f-4e6e-8a4e-ff41456e249b') as ProjectV2 -const projectRoles = roles.filter(role => role.projectId === project.id) -const projectRepos = repositories.filter(repo => repo.projectId === project.id) -const projectEnvs = environments.filter(env => env.projectId === project.id) -const testRole = projectRoles.find(projectRole => projectRole.id === 'c77a1b96-377d-4aa3-bc94-65d4415f9599') as ProjectRole - -function assignPerms() { - // @ts-expect-error - const perms: ProjectPermsKeys[] = this as ProjectPermsKeys[] - cy.kcLogin('test') - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.getByDataTestid('test-tab-roles').click() - cy.get('[data-testid$="-tab"]').contains(testRole.name) - .should('be.visible') - .click() - perms.forEach((key) => { - cy.getByDataTestid(`input-checkbox-${key}-cbx`).check({ force: true }) - }) - cy.getByDataTestid('saveBtn') - .should('be.enabled') - .click() -} - -describe('Project roles', () => { - beforeEach(() => { - cy.intercept('GET', '/api/v1/projects').as('listProjects') - cy.intercept('POST', '/api/v1/projects/*/roles').as('createRole') - }) - - describe('Project roles, without perms', () => { - it('Should create role without perms', () => { - cy.kcLogin('test') - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.getByDataTestid('test-tab-roles').click() - projectRoles.forEach((role) => { - cy.getByDataTestid(`${role.id}-tab`) - .should('be.visible') - }) - - cy.getByDataTestid('addRoleBtn') - .should('be.enabled') - .click() - cy.wait('@createRole') - .its('response.statusCode').should('match', /^20\d$/) - cy.getByDataTestid('snackbar').should('contain', 'Rôle ajouté') - cy.getByDataTestid('saveBtn').should('be.disabled') - cy.getByDataTestid('roleNameInput') - .should('have.value', 'Nouveau rôle') - .clear() - .type(newRole.name) - cy.getByDataTestid('saveBtn') - .should('be.enabled') - .click() - cy.getByDataTestid('test-members').click() - cy.getByDataTestid(`input-checkbox-${user.id}-cbx`).check({ force: true }) - }) - - it('Should not grant perms', () => { - cy.kcLogin((user.firstName.slice(0, 1) + user.lastName).toLowerCase()) - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - - cy.getByDataTestid('test-tab-team').click() - cy.getByDataTestid('teamTable').get('th').contains('Retirer du projet').should('be.visible') - cy.getByDataTestid('addUserSuggestionInput').should('not.exist') - cy.getByDataTestid('showTransferProjectBtn').should('not.exist') - - cy.getByDataTestid('replayHooksBtn').should('not.exist') - cy.getByDataTestid('showSecretsBtn').should('not.exist') - - cy.getByDataTestid('test-tab-roles').should('exist') - }) - }) - - describe('Project roles, with view perms', () => { - const intermediatePermsOptions: ProjectPermsKeys[] = ['LIST_ENVIRONMENTS', 'LIST_REPOSITORIES'] - - it('Should assign view perms', assignPerms.bind(intermediatePermsOptions)) - - it('Should grant view perms', () => { - cy.kcLogin((user.firstName.slice(0, 1) + user.lastName).toLowerCase()) - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - - cy.getByDataTestid('noReposTr').should('not.exist') - - cy.getByDataTestid('addRepoLink').should('not.exist') - cy.getByDataTestid(`repoTr-${projectRepos[0].internalRepoName}`).click() - cy.getByDataTestid('syncRepoBtn').should('not.exist') - cy.getByDataTestid('updateRepoBtn').should('not.exist') - cy.getByDataTestid('showDeleteRepoBtn').should('not.exist') - cy.get('.fr-modal__header > button.fr-btn--close').click() - - cy.getByDataTestid('noEnvsTr').should('not.exist') - cy.getByDataTestid('addEnvironmentLink').should('not.exist') - cy.getByDataTestid(`environmentTr-${projectEnvs[0].name}`).click() - cy.getByDataTestid('putEnvironmentBtn').should('not.exist') - cy.getByDataTestid('showDeleteEnvironmentBtn').should('not.exist') - cy.get('.fr-modal__header > button.fr-btn--close').click() - - cy.getByDataTestid('test-tab-team').click() - cy.getByDataTestid('teamTable').get('th').contains('Retirer du projet').should('be.visible') - cy.getByDataTestid('addUserSuggestionInput').should('not.exist') - cy.getByDataTestid('showTransferProjectBtn').should('not.exist') - - cy.getByDataTestid('replayHooksBtn').should('not.exist') - cy.getByDataTestid('showSecretsBtn').should('not.exist') - - cy.getByDataTestid('test-tab-roles').should('exist').click() - cy.getByDataTestid('insuficientPermsRoles').should('be.visible') - }) - }) - - describe('Project roles, with full access perms', () => { - const fullPermsOptions: ProjectPermsKeys[][] = [ - ['MANAGE_ENVIRONMENTS', 'MANAGE_MEMBERS', 'MANAGE_REPOSITORIES', 'MANAGE_ROLES', 'REPLAY_HOOKS', 'SEE_SECRETS'], - ['MANAGE'], - ] - - fullPermsOptions.forEach((perms, idx) => { - it(`Should assign full access perms (${idx + 1})`, assignPerms.bind(perms)) - - it(`Should grant full access perms (${idx + 1})`, () => { - cy.kcLogin((user.firstName.slice(0, 1) + user.lastName).toLowerCase()) - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - - cy.getByDataTestid('noEnvsTr').should('not.exist') - cy.getByDataTestid('noReposTr').should('not.exist') - cy.getByDataTestid('addRepoLink').should('be.enabled') - cy.getByDataTestid(`repoTr-${projectRepos[0].internalRepoName}`).click() - cy.getByDataTestid('syncRepoBtn').should('be.enabled') - cy.getByDataTestid('updateRepoBtn').should('be.enabled') - cy.getByDataTestid('showDeleteRepoBtn').should('be.enabled') - cy.get('.fr-modal__header > button.fr-btn--close').click() - - cy.getByDataTestid('addEnvironmentLink').should('be.enabled') - cy.getByDataTestid(`environmentTr-${projectEnvs[0].name}`).click() - cy.getByDataTestid('putEnvironmentBtn').should('be.enabled') - cy.getByDataTestid('showDeleteEnvironmentBtn').should('be.enabled') - cy.get('.fr-modal__header > button.fr-btn--close').click() - - cy.getByDataTestid('test-tab-team').click() - cy.getByDataTestid('teamTable').get('th').contains('Retirer du projet').should('be.visible') - cy.getByDataTestid('addUserSuggestionInput').should('be.visible') - cy.getByDataTestid('showTransferProjectBtn').should('not.exist') - - cy.getByDataTestid('replayHooksBtn').should('be.enabled') - cy.getByDataTestid('showSecretsBtn').should('be.enabled') - - cy.getByDataTestid('test-tab-roles').should('be.visible').click() - projectRoles.forEach((role) => { - cy.getByDataTestid(`${role.id}-tab`).should('be.visible') - }) - }) - }) - }) -}) diff --git a/apps/client/cypress/e2e/specs/services-health.e2e.ts b/apps/client/cypress/e2e/specs/services-health.e2e.ts deleted file mode 100644 index 3da8f4085..000000000 --- a/apps/client/cypress/e2e/specs/services-health.e2e.ts +++ /dev/null @@ -1,26 +0,0 @@ -describe('Services health', () => { - it('Should display services health, loggedIn', () => { - cy.intercept('GET', '/api/v1/services').as('getServices') - - cy.kcLogin('test') - - cy.visit('/') - .getByDataTestid('menuServicesHealth').click() - .url().should('contain', '/services-health') - .get('h1').should('contain', 'Status des services de la plateforme DSO') - cy.getByDataTestid('box-info').children().should('have.length', 7) - }) - - it('Should display services health, not loggedIn', () => { - cy.intercept('GET', '/api/v1/services').as('getServices') - - cy.visit('/') - cy.get('a.fr-btn').should('contain', 'Se connecter') - cy.getByDataTestid('menuServicesHealth') - .should('be.visible') - .click() - cy.url().should('contain', '/services-health') - cy.get('h1').should('contain', 'Status des services de la plateforme DSO') - cy.getByDataTestid('box-info').children().should('have.length', 7) - }) -}) diff --git a/apps/client/cypress/e2e/specs/services.e2e.ts b/apps/client/cypress/e2e/specs/services.e2e.ts deleted file mode 100644 index af2ef2fc2..000000000 --- a/apps/client/cypress/e2e/specs/services.e2e.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { getModelById } from '../support/func.js' - -const project = getModelById('project', '011e7860-04d7-461f-912d-334c622d38b3') - -describe('Services view', () => { - beforeEach(() => { - cy.kcLogin('test') - }) - - it('Should display tiles and url services according to selected project', () => { - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.getByDataTestid('test-tab-services').click() - cy.getByDataTestid('service-config-argocd') - .click() - .within(() => { - cy.get('input') - .should('have.length', 1) - }) - }) -}) diff --git a/apps/client/cypress/e2e/specs/sidemenu.e2e.ts b/apps/client/cypress/e2e/specs/sidemenu.e2e.ts deleted file mode 100644 index 5898d4e58..000000000 --- a/apps/client/cypress/e2e/specs/sidemenu.e2e.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { getModelById } from '../support/func.js' - -const project = getModelById('project', '011e7860-04d7-461f-912d-334c622d38b3') - -describe('Sidemenu', () => { - it('Should display Sidemenu, not loggedIn', () => { - cy.visit('/') - .getByDataTestid('mainMenu').should('be.visible') - .getByDataTestid('menuProjectBtn').should('not.exist') - .getByDataTestid('menuDoc').should('be.visible') - .getByDataTestid('menuAdministrationList').should('not.exist') - .getByDataTestid('menuAdministrationBtn').should('not.exist') - }) - it('Should display Sidemenu, loggedIn, isNotAdmin', () => { - cy.kcLogin('test') - - cy.visit('/') - .getByDataTestid('mainMenu').should('be.visible') - .getByDataTestid('menuMyProjects').click() - .url().should('contain', '/projects') - .getByDataTestid(`projectTile-${project.slug}`).click() - .url().should('contain', `/projects/${project.slug}`) - }) - - it('Should display Sidemenu, loggedIn, isAdmin', () => { - cy.kcLogin('tcolin') - - cy.visit('/') - .getByDataTestid('mainMenu').should('be.visible') - .getByDataTestid('menuAdministrationList').should('not.be.visible') - - // Projects - .getByDataTestid('menuMyProjects').click() - .getByDataTestid('menuAdministrationList').should('not.be.visible') - .url().should('contain', '/projects') - .getByDataTestid(`projectTile-${project.slug}`).click() - .getByDataTestid('menuAdministrationList').should('not.be.visible') - .url().should('contain', `/projects/${project.slug}`) - - // Doc - .getByDataTestid('menuDoc').should('be.visible') - .getByDataTestid('menuAdministrationList').should('not.be.visible') - - // Admin - .getByDataTestid('menuAdministrationBtn').click() - .getByDataTestid('menuAdministrationList').should('be.visible') - .getByDataTestid('menuAdministrationUsers').click() - .getByDataTestid('menuAdministrationUsers').should('have.class', 'router-link-active') - .getByDataTestid('menuAdministrationList').should('be.visible') - .url().should('contain', '/admin/users') - }) -}) diff --git a/apps/client/cypress/e2e/specs/team.e2e.ts b/apps/client/cypress/e2e/specs/team.e2e.ts deleted file mode 100644 index 018f2ac79..000000000 --- a/apps/client/cypress/e2e/specs/team.e2e.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { getModelById } from '../support/func.js' - -const project = getModelById('project', '22e7044f-8414-435d-9c4a-2df42a65034b') -const newMember = getModelById('user', 'cb8e5b4b-7b7b-40f5-935f-594f48ae6567') - -describe('Team view', () => { - beforeEach(() => { - cy.kcLogin('test') - }) - - it('Should display team members', () => { - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - .getByDataTestid('test-tab-team').click() - .getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.members.length + 1) - }) - - it('Should not add a non-existing team member', () => { - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - .getByDataTestid('test-tab-team').click() - .getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.members.length + 1) - - cy.getByDataTestid('addUserSuggestionInput') - .find('input') - .clear() - .type('jenexistepas@criseexistentielle.com') - cy.getByDataTestid('addUserBtn') - .should('be.enabled').click() - - cy.getByDataTestid('snackbar').should('contain', 'Utilisateur introuvable') - - cy.getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.members.length + 1) - }) - - it('Should add a team member', () => { - cy.intercept('POST', `api/v1/projects/${project.id}/members`).as('addUser') - - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.getByDataTestid('test-tab-team').click() - cy.getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.members.length + 1) - - cy.getByDataTestid('addUserSuggestionInput') - .find('input') - .clear() - .type('test@test.com') - cy.getByDataTestid('userErrorInfo') - .should('contain', 'L\'utilisateur associé à cette adresse e-mail fait déjà partie du projet.') - cy.getByDataTestid('addUserBtn') - .should('be.disabled') - cy.getByDataTestid('addUserSuggestionInput') - .find('input') - .clear() - - cy.getByDataTestid('addUserSuggestionInput') - .find('input') - .clear() - .type(newMember.email) - cy.getByDataTestid('userErrorInfo') - .should('not.exist') - cy.getByDataTestid('addUserBtn') - .should('be.enabled').click() - cy.wait('@addUser') - .its('response.statusCode') - .should('match', /^20\d$/) - - cy.getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.members.length + 1 + 1) - }) - - it('Should transfert owner role to a team member', () => { - const owner = getModelById('user', 'cb8e5b4b-7b7b-40f5-935f-594f48ae6565') - const userToTransfer = getModelById('user', 'cb8e5b4b-7b7b-40f5-935f-594f48ae6566') - - cy.intercept('PUT', `/api/v1/projects/${project.id}`).as('transferOwnership') - cy.intercept('GET', `/api/v1/projects?filter=member&statusNotIn=archived`).as('getProjectMembers') - - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.getByDataTestid('test-tab-team').click() - - cy.getByDataTestid('showTransferProjectBtn') - .should('be.enabled') - cy.getByDataTestid('transferProjectBtn') - .should('not.exist') - - cy.getByDataTestid('teamTable').get('tr').contains('Propriétaire').should('have.length', 1) - cy.getByDataTestid('showTransferProjectBtn').click() - cy.getByDataTestid('transferProjectBtn') - .should('exist') - .should('be.disabled') - cy.get('#nextOwnerSelect').select(userToTransfer.id) - cy.getByDataTestid('transferProjectBtn') - .should('be.enabled') - .click() - cy.wait('@transferOwnership') - .its('response.statusCode') - .should('match', /^20\d$/) - cy.wait('@getProjectMembers') - .its('response.statusCode') - .should('match', /^20\d$/) - - cy.getByDataTestid('teamTable').get('tr').contains('Propriétaire').should('have.length', 1) - cy.getByDataTestid('showTransferProjectBtn') - .should('not.exist') - cy.getByDataTestid('transferProjectBtn') - .should('not.exist') - - cy.kcLogin((userToTransfer.firstName.slice(0, 1) + userToTransfer.lastName).toLowerCase()) - - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.getByDataTestid('test-tab-team').click() - - cy.getByDataTestid('showTransferProjectBtn').click() - cy.getByDataTestid('transferProjectBtn') - .should('exist') - .should('be.disabled') - cy.get('#nextOwnerSelect').select(owner.id) - cy.getByDataTestid('transferProjectBtn') - .should('be.enabled') - .click() - cy.wait('@transferOwnership') - .its('response.statusCode') - .should('match', /^20\d$/) - cy.wait('@getProjectMembers') - .its('response.statusCode') - .should('match', /^20\d$/) - - cy.getByDataTestid('teamTable').get('tr').contains('Propriétaire').should('have.length', 1) - cy.getByDataTestid('showTransferProjectBtn') - .should('not.exist') - cy.getByDataTestid('transferProjectBtn') - .should('not.exist') - }) - - it('Should remove a team member', () => { - cy.intercept('DELETE', `api/v1/projects/${project.id}/members/*`).as('removeUser') - - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.getByDataTestid('test-tab-team').click() - cy.getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.members.length + 1 + 1) - .get(`div[title="Retirer ${newMember.email} du projet"]`) - .click() - cy.wait('@removeUser') - .its('response.statusCode') - .should('match', /^20\d$/) - - cy.getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.members.length + 1) - }) -}) diff --git a/apps/client/cypress/e2e/support/commands.ts b/apps/client/cypress/e2e/support/commands.ts deleted file mode 100644 index 57d9ecdb0..000000000 --- a/apps/client/cypress/e2e/support/commands.ts +++ /dev/null @@ -1,466 +0,0 @@ -import { deleteValidationInput } from '@cpn-console/shared' -import { keycloakDomain } from '@/utils/env.js' -import { getModelById } from './func.js' - -const defaultOwner = getModelById('user', 'cb8e5b4b-7b7b-40f5-935f-594f48ae6565') - -Cypress.Commands.add('kcLogout', () => { - cy.get('a.fr-btn').should('contain', 'Se déconnecter').click() -}) - -Cypress.Commands.add('kcLogin', (name, password = 'test') => { - cy.session(name, () => { - cy.visit('/') - .get('a.fr-btn').should('contain', 'Se connecter').click() - cy.origin(`http://${keycloakDomain}`, { args: { name, password } }, ({ name, password }) => { - cy.get('input#username').type(name) - .get('input#password').type(password) - .get('#kc-login').click() - }) - cy.url().should('contain', `${Cypress.env('clientHost')}`) - }, { - validate() { - cy.visit('/') - .get('a.fr-btn').should('contain', 'Se déconnecter') - }, - }) -}) - -Cypress.Commands.add('goToProjects', () => { - cy.intercept('GET', 'api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - - cy.get('body').then(($body) => { - // Vérifie si un élément est présent - if ($body.find('a').length === 0) { - // Si l'élément n'est pas trouvé, on considère qu'on est dans les limbes - cy.visit('/') - } - }) - cy.getByDataTestid('menuMyProjects').click() - cy.url({ timeout: 10_000 }).should('contain', '/projects') -}) - -Cypress.Commands.add('createProject', (project, ownerEmail = defaultOwner.email) => { - cy.intercept('POST', '/api/v1/projects').as('postProject') - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - - const newProject = { - name: 'cloud-pi-native', - ...project, - } - - cy.goToProjects() - .getByDataTestid('createProjectLink').click() - .get('h1').should('contain', 'Commander un espace projet') - .get('[data-testid^="repoFieldset-"]').should('not.exist') - cy.getByDataTestid('ownerInfo').should('contain', ownerEmail) - .getByDataTestid('nameInput').clear().type(newProject.name) - .getByDataTestid('nameInput').should('not.have.class', 'fr-input--error') - cy.getByDataTestid('createProjectBtn').should('be.enabled').click() - - cy.wait('@postProject').its('response.statusCode').should('eq', 201) - cy.wait('@listProjects').its('response.statusCode').should('eq', 200) -}) - -Cypress.Commands.add('assertCreateProjects', (slugs) => { - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - cy.goToProjects() - .url().should('match', /\/projects$/) - .wait('@listProjects').its('response.statusCode').should('eq', 200) - slugs.forEach(slug => cy.getByDataTestid(`projectTile-${slug}`).should('exist')) -}) - -Cypress.Commands.add('archiveProject', (project) => { - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - cy.intercept('GET', '/api/v1/stages').as('getAllStages') - - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - - cy.url().should('contain', project.slug) - cy.wait('@getAllStages') - .getByDataTestid('archiveProjectInput').should('not.exist') - .getByDataTestid('showArchiveProjectBtn') - .should('be.visible') - .click() - cy.getByDataTestid('confirmDeletionBtn') - .should('be.disabled') - cy.getByDataTestid('archiveProjectInput').should('be.visible') - .type(deleteValidationInput) - cy.getByDataTestid('confirmDeletionBtn') - .should('be.enabled') - .click() - - cy.url().should('match', /\/projects$/) - cy.wait('@listProjects').its('response.statusCode').should('eq', 200) - cy.getByDataTestid(`projectTile-${project.slug}`) - .should('not.exist') -}) - -Cypress.Commands.add('addRepos', (project, repos) => { - cy.intercept('POST', '/api/v1/repositories').as('postRepo') - cy.intercept('GET', `/api/v1/repositories?projectId=${project.id}`).as('listRepos') - - const newRepo = repo => ({ - internalRepoName: 'console', - externalUserName: 'this-is+tobi', - externalRepoUrl: 'https://github.com/cloud-pi-native/console.git', - isInfra: false, - isPrivate: false, - externalToken: 'private-token', - ...repo, - }) - - const newRepos = repos.map(newRepo) - - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - - newRepos.forEach((repo) => { - cy.getByDataTestid('addRepoLink').click() - .get('h2').should('contain', 'Ajouter un dépôt au projet') - .getByDataTestid('internalRepoNameInput').type(repo.internalRepoName) - .getByDataTestid('externalRepoUrlInput').clear().type(repo.externalRepoUrl) - - if (repo.isPrivate) { - cy.getByDataTestid('input-checkbox-privateRepoCbx').check({ force: true }) - if (repo.externalUserName) { - cy.getByDataTestid('externalUserNameInput').type(repo.externalUserName) - } - if (repo.externalToken) { - cy.getByDataTestid('externalTokenInput').clear().type(repo.externalToken) - } - } - - if (repo.isInfra) { - cy.getByDataTestid('input-checkbox-infraRepoCbx').check({ force: true }) - } - - cy.getByDataTestid('addRepoBtn').click() - cy.wait('@postRepo').its('response.statusCode').should('eq', 201) - cy.wait('@listRepos').its('response.statusCode').should('eq', 200) - cy.getByDataTestid(`repoTr-${repo.internalRepoName}`).should('exist') - }) -}) - -Cypress.Commands.add('assertAddRepo', (project, repos) => { - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - .getByDataTestid('test-tab-resources').click() - - repos.forEach((repo) => { - cy.getByDataTestid(`repoTr-${repo.internalRepoName}`).should('exist') - }) -}) - -Cypress.Commands.add('deleteRepo', (project, repo) => { - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - - cy.getByDataTestid(`repoTr-${repo.internalRepoName}`).click() - .getByDataTestid('repo-form').should('exist') - .getByDataTestid('deleteRepoInput').should('not.exist') - .getByDataTestid('deleteRepoZone') - .scrollIntoView() - .should('be.visible') - .getByDataTestid('showDeleteRepoBtn').click() - .getByDataTestid('deleteRepoBtn') - .should('be.disabled') - .getByDataTestid('deleteRepoInput').should('be.visible') - .type(deleteValidationInput) - .getByDataTestid('deleteRepoBtn') - .should('be.enabled') - .click() - .getByDataTestid('repo-form').should('not.exist') - .reload() - .getByDataTestid(`repoTr-${repo.internalRepoName}`) - .should('not.exist') -}) - -Cypress.Commands.add('addEnvironment', (project, environments) => { - cy.intercept('GET', 'api/v1/stages').as('listStages') - cy.intercept('GET', `api/v1/environments?projectId=${project.id}`).as('listEnvironments') - cy.intercept('GET', 'api/v1/quotas').as('listQuotas') - cy.intercept('GET', 'api/v1/clusters').as('getClusters') - cy.intercept('POST', '/api/v1/environments').as('postEnvironment') - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - - cy.goToProjects() - .getByDataTestid(`projectTile-${project?.slug}`) - .click() - cy.getByDataTestid('test-tab-resources') - .click() - cy.wait('@getClusters') - - environments.forEach((environment) => { - cy.getByDataTestid('addEnvironmentLink').click() - cy.wait('@listStages') - cy.wait('@listQuotas') - cy.get('h1').should('contain', 'Ajouter un environnement au projet') - cy.getByDataTestid('environmentNameInput') - .type(environment?.name) - cy.get('#zone-select') - .select('a66c4230-eba6-41f1-aae5-bb1e4f90cce2') - cy.get('#stage-select') - .select(environment?.stage?.id) - cy.get('#quota-select') - .select(environment?.quota?.id) - cy.get('#cluster-select') - .select(environment?.cluster?.id) - - cy.getByDataTestid('addEnvironmentBtn').click() - cy.wait('@postEnvironment').its('response.statusCode').should('eq', 201) - cy.wait('@listEnvironments').its('response.statusCode').should('eq', 200) - cy.getByDataTestid(`environmentTr-${environment?.name}`).should('exist') - }) -}) - -Cypress.Commands.add('assertAddEnvironment', (project, environments, isDeepCheck = true) => { - cy.intercept('GET', '/api/v1/environments?projectId=*').as('listEnvironments') - cy.intercept('GET', 'api/v1/clusters').as('getClusters') - cy.intercept('GET', 'api/v1/stages').as('listStages') - cy.intercept('GET', 'api/v1/quotas').as('listQuotas') - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`) - .click() - cy.getByDataTestid('test-tab-resources') - .click() - cy.wait('@listEnvironments') - cy.wait('@getClusters') - - environments.forEach((environment) => { - cy.getByDataTestid(`environmentTr-${environment.name}`) - .should('exist') - if (isDeepCheck) { - cy.getByDataTestid(`environmentTr-${environment.name}`) - .click() - cy.wait('@listStages') - cy.wait('@listQuotas') - cy.getByDataTestid('environmentNameInput') - .should('have.value', environment?.name) - cy.get('#zone-select') - .should('have.value', 'a66c4230-eba6-41f1-aae5-bb1e4f90cce2') - cy.get('#stage-select') - .should('have.value', environment?.stage?.id) - cy.get('#quota-select') - .should('have.value', environment?.quota?.id) - cy.get('#cluster-select') - .should('have.value', environment?.cluster?.id) - cy.getByDataTestid('cancelEnvironmentBtn') - .click() - cy.getByDataTestid('resource-modal') - .should('not.exist') - } - }) -}) - -Cypress.Commands.add('deleteEnvironment', (project, environmentName) => { - cy.intercept('GET', '/api/v1/environments?projectId=*').as('listEnvironments') - cy.intercept('GET', 'api/v1/clusters').as('getClusters') - cy.intercept('DELETE', '/api/v1/environments/*').as('deleteEnvironment') - cy.intercept('GET', '/api/v1/projects?filter=member&statusNotIn=archived').as('listProjects') - - cy.goToProjects() - cy.getByDataTestid(`projectTile-${project.slug}`).click() - cy.wait('@listEnvironments') - cy.wait('@getClusters') - cy.getByDataTestid(`environmentTr-${environmentName}`) - .click() - cy.getByDataTestid('showDeleteEnvironmentBtn').click() - cy.getByDataTestid('deleteEnvironmentInput').should('be.visible') - cy.getByDataTestid('deleteEnvironmentInput') - .type(environmentName.slice(0, 2)) - cy.getByDataTestid('deleteEnvironmentBtn').should('be.disabled') - cy.getByDataTestid('deleteEnvironmentInput').clear() - .type(deleteValidationInput) - cy.getByDataTestid('deleteEnvironmentBtn').should('be.enabled') - .click() - cy.wait('@deleteEnvironment').its('response.statusCode').should('eq', 204) - cy.wait('@listProjects').its('response.statusCode').should('eq', 200) - cy.getByDataTestid(`environmentTr-${environmentName}`).should('not.exist') -}) - -Cypress.Commands.add('addProjectMember', (project, userEmail) => { - cy.intercept('POST', /\/api\/v1\/projects\/[\w-]{36}\/users$/).as('postUser') - - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - .getByDataTestid('menuTeam').click() - .url().should('match', /\/team$/) - .getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.users.length) - .getByDataTestid('addUserSuggestionInput') - .find('input') - .clear() - .type(userEmail) - .getByDataTestid('userErrorInfo') - .should('not.exist') - .getByDataTestid('addUserBtn') - .should('be.enabled').click() - .wait('@postUser') - .its('response.statusCode').should('eq', 201) - .getByDataTestid('teamTable') - .find('tbody > tr') - .should('have.length', project.users.length + 1) -}) - -Cypress.Commands.add('assertUsers', (project, emails) => { - cy.goToProjects() - .getByDataTestid(`projectTile-${project.slug}`).click() - .getByDataTestid('test-tab-team').click() - - emails.forEach((email) => { - cy.getByDataTestid('teamTable').within(() => { - cy.get('td') - .contains(email) - .should('exist') - }) - }) -}) - -Cypress.Commands.add('generateGitLabCI', (ciForms) => { - let version - ciForms.forEach((ciForm) => { - if (ciForm.language === 'java') version = `BUILD_IMAGE_NAME: maven:3.8-openjdk-${ciForm.version}` - if (ciForm.language === 'node') version = `BUILD_IMAGE_NAME: node:${ciForm.version}` - if (ciForm.language === 'python') version = `BUILD_IMAGE_NAME: maven:3.8-openjdk-${ciForm.version}` - - cy.get('select#type-language-select') - .select(`${ciForm.language}`) - - if (ciForm.language === 'node') { - cy.getByDataTestid('nodeVersionInput').clear().type(`${ciForm.version}`) - .getByDataTestid('nodeInstallInput').clear().type(`${ciForm.install}`) - .getByDataTestid('nodeBuildInput').clear().type(`${ciForm.build}`) - } - if (ciForm.language === 'java') { - cy.getByDataTestid('javaVersionInput').clear().type(`${ciForm.version}`) - .getByDataTestid('artefactDirInput').clear().type(`${ciForm.artefactDir}`) - } - cy.getByDataTestid('workingDirInput').clear().type(`${ciForm.workingDir}`) - .getByDataTestid('generateCIBtn').click() - .getByDataTestid('generatedCI').should('be.visible') - .getByDataTestid('zip-download-link').should('contain', 'Télécharger tous les fichiers') - .getByDataTestid(`copy-${ciForm.language}-ContentBtn`).should('exist') - .getByDataTestid('copy-vault-ContentBtn').should('exist') - .getByDataTestid('copy-docker-ContentBtn').should('exist') - .getByDataTestid('copy-rules-ContentBtn').should('exist') - .getByDataTestid('copy-gitlab-ci-dso-ContentBtn').click() - cy.assertClipboard(version) - cy.get('.fr-link--download').first().click() - .find('span').should(($span) => { - const text = $span.text() - expect(text).to.match(/zip – \d* bytes/) - }) - cy.get('.fr-link--download').last().click() - .find('span').should(($span) => { - const text = $span.text() - expect(text).to.match(/YAML – \d* bytes/) - }) - }) -}) - -Cypress.Commands.add('assertClipboard', (value) => { - cy.window().then((win) => { - win.navigator.clipboard.readText().then((text) => { - expect(text).to.contain(value) - }) - }) -}) - -Cypress.Commands.add('getServicesResponse', () => { - cy.wait('@getServices').its('response').then((response) => { - const services = response.body - services.map(service => - cy.getByDataTestid(`${service.name}-info`).should('contain', `${service.code} - ${service.message}`), - ) - if (services.some(service => service.code >= 400)) { - cy.getByDataTestid('services-health-badge').should('contain', 'Un ou plusieurs services dysfonctionnent') - } else { - cy.getByDataTestid('services-health-badge').should('contain', 'Tous les services fonctionnent') - } - }) -}) - -Cypress.Commands.add('getByDataTestid', (dataTestid, timeout = 4_000) => { - cy.get(`[data-testid="${dataTestid}"]`, { timeout }) -}) - -Cypress.Commands.add('selectProject', (element) => { - cy.getByDataTestid('projectSelector') - ?.find('select') - ?.select(element) -}) - -Cypress.Commands.add('deleteIndexedDB', () => { - Cypress.on('window:before:load', (win) => { - win.indexedDB.deleteDatabase('localforage') - }) -}) - -Cypress.on('uncaught:exception', (_err, _runnable) => false) - -// Commande pour accéder / interagir avec le store dans les tests -Cypress.Commands.add('getStore', () => cy.window().its('app.$store')) - -// A utiliser sur les éléments détâchés du DOM (lors de rerendu assez lourds dans le DOM) -// https://github.com/cypress-io/cypress/issues/7306#issuecomment-850621378 -// Recursively gets an element, returning only after it's determined to be attached to the DOM for good -Cypress.Commands.add('getSettled', (selector, opts = {}) => { - const retries = opts.retries || 3 - const delay = opts.delay || 100 - - const isAttached = (resolve, count = 0) => { - const el = Cypress.$(selector) - - // Is element attached to the DOM? - count = Cypress.dom.isAttached(el) ? count + 1 : 0 - - // Hit our base case, return the element - if (count >= retries) { - return resolve(el) - } - - // Retry after a bit of a delay - setTimeout(isAttached, delay, resolve, count) - } - - // Wrap, so we can chain cypress commands off the result - return cy.wrap(null).then(() => { - return new Cypress.Promise((resolve) => { - return isAttached(resolve, 0) - }).then((el) => { - return cy.wrap(el) - }) - }) -}) - -Cypress.Commands.add('goToAdminListUsers', () => { - cy.get('body').then(($body) => { - if ($body.find('a').length === 0) { - // Si l'élément n'est pas trouvé, on considère qu'on est dans les limbes - cy.visit('/admin/users') - } - }) - try { - cy.getByDataTestid('menuAdministrationUsers', 100).click() - cy.url().should('contain', '/admin/users') - } catch { - cy.getByDataTestid('menuAdministrationBtn').click() - .getByDataTestid('menuAdministrationUsers').click() - cy.url().should('contain', '/admin/users') - } -}) - -Cypress.Commands.add('checkTableBody', (tableDataTestId: string, rowLength: number, noResultText?: string) => { - if (rowLength) { - cy.getByDataTestid(tableDataTestId) - .get('tbody > tr') - .should('not.have.text', noResultText) - .should('have.length', rowLength) - } else { - cy.get('tr:last-child>td:first-child') - .should('have.text', noResultText) - } -}) diff --git a/apps/client/cypress/e2e/support/func.ts b/apps/client/cypress/e2e/support/func.ts deleted file mode 100644 index 1269d9cf2..000000000 --- a/apps/client/cypress/e2e/support/func.ts +++ /dev/null @@ -1,37 +0,0 @@ -import type { ProjectV2 } from '@cpn-console/shared' -import { data } from '@cpn-console/test-utils' - -export const getModel = (model: keyof typeof data) => data[model] -export const getProjectById = (id: string) => getProjects().find((project: ProjectV2) => project.id === id) - -export function getModelById(model: string, id: string) { - return model === 'project' - ? getProjectById(id) - : data[model]?.find(key => key.id === id) -} - -export function getProjects(): ProjectV2[] { - return getModel('project') - .map(project => ({ - ...project, - repositories: getModel('repository') - ?.filter(repository => repository.projectId === project.id), - environments: getModel('environment') - ?.filter(environment => environment.projectId === project.id) - ?.map(environment => ({ - ...environment, - permissions: getModel('permission')?.filter(permission => permission.environmentId === environment.id), - })), - members: getModel('projectMembers') - ?.filter(member => member.projectId === project.id) - ?.map(member => ({ - roleIds: member.roleIds, - ...getModelById('user', member.userId), - })), - })) satisfies ProjectV2[] -} - -export function getProjectMembers(userId: string) { - return getProjects() - ?.filter(project => project.status !== 'archived' && project.members?.find(member => member.id === userId)) -} diff --git a/apps/client/cypress/e2e/support/index.ts b/apps/client/cypress/e2e/support/index.ts deleted file mode 100644 index ad27b743a..000000000 --- a/apps/client/cypress/e2e/support/index.ts +++ /dev/null @@ -1,273 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -/* eslint-disable ts/method-signature-style */ - -import type { CiForm, Project, Repository } from '../../types.js' -import './commands.js' - -Cypress.on('window:before:load', (win) => { - let copyText: string - if (!win.navigator.clipboard) { - // @ts-ignore - win.navigator.clipboard = {} - } - Object.setPrototypeOf(win.navigator.clipboard, { - writeText: async (text: string) => (copyText = text), - readText: async () => copyText, - }) -}) - -declare global { - // eslint-disable-next-line ts/no-namespace - namespace Cypress { - interface Chainable { - /** - * Custom command to logout from application - * @example cy.kcLogout() - */ - kcLogout(): Chainable> - - /** - * Custom command to login to application with a given user - * @param name - * @param password - * @example cy.kcLogin('test', 'test') - */ - kcLogin( - name: string, - password?: string, - ): Chainable> - - /** - * Custom command to visit the projects page - * @example cy.goToProjects() - */ - goToProjects(): Chainable> - - /** - * Custom command to create a new project - * @param project - * @example cy.createProject({ name: 'projectName' }) - */ - createProject( - project: Project - ): Chainable> - - /** - * Custom command to assert projects creation - * @param names - * @example cy.assertCreateProjects(['project1', 'project2']) - */ - assertCreateProjects( - names: string[] - ): Chainable> - - /** - * Custom command to archive a project - * @param project - * @example cy.archiveProject({ name: 'projectName' }) - */ - archiveProject( - project: Project - ): Chainable> - - /** - * Custom command to add repositories into a project - * @param project - * @param repos - * @example cy.addRepos({ name: 'projectName' }, [{ internalRepoName: 'repo1' }, { internalRepoName: 'repo2' }]) - */ - addRepos( - project: Project, - repos: Repository[] - ): Chainable> - - /** - * Custom command to assert repos creation - * @param project - * @param repos - * @example cy.assertAddRepo({ name: 'projectName' }, [{ internalRepoName: 'repo1' }, { internalRepoName: 'repo2' }]) - */ - assertAddRepo( - project: Project, - repos: Repository[] - ): Chainable> - - /** - * Custom command to delete a repo - * @param project - * @param repo - * @example cy.deleteRepo({ name: 'projectName' }, { internalRepoName: 'repo1' }) - */ - deleteRepo( - project: Project, - repo: Repository - ): Chainable> - - /** - * Custom command to create environments - * @param project - * @param environments - * @example cy.addEnvironment({ name: 'projectName' }, ['preprod', 'prod']) - */ - addEnvironment( - project: Project, - environments: any[] - ): Chainable> - - /** - * Custom command to assert environments creation - * @param project - * @param environments - * @example cy.assertAddEnvironment({ name: 'projectName' }, ['preprod', 'prod']) - */ - assertAddEnvironment( - project: Project, - environments: any[], - isDeepCheck?: boolean, - ): Chainable> - - /** - * Custom command to delete an environment - * @param project - * @param environment - * @example cy.deleteEnvironment({ name: 'projectName' }, 'prod') - */ - deleteEnvironment( - project: Project, - environment: string - ): Chainable> - - /** - * Custom command to assert permission creations - * @param project - * @param environment - * @param permissions - * @example cy.assertPermission({ name: 'projectName' }, 'prod', [{ email: 'test1@test.com', isOwner: true }, { email: 'test2@test.com', isOwner: false }]) - */ - assertPermission( - project: Project, - environment: string, - permissions: { - email: string - isOwner: boolean - }[] - ): Chainable> - - /** - * Custom command to add a member to a project - * @param project - * @param userEmail - * @example cy.addProjectMember({ name: 'projectName' }, 'test@test.com') - */ - addProjectMember( - project: Project & { - users: Record[] - }, - userEmail: string, - ): Chainable> - - /** - * Custom command to assert members creation into a project - * @param project - * @param emails - * @example cy.assertUsers({ name: 'projectName' }, ['test1@test.com', 'test2@test.com']) - */ - assertUsers( - project: Project, - emails: string[] - ): Chainable> - - /** - * Custom command to assert members creation into a project - * @param ciForms - * @example cy.generateGitLabCI([{ language: 'node', version: '20.0.0', install: 'npm install', build: 'npm run build',workingDir: './' }]) - */ - generateGitLabCI( - ciForms: CiForm[] - ): Chainable> - - /** - * Custom command to assert clipboard value - * @param value - * @example cy.assertClipboard('test') - */ - assertClipboard( - value: string - ): Chainable> - - /** - * Custom command to assert services health - * @example cy.getServicesResponse() - */ - getServicesResponse(): Chainable> - - /** - * Custom command to get an html element by its 'data-testid' - * @param dataTestid - * @param timeout - * @example cy.getByDataTestid('testBtn') - */ - getByDataTestid( - dataTestid: string, - timeout?: number - ): Chainable> - - /** - * Custom command to select a project from the selector - * @param element - * @example cy.selectProject('project1') - */ - selectProject( - element: string - ): Chainable> - - /** - * Custom command to delete window indexedDB 'localForage' - * @example cy.deleteIndexedDB() - */ - deleteIndexedDB(): Chainable> - - /** - * Custom command to access pinia store - * @example cy.getStore() - */ - getStore(): Chainable> - - /** - * Custom command to get an html element by its 'data-testid' with a retry system for flaky tests - * @param selector - * @param opt - * @param opt.delay - * @param opt.retries - * @example cy.getSettled('testBtn') - */ - getSettled( - selector: string, - opt?: { - delay?: number - retries?: number - } - ): void - - /** - * Custom command to visit admin user list page - * @example cy.goToAdminListUsers() - */ - goToAdminListUsers(): Chainable> - } - } -} diff --git a/apps/client/cypress/tsconfig.json b/apps/client/cypress/tsconfig.json deleted file mode 100644 index a2dc2006a..000000000 --- a/apps/client/cypress/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": { - "baseUrl": "./", - "paths": { - "@/*": ["../src/*"] - }, - "types": ["cypress", "node"], - "noEmit": true - }, - "include": [ - "./**/*.ts" - ], - "exclude": [] -} diff --git a/apps/client/cypress/types.ts b/apps/client/cypress/types.ts deleted file mode 100644 index 83274933e..000000000 --- a/apps/client/cypress/types.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Project as ProjectType, Repo } from '@cpn-console/shared' - -export type Project = Partial> - -export type Repository = Partial - -export interface CiForm { - language: string - version: string - install?: string - build?: string - artefactDir?: string - workingDir: string -} diff --git a/apps/client/package.json b/apps/client/package.json index 3ef79cf5e..85e6dd694 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -12,7 +12,6 @@ "build": "run-s icons type-check build-only", "build-only": "vite --mode=production build", "build:clean": "rimraf ./dist ./tsconfig.tsbuildinfo", - "cypress:install": "cypress install", "dev": "vite --mode=development", "format": "NODE_OPTIONS='--no-warnings=ExperimentalWarning' eslint ./ --fix", "format:style": "stylelint ./src/**/*.{css,vue} --fix", @@ -24,10 +23,6 @@ "preview": "vite preview --port 8080", "test": "vitest run", "test:cov": "vitest run --coverage", - "test:ct": "NODE_ENV=test cypress open --component --browser=firefox", - "test:ct-ci": "NODE_ENV=test cypress run --component --browser=firefox", - "test:e2e": "cypress open --browser=firefox", - "test:e2e-ci": "cypress run --browser=firefox", "type-check": "vue-tsc --noEmit -p tsconfig.json" }, "dependencies": { @@ -53,11 +48,6 @@ "vue3-json-viewer": "^2.4.1", "xbytes": "^1.9.1" }, - "optionalDependencies": { - "@cypress/vue": "6.0.2", - "cypress": "15.6.0", - "cypress-vite": "1.8.0" - }, "devDependencies": { "@cpn-console/eslint-config": "workspace:^", "@cpn-console/test-utils": "workspace:^", @@ -70,7 +60,6 @@ "@vitejs/plugin-vue": "^6.0.4", "@vitest/coverage-v8": "^2.1.9", "@vue/eslint-config-typescript": "^14.7.0", - "eslint-plugin-cypress": "^4.3.0", "eslint-plugin-vue": "^10.8.0", "jsdom": "^25.0.1", "npm-run-all": "^4.1.5", diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts index 07bc1c148..7875604c5 100644 --- a/apps/client/vite.config.ts +++ b/apps/client/vite.config.ts @@ -138,9 +138,6 @@ export default defineConfig({ target: 'ESNext', }, optimizeDeps: { - entries: [ - './cypress/components/specs/environment-form.ct.ts', - ], include: [ 'jszip', ], diff --git a/ci/scripts/run-tests.sh b/ci/scripts/run-tests.sh index a2de05ee8..cf18c018f 100755 --- a/ci/scripts/run-tests.sh +++ b/ci/scripts/run-tests.sh @@ -20,7 +20,6 @@ DOCKER_BUILDX_VERSION="$(docker buildx version)" # Default RUN_LINT="false" RUN_UNIT_TESTS="false" -RUN_COMPONENT_TESTS="false" RUN_E2E_TESTS="false" RUN_STATUS_CHECK="false" @@ -28,10 +27,6 @@ RUN_STATUS_CHECK="false" TEXT_HELPER="\nThis script aims to run application tests. Following flags are available: - -b (Optional) Browser used for e2e components and tests - - -c Run component tests - -e Run e2e tests -l Run lint @@ -49,13 +44,9 @@ print_help() { } # Parse options -while getopts hb:ceklst:u flag +while getopts heklst:u flag do case "${flag}" in - b) - BROWSER=${OPTARG};; - c) - RUN_COMPONENT_TESTS=true;; e) RUN_E2E_TESTS=true;; l) @@ -74,7 +65,7 @@ done # Script condition -if [ "$RUN_LINT" == "false" ] && [ "$RUN_UNIT_TESTS" == "false" ] && [ "$RUN_E2E_TESTS" == "false" ] && [ "$RUN_COMPONENT_TESTS" == "false" ] && [ "$RUN_STATUS_CHECK" == "false" ]; then +if [ "$RUN_LINT" == "false" ] && [ "$RUN_UNIT_TESTS" == "false" ] && [ "$RUN_E2E_TESTS" == "false" ] && [ "$RUN_STATUS_CHECK" == "false" ]; then printf "\nArgument(s) missing, you don't specify any kind of test to run.\n" print_help exit 1 @@ -108,7 +99,6 @@ printf "\nScript settings: -> docker version: ${DOCKER_VERSION} -> docker buildx version: ${DOCKER_BUILDX_VERSION} -> run unit tests: ${RUN_UNIT_TESTS} - -> run component tests: ${RUN_COMPONENT_TESTS} -> run e2e tests: ${RUN_E2E_TESTS} -> run deploy status check: ${RUN_STATUS_CHECK}\n" @@ -126,18 +116,6 @@ if [ "$RUN_UNIT_TESTS" == "true" ]; then npm run test:cov fi -# Run component tests -if [ "$RUN_COMPONENT_TESTS" == "true" ]; then - checkDockerRunning - - printf "\n${red}${i}.${no_color} Launch component tests\n" - i=$(($i + 1)) - - [[ -n "$BROWSER" ]] && BROWSER_ARGS="-- --browser $BROWSER" - - npm run test:ct-ci $BROWSER_ARGS -fi - # Run e2e tests if [ "$RUN_E2E_TESTS" == "true" ]; then checkDockerRunning @@ -145,8 +123,6 @@ if [ "$RUN_E2E_TESTS" == "true" ]; then printf "\n${red}${i}.${no_color} Launch e2e tests\n" i=$(($i + 1)) - [[ -n "$BROWSER" ]] && BROWSER_ARGS="-- --browser $BROWSER" - npm --prefix $PROJECT_DIR/packages/shared run build npm --prefix $PROJECT_DIR/packages/test-utils run build @@ -157,7 +133,7 @@ if [ "$RUN_E2E_TESTS" == "true" ]; then docker pull ghcr.io/cloud-pi-native/console/nginx-strangler:$TAG && docker tag ghcr.io/cloud-pi-native/console/client:$TAG dso-console/nginx-strangler:ci fi - npm run docker:e2e-ci $BROWSER_ARGS + npm run docker:e2e-ci printf "\n${red}${i}.${no_color} Remove resources\n" i=$(($i + 1)) diff --git a/package.json b/package.json index 8f1f30219..15f95cea1 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "docker:dev:build": "export COMPOSE_FILE=./docker/docker-compose.dev.yml && ./scripts/run-build.sh $COMPOSE_FILE", "docker:dev:clean": "docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans", "docker:dev:delete": "docker compose -f ./docker/docker-compose.dev.yml down -v --remove-orphans", - "docker:e2e": "docker compose -f ./docker/docker-compose.dev.yml up ${TAG:+--no-build} -d --remove-orphans; pnpm --filter=@cpn-console/client run test:e2e; docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans", - "docker:e2e-ci": "docker compose -f ./docker/docker-compose.ci.yml up ${TAG:+--no-build} -d --remove-orphans; pnpm --filter=@cpn-console/client run test:e2e-ci", + "docker:e2e": "docker compose -f ./docker/docker-compose.dev.yml up ${TAG:+--no-build} -d --remove-orphans; pnpm playwright:test; docker compose -f ./docker/docker-compose.dev.yml down --remove-orphans", + "docker:e2e-ci": "docker compose -f ./docker/docker-compose.ci.yml up ${TAG:+--no-build} -d --remove-orphans; pnpm playwright:test", "docker:e2e-ci:delete": "docker compose -f ./docker/docker-compose.ci.yml down -v --remove-orphans", "docker:integ": "docker compose --env-file apps/server/.env.integ -f ./docker/docker-compose.integ.yml up -d; docker compose --env-file apps/server/.env.integ -f ./docker/docker-compose.integ.yml watch --no-up & docker compose --env-file apps/server/.env.integ -f ./docker/docker-compose.integ.yml logs server client -f", "docker:integ:build": "export $(cat apps/server/.env.integ | grep -v '#' | xargs) && export COMPOSE_FILE=./docker/docker-compose.integ.yml && cd $(dirname $COMPOSE_FILE) && docker buildx bake --allow=fs.read=.. --file $(basename $COMPOSE_FILE) --load && cd - > /dev/null", @@ -51,8 +51,6 @@ "prepare": "husky", "test": "pnpm -r run test", "test:cov": "pnpm -r run test:cov", - "test:ct": "pnpm --filter @cpn-console/shared run build && pnpm --filter @cpn-console/test-utils run build && pnpm --filter @cpn-console/client run test:ct", - "test:ct-ci": "pnpm -r run test:ct-ci", "test:e2e": "pnpm kube:e2e", "test:e2e-ci": "pnpm kube:prod; pnpm kube:e2e-ci" }, @@ -73,7 +71,6 @@ "onlyBuiltDependencies": [ "@prisma/client", "@prisma/engines", - "cypress", "esbuild", "prisma", "vue-demi" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d9d215a96..cc15cc5df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,9 +135,6 @@ importers: '@vue/eslint-config-typescript': specifier: ^14.7.0 version: 14.7.0(eslint-plugin-vue@10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.0.3(jiti@2.6.1)))(@typescript-eslint/parser@8.57.0(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.3(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.0.3(jiti@2.6.1))))(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) - eslint-plugin-cypress: - specifier: ^4.3.0 - version: 4.3.0(eslint@10.0.3(jiti@2.6.1)) eslint-plugin-vue: specifier: ^10.8.0 version: 10.8.0(@stylistic/eslint-plugin@5.10.0(eslint@10.0.3(jiti@2.6.1)))(@typescript-eslint/parser@8.57.0(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.3(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@10.0.3(jiti@2.6.1))) @@ -195,16 +192,6 @@ importers: workbox-window: specifier: ^7.4.0 version: 7.4.0 - optionalDependencies: - '@cypress/vue': - specifier: 6.0.2 - version: 6.0.2(cypress@15.6.0)(vue@3.5.30(typescript@5.9.3)) - cypress: - specifier: 15.6.0 - version: 15.6.0 - cypress-vite: - specifier: 1.8.0 - version: 1.8.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2)) apps/server: dependencies: @@ -1944,24 +1931,6 @@ packages: peerDependencies: postcss-selector-parser: ^7.1.1 - '@cypress/request@3.0.10': - resolution: {integrity: sha512-hauBrOdvu08vOsagkZ/Aju5XuiZx6ldsLfByg1htFeldhex+PeMrYauANzFsMJeAA0+dyPLbDoX2OYuvVoLDkQ==} - engines: {node: '>= 6'} - - '@cypress/vue@6.0.2': - resolution: {integrity: sha512-To+Ik4CnhTPMmDh7VGpl5k0Z1LuE0xrI0j6LF7QyjROY2bkQwUE50WTmVPCz/Dvez9WrVpkJjRmflR5KlVmGiQ==} - engines: {node: '>=18'} - peerDependencies: - '@cypress/webpack-dev-server': '*' - cypress: '>=7.0.0' - vue: '>=3.0.0' - peerDependenciesMeta: - '@cypress/webpack-dev-server': - optional: true - - '@cypress/xvfb@1.2.4': - resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} - '@e18e/eslint-plugin@0.2.0': resolution: {integrity: sha512-mXgODVwhuDjTJ+UT+XSvmMmCidtGKfrV5nMIv1UtpWex2pYLsIM3RSpT8HWIMAebS9qANbXPKlSX4BE7ZvuCgA==} peerDependencies: @@ -3925,12 +3894,6 @@ packages: '@types/serve-static@2.2.0': resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - '@types/sinonjs__fake-timers@8.1.1': - resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} - - '@types/sizzle@2.3.10': - resolution: {integrity: sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==} - '@types/statuses@2.0.6': resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} @@ -3946,9 +3909,6 @@ packages: '@types/tedious@4.0.14': resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} - '@types/tmp@0.2.6': - resolution: {integrity: sha512-chhaNf2oKHlRkDGt+tiKE2Z5aJ6qalm7Z9rlLdBwmOiAAf09YQvvoLXjWK4HWPF1xU/fqvMgfNfpVoBscA/tKA==} - '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -3958,9 +3918,6 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - '@typescript-eslint/eslint-plugin@8.57.0': resolution: {integrity: sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4324,10 +4281,6 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - ajv-draft-04@1.0.0: resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -4388,10 +4341,6 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - ansi-escapes@7.3.0: resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} engines: {node: '>=18'} @@ -4430,9 +4379,6 @@ packages: append-field@1.0.0: resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} - arch@2.2.0: - resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} - are-docs-informative@0.0.2: resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} engines: {node: '>=14'} @@ -4463,13 +4409,6 @@ packages: asn1.js@5.4.1: resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} - asn1@0.2.6: - resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} - - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -4503,12 +4442,6 @@ packages: avvio@8.4.0: resolution: {integrity: sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==} - aws-sign2@0.7.0: - resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} - - aws4@1.13.2: - resolution: {integrity: sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==} - axios-retry@4.5.0: resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==} peerDependencies: @@ -4547,9 +4480,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - bcrypt-pbkdf@1.0.2: - resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} - bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} @@ -4560,12 +4490,6 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - blob-util@2.0.2: - resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} - - bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} - bn.js@4.12.3: resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} @@ -4598,9 +4522,6 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} @@ -4649,10 +4570,6 @@ packages: cacheable@2.3.3: resolution: {integrity: sha512-iffYMX4zxKp54evOH27fm92hs+DeC1DhXmNVN8Tr94M/iZIV42dqTHSR2Ik4TOSPyOAwKr7Yu3rN9ALoLkbWyQ==} - cachedir@2.4.0: - resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} - engines: {node: '>=6'} - call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -4679,9 +4596,6 @@ packages: caniuse-lite@1.0.30001777: resolution: {integrity: sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==} - caseless@0.12.0: - resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} - ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -4750,10 +4664,6 @@ packages: resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==} engines: {node: '>=4'} - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -4766,18 +4676,10 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-table3@0.6.1: - resolution: {integrity: sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==} - engines: {node: 10.* || >= 12.*} - cli-table3@0.6.5: resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} engines: {node: 10.* || >= 12.*} - cli-truncate@2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} - cli-truncate@5.2.0: resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} engines: {node: '>=20'} @@ -4820,10 +4722,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - colors@1.4.0: - resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} - engines: {node: '>=0.1.90'} - combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -4839,10 +4737,6 @@ packages: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - commander@6.2.1: - resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} - engines: {node: '>= 6'} - comment-json@4.4.1: resolution: {integrity: sha512-r1To31BQD5060QdkC+Iheai7gHwoSZobzunqkf2/kQ6xIAfJyrKNAFUwdKvkK7Qgu7pVTKQEa7ok7Ed3ycAJgg==} engines: {node: '>= 6'} @@ -4924,9 +4818,6 @@ packages: core-js-compat@3.48.0: resolution: {integrity: sha512-OM4cAF3D6VtH/WkLtWvyNC56EZVXsZdU3iqaMG2B4WvYrlqU831pc4UtG5yp0sE9z8Y02wVN7PjW5Zf9Gt0f1Q==} - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -4998,24 +4889,10 @@ packages: csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - cypress-vite@1.8.0: - resolution: {integrity: sha512-rPkIpDzCIo+upsDkFa/NlrnzVumuQ45UcwL7a2k/n8WFIwsW8QYuQaWU2JiIKExP/LNQew3H3Hbs/bp26xC0Fw==} - peerDependencies: - vite: ^2.9.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - cypress@15.6.0: - resolution: {integrity: sha512-Vqo66GG1vpxZ7H1oDX9umfmzA3nF7Wy80QAc3VjwPREO5zTY4d1xfQFNPpOWleQl9vpdmR2z1liliOcYlRX6rQ==} - engines: {node: ^20.1.0 || ^22.0.0 || >=24.0.0} - hasBin: true - dargs@8.1.0: resolution: {integrity: sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw==} engines: {node: '>=12'} - dashdash@1.14.1: - resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} - engines: {node: '>=0.10'} - data-uri-to-buffer@4.0.1: resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} engines: {node: '>= 12'} @@ -5048,14 +4925,6 @@ packages: de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -5190,9 +5059,6 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ecc-jsbn@0.1.2: - resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} - ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} @@ -5237,10 +5103,6 @@ packages: resolution: {integrity: sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==} engines: {node: '>=10.13.0'} - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -5372,11 +5234,6 @@ packages: '@typescript-eslint/utils': '*' eslint: '*' - eslint-plugin-cypress@4.3.0: - resolution: {integrity: sha512-CgS/S940MJlT8jtnWGKI0LvZQBGb/BB0QCpgBOxFMM/Z6znD+PZUwBhCTwHKN2GEr5AOny3xB92an0QfzBGooQ==} - peerDependencies: - eslint: '>=9' - eslint-plugin-depend@1.5.0: resolution: {integrity: sha512-i3UeLYmclf1Icp35+6W7CR4Bp2PIpDgBuf/mpmXK5UeLkZlvYJ21VuQKKHHAIBKRTPivPGX/gZl5JGno1o9Y0A==} peerDependencies: @@ -5574,9 +5431,6 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - eventemitter2@6.4.7: - resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} - eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -5584,14 +5438,6 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - execa@4.1.0: - resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} - engines: {node: '>=10'} - - executable@4.1.1: - resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} - engines: {node: '>=4'} - expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} @@ -5606,15 +5452,6 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - - extsprintf@1.3.0: - resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} - engines: {'0': node >=0.6.0} - fast-check@3.23.2: resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} engines: {node: '>=8.0.0'} @@ -5692,9 +5529,6 @@ packages: fault@2.0.1: resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -5708,10 +5542,6 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} - figures@3.2.0: - resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} - engines: {node: '>=8'} - file-entry-cache@11.1.2: resolution: {integrity: sha512-N2WFfK12gmrK1c1GXOqiAJ1tc5YE+R53zvQ+t5P8S5XhnmKYVB5eZEiLNZKDSmoG8wqqbF9EXYBBW/nef19log==} @@ -5782,9 +5612,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - forever-agent@0.6.1: - resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} - fork-ts-checker-webpack-plugin@9.1.0: resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} engines: {node: '>=14.21.3'} @@ -5888,10 +5715,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -5899,9 +5722,6 @@ packages: get-tsconfig@4.13.6: resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} - getpass@0.1.7: - resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} - giget@2.0.0: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true @@ -5949,10 +5769,6 @@ packages: resolution: {integrity: sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==} engines: {node: '>=18'} - global-dirs@3.0.1: - resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} - engines: {node: '>=10'} - global-modules@2.0.0: resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} engines: {node: '>=6'} @@ -6055,10 +5871,6 @@ packages: hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - hasha@5.2.2: - resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} - engines: {node: '>=8'} - hashery@1.5.0: resolution: {integrity: sha512-nhQ6ExaOIqti2FDWoEMWARUqIKyjr2VcZzXShrI+A3zpeiuPWzx6iPftt44LhP74E5sW36B75N6VHbvRtpvO6Q==} engines: {node: '>=20'} @@ -6119,10 +5931,6 @@ packages: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} - http-signature@1.4.0: - resolution: {integrity: sha512-G5akfn7eKbpDN+8nPS/cb57YeA1jLTVxjpCj7tmm3QKPdyDy7T+qSC40e9ptydSWvkwjSXw1VbkpyEm39ukeAg==} - engines: {node: '>=0.10'} - http2-client@1.3.5: resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==} @@ -6130,10 +5938,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - human-signals@1.1.1: - resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} - engines: {node: '>=8.12.0'} - husky@9.1.7: resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} engines: {node: '>=18'} @@ -6185,10 +5989,6 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - indent-string@5.0.0: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} @@ -6199,10 +5999,6 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - ini@2.0.0: - resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} - engines: {node: '>=10'} - ini@4.1.1: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -6299,10 +6095,6 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - is-installed-globally@0.4.0: - resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} - engines: {node: '>=10'} - is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} @@ -6337,10 +6129,6 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - is-path-inside@4.0.0: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} @@ -6395,9 +6183,6 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} - is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -6427,9 +6212,6 @@ packages: resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} engines: {node: '>=18'} - isstream@0.1.2: - resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} - istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -6491,9 +6273,6 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - jsbn@0.1.1: - resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} - jsdoc-type-pratt-parser@7.1.1: resolution: {integrity: sha512-/2uqY7x6bsrpi3i9LVU6J89352C0rpMk0as8trXxCtvd4kPk1ke/Eyif6wqfSLvoNJqcDG9Vk4UsXgygzCt2xA==} engines: {node: '>=20.0.0'} @@ -6547,9 +6326,6 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -6569,10 +6345,6 @@ packages: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} - jsprim@2.0.2: - resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} - engines: {'0': node >=0.6.0} - jszip@3.10.1: resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} @@ -6620,15 +6392,6 @@ packages: engines: {node: '>=20.17'} hasBin: true - listr2@3.14.0: - resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} - engines: {node: '>=10.0.0'} - peerDependencies: - enquirer: '>= 2.3.0 < 3' - peerDependenciesMeta: - enquirer: - optional: true - listr2@9.0.5: resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} engines: {node: '>=20.0.0'} @@ -6672,9 +6435,6 @@ packages: lodash.mergewith@4.6.2: resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} - lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - lodash.snakecase@4.1.1: resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} @@ -6697,10 +6457,6 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} - log-update@4.0.0: - resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} - engines: {node: '>=10'} - log-update@6.1.0: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} @@ -7137,10 +6893,6 @@ packages: engines: {node: '>= 4'} hasBin: true - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -7232,9 +6984,6 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} - ospath@1.2.2: - resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} - outvariant@1.4.3: resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} @@ -7263,10 +7012,6 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -7355,18 +7100,12 @@ packages: resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} engines: {node: '>= 14.16'} - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} perfect-debounce@2.1.0: resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} - performance-now@2.1.0: - resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} - pg-int8@1.0.1: resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} engines: {node: '>=4.0.0'} @@ -7402,10 +7141,6 @@ packages: engines: {node: '>=0.10'} hasBin: true - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - pify@3.0.0: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} @@ -7544,10 +7279,6 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} - process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} - protobufjs@7.5.4: resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} engines: {node: '>=12.0.0'} @@ -7560,9 +7291,6 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} - proxy-from-env@1.0.0: - resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} - proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -7583,10 +7311,6 @@ packages: resolution: {integrity: sha512-tsSGN1x3h569ZSU1u6diwhltLyfUWDp3YbFHedapTmpBl0B3P6U3+Qptg7xu+v+1io1EwhdPyyRHYbEw0KN2FA==} engines: {node: '>=20'} - qs@6.14.2: - resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} - engines: {node: '>=0.6'} - qs@6.15.0: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} @@ -7713,9 +7437,6 @@ packages: resolution: {integrity: sha512-85THTg1RgOYtqQw42JON6AqvHLptlj1biw265Tsq4fD4cPdUvhDB2Qh9NTv17yCD322ROuO9aOmpc4GyayGVBA==} engines: {node: '>=8.0.0'} - request-progress@3.0.0: - resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -7995,10 +7716,6 @@ packages: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} - slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} - slice-ansi@4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} @@ -8069,11 +7786,6 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - sshpk@1.18.0: - resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} - engines: {node: '>=0.10.0'} - hasBin: true - stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -8168,10 +7880,6 @@ packages: resolution: {integrity: sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==} engines: {node: '>=10'} - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - strip-indent@4.1.1: resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} engines: {node: '>=12'} @@ -8280,12 +7988,6 @@ packages: resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} engines: {node: ^14.18.0 || >=16.0.0} - systeminformation@5.27.7: - resolution: {integrity: sha512-saaqOoVEEFaux4v0K8Q7caiauRwjXC4XbD2eH60dxHXbpKxQ8kH9Rf7Jh+nryKpOUSEFxtCdBlSUx0/lO6rwRg==} - engines: {node: '>=8.0.0'} - os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] - hasBin: true - tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} @@ -8344,12 +8046,6 @@ packages: resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} engines: {node: '>=20'} - throttleit@1.0.1: - resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==} - - through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - tiny-emitter@2.1.0: resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} @@ -8393,10 +8089,6 @@ packages: resolution: {integrity: sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w==} hasBin: true - tmp@0.2.5: - resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} - engines: {node: '>=14.14'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -8447,10 +8139,6 @@ packages: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - ts-algebra@2.0.0: resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} @@ -8513,12 +8201,6 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - - tweetnacl@0.14.5: - resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} - type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -8527,14 +8209,6 @@ packages: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - - type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - type-fest@5.4.4: resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} engines: {node: '>=20'} @@ -8730,10 +8404,6 @@ packages: until-async@3.0.2: resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} - untildify@4.0.0: - resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} - engines: {node: '>=8'} - upath@1.2.0: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} @@ -8772,10 +8442,6 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} - verror@1.10.0: - resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} - engines: {'0': node >=0.6.0} - vite-node@2.1.9: resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -9180,9 +8846,6 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -9397,7 +9060,7 @@ snapshots: '@babel/types': 7.29.0 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -9449,7 +9112,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-plugin-utils': 7.28.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) lodash.debounce: 4.0.8 resolve: 1.22.11 transitivePeerDependencies: @@ -10021,7 +9684,7 @@ snapshots: '@babel/parser': 7.29.0 '@babel/template': 7.28.6 '@babel/types': 7.29.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color @@ -10348,42 +10011,6 @@ snapshots: dependencies: postcss-selector-parser: 7.1.1 - '@cypress/request@3.0.10': - dependencies: - aws-sign2: 0.7.0 - aws4: 1.13.2 - caseless: 0.12.0 - combined-stream: 1.0.8 - extend: 3.0.2 - forever-agent: 0.6.1 - form-data: 4.0.5 - http-signature: 1.4.0 - is-typedarray: 1.0.0 - isstream: 0.1.2 - json-stringify-safe: 5.0.1 - mime-types: 2.1.35 - performance-now: 2.1.0 - qs: 6.14.2 - safe-buffer: 5.2.1 - tough-cookie: 5.1.2 - tunnel-agent: 0.6.0 - uuid: 8.3.2 - optional: true - - '@cypress/vue@6.0.2(cypress@15.6.0)(vue@3.5.30(typescript@5.9.3))': - dependencies: - cypress: 15.6.0 - vue: 3.5.30(typescript@5.9.3) - optional: true - - '@cypress/xvfb@1.2.4(supports-color@8.1.1)': - dependencies: - debug: 3.2.7(supports-color@8.1.1) - lodash.once: 4.1.1 - transitivePeerDependencies: - - supports-color - optional: true - '@e18e/eslint-plugin@0.2.0(eslint@10.0.3(jiti@2.6.1))': dependencies: eslint-plugin-depend: 1.5.0(eslint@10.0.3(jiti@2.6.1)) @@ -10590,7 +10217,7 @@ snapshots: '@eslint/config-array@0.21.2': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -10598,7 +10225,7 @@ snapshots: '@eslint/config-array@0.23.3': dependencies: '@eslint/object-schema': 3.0.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) minimatch: 10.2.4 transitivePeerDependencies: - supports-color @@ -10622,7 +10249,7 @@ snapshots: '@eslint/eslintrc@3.3.5': dependencies: ajv: 6.14.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 @@ -12306,7 +11933,7 @@ snapshots: '@tokenizer/inflate@0.4.1': dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) token-types: 6.1.2 transitivePeerDependencies: - supports-color @@ -12504,12 +12131,6 @@ snapshots: '@types/http-errors': 2.0.5 '@types/node': 22.19.15 - '@types/sinonjs__fake-timers@8.1.1': - optional: true - - '@types/sizzle@2.3.10': - optional: true - '@types/statuses@2.0.6': optional: true @@ -12531,20 +12152,12 @@ snapshots: dependencies: '@types/node': 24.12.0 - '@types/tmp@0.2.6': - optional: true - '@types/tough-cookie@4.0.5': {} '@types/trusted-types@2.0.7': {} '@types/unist@3.0.3': {} - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 24.12.0 - optional: true - '@typescript-eslint/eslint-plugin@8.57.0(@typescript-eslint/parser@8.57.0(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3))(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -12583,7 +12196,7 @@ snapshots: '@typescript-eslint/types': 8.57.0 '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.57.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 10.0.3(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -12595,7 +12208,7 @@ snapshots: '@typescript-eslint/types': 8.57.0 '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.57.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 9.39.4(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: @@ -12605,7 +12218,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) '@typescript-eslint/types': 8.57.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -12638,7 +12251,7 @@ snapshots: '@typescript-eslint/types': 8.57.0 '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) '@typescript-eslint/utils': 8.57.0(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 10.0.3(jiti@2.6.1) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 @@ -12650,7 +12263,7 @@ snapshots: '@typescript-eslint/types': 8.57.0 '@typescript-eslint/typescript-estree': 8.57.0(typescript@5.9.3) '@typescript-eslint/utils': 8.57.0(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 9.39.4(jiti@2.6.1) ts-api-utils: 2.4.0(typescript@5.9.3) typescript: 5.9.3 @@ -12665,7 +12278,7 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.57.0(typescript@5.9.3) '@typescript-eslint/types': 8.57.0 '@typescript-eslint/visitor-keys': 8.57.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) minimatch: 10.2.4 semver: 7.7.4 tinyglobby: 0.2.15 @@ -12853,7 +12466,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -12871,7 +12484,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -12889,7 +12502,7 @@ snapshots: dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 0.2.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 5.0.6 @@ -13184,12 +12797,6 @@ snapshots: agent-base@7.1.4: {} - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - optional: true - ajv-draft-04@1.0.0(ajv@8.18.0): optionalDependencies: ajv: 8.18.0 @@ -13252,11 +12859,6 @@ snapshots: ansi-colors@4.1.3: {} - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - optional: true - ansi-escapes@7.3.0: dependencies: environment: 1.1.0 @@ -13286,9 +12888,6 @@ snapshots: append-field@1.0.0: {} - arch@2.2.0: - optional: true - are-docs-informative@0.0.2: {} arg@4.1.3: {} @@ -13323,14 +12922,6 @@ snapshots: minimalistic-assert: 1.0.1 safer-buffer: 2.1.2 - asn1@0.2.6: - dependencies: - safer-buffer: 2.1.2 - optional: true - - assert-plus@1.0.0: - optional: true - assertion-error@2.0.1: {} astral-regex@2.0.0: {} @@ -13354,12 +12945,6 @@ snapshots: '@fastify/error': 3.4.1 fastq: 1.20.1 - aws-sign2@0.7.0: - optional: true - - aws4@1.13.2: - optional: true - axios-retry@4.5.0(axios@1.13.6): dependencies: axios: 1.13.6 @@ -13405,11 +12990,6 @@ snapshots: baseline-browser-mapping@2.10.0: {} - bcrypt-pbkdf@1.0.2: - dependencies: - tweetnacl: 0.14.5 - optional: true - bignumber.js@9.3.1: {} binary-extensions@2.3.0: {} @@ -13420,19 +13000,13 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 - blob-util@2.0.2: - optional: true - - bluebird@3.7.2: - optional: true - bn.js@4.12.3: {} body-parser@2.2.2: dependencies: bytes: 3.1.2 content-type: 1.0.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 @@ -13472,9 +13046,6 @@ snapshots: node-releases: 2.0.36 update-browserslist-db: 1.2.3(browserslist@4.28.1) - buffer-crc32@0.2.13: - optional: true - buffer-equal-constant-time@1.0.1: optional: true @@ -13539,9 +13110,6 @@ snapshots: keyv: 5.6.0 qified: 0.6.0 - cachedir@2.4.0: - optional: true - call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -13567,9 +13135,6 @@ snapshots: caniuse-lite@1.0.30001777: {} - caseless@0.12.0: - optional: true - ccount@2.0.1: {} chai@5.3.3: @@ -13643,9 +13208,6 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 - clean-stack@2.2.0: - optional: true - cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 @@ -13656,25 +13218,12 @@ snapshots: cli-spinners@2.9.2: {} - cli-table3@0.6.1: - dependencies: - string-width: 4.2.3 - optionalDependencies: - colors: 1.4.0 - optional: true - cli-table3@0.6.5: dependencies: string-width: 4.2.3 optionalDependencies: '@colors/colors': 1.5.0 - cli-truncate@2.1.0: - dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 - optional: true - cli-truncate@5.2.0: dependencies: slice-ansi: 8.0.0 @@ -13714,9 +13263,6 @@ snapshots: colorette@2.0.20: {} - colors@1.4.0: - optional: true - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -13727,9 +13273,6 @@ snapshots: commander@4.1.1: {} - commander@6.2.1: - optional: true - comment-json@4.4.1: dependencies: array-timsort: 1.0.3 @@ -13798,9 +13341,6 @@ snapshots: dependencies: browserslist: 4.28.1 - core-util-is@1.0.2: - optional: true - core-util-is@1.0.3: {} cors@2.8.6: @@ -13869,69 +13409,8 @@ snapshots: csstype@3.2.3: {} - cypress-vite@1.8.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2)): - dependencies: - chokidar: 3.6.0 - debug: 4.4.3 - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2) - transitivePeerDependencies: - - supports-color - optional: true - - cypress@15.6.0: - dependencies: - '@cypress/request': 3.0.10 - '@cypress/xvfb': 1.2.4(supports-color@8.1.1) - '@types/sinonjs__fake-timers': 8.1.1 - '@types/sizzle': 2.3.10 - '@types/tmp': 0.2.6 - arch: 2.2.0 - blob-util: 2.0.2 - bluebird: 3.7.2 - buffer: 5.7.1 - cachedir: 2.4.0 - chalk: 4.1.2 - ci-info: 4.4.0 - cli-cursor: 3.1.0 - cli-table3: 0.6.1 - commander: 6.2.1 - common-tags: 1.8.2 - dayjs: 1.11.19 - debug: 4.4.3(supports-color@8.1.1) - enquirer: 2.4.1 - eventemitter2: 6.4.7 - execa: 4.1.0 - executable: 4.1.1 - extract-zip: 2.0.1(supports-color@8.1.1) - figures: 3.2.0 - fs-extra: 9.1.0 - hasha: 5.2.2 - is-installed-globally: 0.4.0 - listr2: 3.14.0(enquirer@2.4.1) - lodash: 4.17.23 - log-symbols: 4.1.0 - minimist: 1.2.8 - ospath: 1.2.2 - pretty-bytes: 5.6.0 - process: 0.11.10 - proxy-from-env: 1.0.0 - request-progress: 3.0.0 - semver: 7.7.4 - supports-color: 8.1.1 - systeminformation: 5.27.7 - tmp: 0.2.5 - tree-kill: 1.2.2 - untildify: 4.0.0 - yauzl: 2.10.0 - optional: true - dargs@8.1.0: {} - dashdash@1.14.1: - dependencies: - assert-plus: 1.0.0 - optional: true - data-uri-to-buffer@4.0.1: {} data-urls@5.0.0: @@ -13965,30 +13444,12 @@ snapshots: de-indent@1.0.2: {} - debug@3.2.7(supports-color@8.1.1): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 8.1.1 - optional: true - - debug@4.4.3: - dependencies: - ms: 2.1.3 - debug@4.4.3(supports-color@5.5.0): dependencies: ms: 2.1.3 optionalDependencies: supports-color: 5.5.0 - debug@4.4.3(supports-color@8.1.1): - dependencies: - ms: 2.1.3 - optionalDependencies: - supports-color: 8.1.1 - optional: true - decimal.js@10.6.0: {} decode-named-character-reference@1.3.0: @@ -14096,12 +13557,6 @@ snapshots: eastasianwidth@0.2.0: {} - ecc-jsbn@0.1.2: - dependencies: - jsbn: 0.1.1 - safer-buffer: 2.1.2 - optional: true - ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 @@ -14149,12 +13604,6 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.0 - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - optional: true - entities@4.5.0: {} entities@6.0.1: {} @@ -14357,11 +13806,6 @@ snapshots: '@typescript-eslint/utils': 8.57.0(eslint@10.0.3(jiti@2.6.1))(typescript@5.9.3) eslint: 10.0.3(jiti@2.6.1) - eslint-plugin-cypress@4.3.0(eslint@10.0.3(jiti@2.6.1)): - dependencies: - eslint: 10.0.3(jiti@2.6.1) - globals: 15.15.0 - eslint-plugin-depend@1.5.0(eslint@10.0.3(jiti@2.6.1)): dependencies: empathic: 2.0.0 @@ -14386,7 +13830,7 @@ snapshots: '@es-joy/resolve.exports': 1.2.0 are-docs-informative: 0.0.2 comment-parser: 1.4.5 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) escape-string-regexp: 4.0.0 eslint: 10.0.3(jiti@2.6.1) espree: 11.2.0 @@ -14468,7 +13912,7 @@ snapshots: '@eslint/core': 1.1.1 '@eslint/plugin-kit': 0.6.1 '@ota-meshi/ast-token-store': 0.3.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 10.0.3(jiti@2.6.1) toml-eslint-parser: 1.0.3 transitivePeerDependencies: @@ -14519,7 +13963,7 @@ snapshots: '@eslint/core': 1.1.1 '@eslint/plugin-kit': 0.6.1 '@ota-meshi/ast-token-store': 0.3.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) diff-sequences: 29.6.3 escape-string-regexp: 5.0.0 eslint: 10.0.3(jiti@2.6.1) @@ -14570,7 +14014,7 @@ snapshots: '@types/estree': 1.0.8 ajv: 6.14.0 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) escape-string-regexp: 4.0.0 eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -14610,7 +14054,7 @@ snapshots: ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -14674,31 +14118,10 @@ snapshots: etag@1.8.1: {} - eventemitter2@6.4.7: - optional: true - eventemitter3@5.0.4: {} events@3.3.0: {} - execa@4.1.0: - dependencies: - cross-spawn: 7.0.6 - get-stream: 5.2.0 - human-signals: 1.1.1 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - optional: true - - executable@4.1.1: - dependencies: - pify: 2.3.0 - optional: true - expect-type@1.3.0: {} express@5.2.1: @@ -14709,7 +14132,7 @@ snapshots: content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 @@ -14738,20 +14161,6 @@ snapshots: extend@3.0.2: {} - extract-zip@2.0.1(supports-color@8.1.1): - dependencies: - debug: 4.4.3(supports-color@8.1.1) - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - optional: true - - extsprintf@1.3.0: - optional: true - fast-check@3.23.2: dependencies: pure-rand: 6.1.0 @@ -14866,11 +14275,6 @@ snapshots: dependencies: format: 0.2.2 - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - optional: true - fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -14880,11 +14284,6 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.3.3 - figures@3.2.0: - dependencies: - escape-string-regexp: 1.0.5 - optional: true - file-entry-cache@11.1.2: dependencies: flat-cache: 6.1.20 @@ -14912,7 +14311,7 @@ snapshots: finalhandler@2.1.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -14967,9 +14366,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - forever-agent@0.6.1: - optional: true - fork-ts-checker-webpack-plugin@9.1.0(typescript@5.9.3)(webpack@5.104.1): dependencies: '@babel/code-frame': 7.29.0 @@ -15093,11 +14489,6 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-stream@5.2.0: - dependencies: - pump: 3.0.4 - optional: true - get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -15108,11 +14499,6 @@ snapshots: dependencies: resolve-pkg-maps: 1.0.0 - getpass@0.1.7: - dependencies: - assert-plus: 1.0.0 - optional: true - giget@2.0.0: dependencies: citty: 0.1.6 @@ -15174,11 +14560,6 @@ snapshots: dependencies: ini: 4.1.1 - global-dirs@3.0.1: - dependencies: - ini: 2.0.0 - optional: true - global-modules@2.0.0: dependencies: global-prefix: 3.0.0 @@ -15277,12 +14658,6 @@ snapshots: minimalistic-assert: 1.0.1 optional: true - hasha@5.2.2: - dependencies: - is-stream: 2.0.1 - type-fest: 0.8.1 - optional: true - hashery@1.5.0: dependencies: hookified: 1.15.1 @@ -15347,29 +14722,19 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color - http-signature@1.4.0: - dependencies: - assert-plus: 1.0.0 - jsprim: 2.0.2 - sshpk: 1.18.0 - optional: true - http2-client@1.3.5: {} https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) transitivePeerDependencies: - supports-color - human-signals@1.1.1: - optional: true - husky@9.1.7: {} iconv-lite@0.6.3: @@ -15415,18 +14780,12 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@4.0.0: - optional: true - indent-string@5.0.0: {} inherits@2.0.4: {} ini@1.3.8: {} - ini@2.0.0: - optional: true - ini@4.1.1: {} ini@4.1.3: {} @@ -15523,12 +14882,6 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-installed-globally@0.4.0: - dependencies: - global-dirs: 3.0.1 - is-path-inside: 3.0.3 - optional: true - is-interactive@1.0.0: {} is-map@2.0.3: {} @@ -15551,9 +14904,6 @@ snapshots: is-obj@2.0.0: {} - is-path-inside@3.0.3: - optional: true - is-path-inside@4.0.0: {} is-plain-obj@4.1.0: {} @@ -15598,9 +14948,6 @@ snapshots: dependencies: which-typed-array: 1.1.20 - is-typedarray@1.0.0: - optional: true - is-unicode-supported@0.1.0: {} is-weakmap@2.0.2: {} @@ -15622,9 +14969,6 @@ snapshots: isexe@3.1.5: {} - isstream@0.1.2: - optional: true - istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -15636,7 +14980,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: - supports-color @@ -15690,9 +15034,6 @@ snapshots: dependencies: argparse: 2.0.1 - jsbn@0.1.1: - optional: true - jsdoc-type-pratt-parser@7.1.1: {} jsdom@25.0.1: @@ -15746,7 +15087,7 @@ snapshots: json-schema-resolver@2.0.0: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) rfdc: 1.4.1 uri-js: 4.4.1 transitivePeerDependencies: @@ -15760,9 +15101,6 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - json-stringify-safe@5.0.1: - optional: true - json5@2.2.3: {} jsonc-eslint-parser@3.1.0: @@ -15781,14 +15119,6 @@ snapshots: jsonpointer@5.0.1: {} - jsprim@2.0.2: - dependencies: - assert-plus: 1.0.0 - extsprintf: 1.3.0 - json-schema: 0.4.0 - verror: 1.10.0 - optional: true - jszip@3.10.1: dependencies: lie: 3.3.0 @@ -15856,20 +15186,6 @@ snapshots: tinyexec: 1.0.2 yaml: 2.8.2 - listr2@3.14.0(enquirer@2.4.1): - dependencies: - cli-truncate: 2.1.0 - colorette: 2.0.20 - log-update: 4.0.0 - p-map: 4.0.0 - rfdc: 1.4.1 - rxjs: 7.8.2 - through: 2.3.8 - wrap-ansi: 7.0.0 - optionalDependencies: - enquirer: 2.4.1 - optional: true - listr2@9.0.5: dependencies: cli-truncate: 5.2.0 @@ -15915,9 +15231,6 @@ snapshots: lodash.mergewith@4.6.2: {} - lodash.once@4.1.1: - optional: true - lodash.snakecase@4.1.1: {} lodash.sortby@4.7.0: {} @@ -15935,14 +15248,6 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 - log-update@4.0.0: - dependencies: - ansi-escapes: 4.3.2 - cli-cursor: 3.1.0 - slice-ansi: 4.0.0 - wrap-ansi: 6.2.0 - optional: true - log-update@6.1.0: dependencies: ansi-escapes: 7.3.0 @@ -16323,7 +15628,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -16598,11 +15903,6 @@ snapshots: shell-quote: 1.8.3 string.prototype.padend: 3.1.6 - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - optional: true - nth-check@2.1.1: dependencies: boolbase: 1.0.0 @@ -16720,9 +16020,6 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 - ospath@1.2.2: - optional: true - outvariant@1.4.3: optional: true @@ -16772,11 +16069,6 @@ snapshots: dependencies: p-limit: 3.1.0 - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - optional: true - package-json-from-dist@1.0.1: {} package-manager-detector@1.6.0: {} @@ -16850,16 +16142,10 @@ snapshots: pathval@2.0.1: {} - pend@1.2.0: - optional: true - perfect-debounce@1.0.0: {} perfect-debounce@2.1.0: {} - performance-now@2.1.0: - optional: true - pg-int8@1.0.1: {} pg-protocol@1.13.0: {} @@ -16884,9 +16170,6 @@ snapshots: pidtree@0.3.1: {} - pify@2.3.0: - optional: true - pify@3.0.0: {} pinia@2.3.1(typescript@5.9.3)(vue@3.5.30(typescript@5.9.3)): @@ -17047,9 +16330,6 @@ snapshots: process-warning@5.0.0: {} - process@0.11.10: - optional: true - protobufjs@7.5.4: dependencies: '@protobufjs/aspromise': 1.1.2 @@ -17085,9 +16365,6 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 - proxy-from-env@1.0.0: - optional: true - proxy-from-env@1.1.0: {} pstree.remy@1.1.8: {} @@ -17105,11 +16382,6 @@ snapshots: dependencies: hookified: 1.15.1 - qs@6.14.2: - dependencies: - side-channel: 1.1.0 - optional: true - qs@6.15.0: dependencies: side-channel: 1.1.0 @@ -17250,18 +16522,13 @@ snapshots: qs: 6.15.0 uuid: 8.3.2 - request-progress@3.0.0: - dependencies: - throttleit: 1.0.1 - optional: true - require-directory@2.1.1: {} require-from-string@2.0.2: {} require-in-the-middle@8.0.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) module-details-from-path: 1.0.4 transitivePeerDependencies: - supports-color @@ -17343,7 +16610,7 @@ snapshots: router@2.2.0: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 @@ -17441,7 +16708,7 @@ snapshots: send@1.2.1: dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -17589,13 +16856,6 @@ snapshots: slash@5.1.0: {} - slice-ansi@3.0.0: - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - optional: true - slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 @@ -17662,19 +16922,6 @@ snapshots: split2@4.2.0: {} - sshpk@1.18.0: - dependencies: - asn1: 0.2.6 - assert-plus: 1.0.0 - bcrypt-pbkdf: 1.0.2 - dashdash: 1.14.1 - ecc-jsbn: 0.1.2 - getpass: 0.1.7 - jsbn: 0.1.1 - safer-buffer: 2.1.2 - tweetnacl: 0.14.5 - optional: true - stackback@0.0.2: {} statuses@2.0.1: {} @@ -17798,9 +17045,6 @@ snapshots: strip-comments@2.0.1: {} - strip-final-newline@2.0.0: - optional: true - strip-indent@4.1.1: {} strip-json-comments@3.1.1: {} @@ -17850,7 +17094,7 @@ snapshots: cosmiconfig: 9.0.1(typescript@5.9.3) css-functions-list: 3.3.3 css-tree: 3.2.1 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) fast-glob: 3.3.3 fastest-levenshtein: 1.0.16 file-entry-cache: 11.1.2 @@ -17884,7 +17128,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) fast-safe-stringify: 2.1.1 form-data: 4.0.5 formidable: 3.5.4 @@ -17978,9 +17222,6 @@ snapshots: dependencies: '@pkgr/core': 0.2.9 - systeminformation@5.27.7: - optional: true - tabbable@6.4.0: {} table@6.9.0: @@ -18035,12 +17276,6 @@ snapshots: dependencies: real-require: 0.2.0 - throttleit@1.0.1: - optional: true - - through@2.3.8: - optional: true - tiny-emitter@2.1.0: {} tinybench@2.9.0: {} @@ -18074,9 +17309,6 @@ snapshots: tldts-core: 7.0.25 optional: true - tmp@0.2.5: - optional: true - to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -18123,9 +17355,6 @@ snapshots: dependencies: punycode: 2.3.1 - tree-kill@1.2.2: - optional: true - ts-algebra@2.0.0: {} ts-api-utils@2.4.0(typescript@5.9.3): @@ -18195,26 +17424,12 @@ snapshots: tslib@2.8.1: {} - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - optional: true - - tweetnacl@0.14.5: - optional: true - type-check@0.4.0: dependencies: prelude-ls: 1.2.1 type-fest@0.16.0: {} - type-fest@0.21.3: - optional: true - - type-fest@0.8.1: - optional: true - type-fest@5.4.4: dependencies: tagged-tag: 1.0.0 @@ -18440,7 +17655,7 @@ snapshots: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.3.0(rollup@2.80.0) chokidar: 3.6.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) fast-glob: 3.3.3 local-pkg: 0.5.1 magic-string: 0.30.21 @@ -18469,9 +17684,6 @@ snapshots: until-async@3.0.2: optional: true - untildify@4.0.0: - optional: true - upath@1.2.0: {} update-browserslist-db@1.2.3(browserslist@4.28.1): @@ -18501,17 +17713,10 @@ snapshots: vary@1.1.2: {} - verror@1.10.0: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.3.0 - optional: true - vite-node@2.1.9(@types/node@22.19.15)(terser@5.46.0): dependencies: cac: 6.7.14 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) es-module-lexer: 1.7.0 pathe: 1.1.2 vite: 5.4.21(@types/node@22.19.15)(terser@5.46.0) @@ -18529,7 +17734,7 @@ snapshots: vite-node@2.1.9(@types/node@24.12.0)(terser@5.46.0): dependencies: cac: 6.7.14 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) es-module-lexer: 1.7.0 pathe: 1.1.2 vite: 5.4.21(@types/node@24.12.0)(terser@5.46.0) @@ -18546,7 +17751,7 @@ snapshots: vite-plugin-pwa@1.2.0(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2))(workbox-build@7.4.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) pretty-bytes: 6.1.1 tinyglobby: 0.2.15 vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(terser@5.46.0)(yaml@2.8.2) @@ -18627,7 +17832,7 @@ snapshots: '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 chai: 5.3.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) expect-type: 1.3.0 magic-string: 0.30.21 pathe: 1.1.2 @@ -18663,7 +17868,7 @@ snapshots: '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 chai: 5.3.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) expect-type: 1.3.0 magic-string: 0.30.21 pathe: 1.1.2 @@ -18699,7 +17904,7 @@ snapshots: '@vitest/spy': 2.1.9 '@vitest/utils': 2.1.9 chai: 5.3.3 - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) expect-type: 1.3.0 magic-string: 0.30.21 pathe: 1.1.2 @@ -18733,7 +17938,7 @@ snapshots: vue-eslint-parser@10.4.0(eslint@10.0.3(jiti@2.6.1)): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@5.5.0) eslint: 10.0.3(jiti@2.6.1) eslint-scope: 9.1.2 eslint-visitor-keys: 5.0.1 @@ -19094,12 +18299,6 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - optional: true - yn@3.1.1: {} yocto-queue@0.1.0: {}