From edefa6fc7e7ceaeb5efbb63487f792d128832cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuno=20G=C3=B3is?= Date: Mon, 8 May 2023 09:16:18 +0100 Subject: [PATCH] test: add interactive demo guide e2e test (#3656) This PR revamps e2e tests, while adding a new one for the interactive demo guide: - Bumps Cypress from `9.7.0` to `12.11.0`; - Bumps Cypress GH action from `v2` to `v5`; - Makes any adjustments needed; - Fixes a lot of issues identified with existing tests; - Adds new `demo.spec.ts` e2e test that covers the entire demo guide flow; **Note:** Currently does not include `demo.spec.ts` in the GH action, as it [fails](https://github.com/Unleash/unleash/actions/runs/4896839575/jobs/8744137231?pr=3656) on step 2.13 (last step of "user-specific" topic). It runs perfectly fine locally, though. Might be placebo, but in general tests seem less flaky now and they may even be faster (especially when not adding the `demo` one, which would always take a long time). --- .github/workflows/e2e.frontend.yaml | 2 +- frontend/cypress.config.ts | 28 ++++ frontend/cypress.json | 7 - frontend/cypress/global.d.ts | 28 ++-- .../cypress/integration/demo/demo.spec.ts | 130 ++++++++++++++++++ .../integration/feature/feature.spec.ts | 21 +-- .../cypress/integration/import/import.spec.ts | 5 +- frontend/cypress/plugins/index.ts | 22 --- frontend/cypress/support/API.ts | 31 ++++- frontend/cypress/support/UI.ts | 31 ++--- frontend/cypress/support/commands.ts | 3 + frontend/cypress/support/e2e.ts | 20 +++ frontend/package.json | 3 +- .../DemoDialogFinish/DemoDialogFinish.tsx | 1 + .../DemoDialogWelcome/DemoDialogWelcome.tsx | 1 + .../DemoStepTooltip/DemoStepTooltip.tsx | 2 + frontend/yarn.lock | 45 +++--- 17 files changed, 288 insertions(+), 92 deletions(-) create mode 100644 frontend/cypress.config.ts delete mode 100644 frontend/cypress.json create mode 100644 frontend/cypress/integration/demo/demo.spec.ts delete mode 100644 frontend/cypress/plugins/index.ts create mode 100644 frontend/cypress/support/e2e.ts diff --git a/.github/workflows/e2e.frontend.yaml b/.github/workflows/e2e.frontend.yaml index 3bbd1835de..ad87fad6ca 100644 --- a/.github/workflows/e2e.frontend.yaml +++ b/.github/workflows/e2e.frontend.yaml @@ -22,7 +22,7 @@ jobs: - name: Checkout uses: actions/checkout@v3 - name: Run Cypress - uses: cypress-io/github-action@v2 + uses: cypress-io/github-action@v5 with: working-directory: frontend env: AUTH_USER=admin,AUTH_PASSWORD=unleash4all diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts new file mode 100644 index 0000000000..88468d02b1 --- /dev/null +++ b/frontend/cypress.config.ts @@ -0,0 +1,28 @@ +import path from 'path'; +import { defineConfig } from 'cypress'; +import vitePreprocessor from 'cypress-vite'; + +export default defineConfig({ + projectId: 'tc2qff', + defaultCommandTimeout: 12000, + screenshotOnRunFailure: false, + video: false, + e2e: { + specPattern: '**/*.spec.ts', + setupNodeEvents(on, config) { + on( + 'file:preprocessor', + vitePreprocessor({ + configFile: path.resolve(__dirname, './vite.config.ts'), + mode: 'development', + }) + ); + on('task', { + log(message) { + console.log(message); + return null; + }, + }); + }, + }, +}); diff --git a/frontend/cypress.json b/frontend/cypress.json deleted file mode 100644 index ea78e63c8d..0000000000 --- a/frontend/cypress.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "projectId": "tc2qff", - "defaultCommandTimeout": 12000, - "screenshotOnRunFailure": false, - "video": false, - "experimentalSessionAndOrigin": true -} diff --git a/frontend/cypress/global.d.ts b/frontend/cypress/global.d.ts index 90783d8bd0..aacc3afe18 100644 --- a/frontend/cypress/global.d.ts +++ b/frontend/cypress/global.d.ts @@ -12,6 +12,12 @@ declare namespace Cypress { email: string; password: string; } + + interface IEnvironment { + name: string; + type: 'development' | 'preproduction' | 'test' | 'production'; + } + interface Chainable { runBefore(): Chainable; @@ -48,19 +54,14 @@ declare namespace Cypress { // STRATEGY addUserIdStrategyToFeature_UI( featureName: string, - strategyId: string, projectName?: string ): Chainable; addFlexibleRolloutStrategyToFeature_UI( options: AddFlexibleRolloutStrategyOptions ): Chainable; - updateFlexibleRolloutStrategy_UI( - featureToggleName: string, - strategyId: string - ); + updateFlexibleRolloutStrategy_UI(featureToggleName: string); deleteFeatureStrategy_UI( featureName: string, - strategyId: string, shouldWait?: boolean, projectName?: string ): Chainable; @@ -73,9 +74,20 @@ declare namespace Cypress { role: number, projectName?: string ): Chainable; - createProject_API(name: string): Chainable; + createProject_API( + name: string, + options?: Partial + ): Chainable; deleteProject_API(name: string): Chainable; - createFeature_API(name: string, projectName?: string): Chainable; + createFeature_API( + name: string, + projectName?: string, + options?: Partial + ): Chainable; deleteFeature_API(name: string): Chainable; + createEnvironment_API( + environment: IEnvironment, + options?: Partial + ): Chainable; } } diff --git a/frontend/cypress/integration/demo/demo.spec.ts b/frontend/cypress/integration/demo/demo.spec.ts new file mode 100644 index 0000000000..71f57a0938 --- /dev/null +++ b/frontend/cypress/integration/demo/demo.spec.ts @@ -0,0 +1,130 @@ +/// +import { TOPICS } from '../../../src/component/demo/demo-topics'; + +describe('demo', () => { + const baseUrl = Cypress.config().baseUrl; + const randomId = String(Math.random()).split('.')[1]; + + before(() => { + cy.runBefore(); + cy.login_UI(); + + const optionsIgnore409 = { failOnStatusCode: false }; + + cy.createEnvironment_API( + { + name: 'dev', + type: 'development', + }, + optionsIgnore409 + ); + cy.createProject_API('demo-app', optionsIgnore409); + cy.createFeature_API('demoApp.step1', 'demo-app', optionsIgnore409); + cy.createFeature_API('demoApp.step2', 'demo-app', optionsIgnore409); + cy.createFeature_API('demoApp.step3', 'demo-app', optionsIgnore409); + cy.createFeature_API('demoApp.step4', 'demo-app', optionsIgnore409); + }); + + beforeEach(() => { + cy.login_UI(); + cy.visit('/projects'); + if (document.querySelector("[data-testid='CLOSE_SPLASH']")) { + cy.get("[data-testid='CLOSE_SPLASH']").click(); + } + + cy.intercept('GET', `${baseUrl}/api/admin/ui-config`, req => { + req.headers['cache-control'] = + 'no-cache, no-store, must-revalidate'; + req.on('response', res => { + if (res.body) { + res.body.flags = { + ...res.body.flags, + demo: true, + }; + } + }); + }); + }); + + afterEach(() => { + cy.intercept('GET', `${baseUrl}/api/admin/ui-config`).as('uiConfig'); + }); + + after(() => { + cy.request({ + method: 'DELETE', + url: `${baseUrl}/api/admin/projects/demo-app/features/demoApp.step1`, + }); + cy.request({ + method: 'DELETE', + url: `${baseUrl}/api/admin/projects/demo-app/features/demoApp.step2`, + }); + cy.request({ + method: 'DELETE', + url: `${baseUrl}/api/admin/projects/demo-app/features/demoApp.step3`, + }); + cy.request({ + method: 'DELETE', + url: `${baseUrl}/api/admin/projects/demo-app/features/demoApp.step4`, + }); + cy.request({ + method: 'POST', + url: `${baseUrl}/api/admin/projects/demo-app/delete`, + body: { + features: [ + 'demoApp.step1', + 'demoApp.step2', + 'demoApp.step3', + 'demoApp.step4', + ], + }, + }); + }); + + it('can complete the demo', () => { + cy.get('[data-testid="DEMO_START_BUTTON"]').click(); + + for (let topic = 0; topic < TOPICS.length; topic++) { + const currentTopic = TOPICS[topic]; + for (let step = 0; step < currentTopic.steps.length; step++) { + const currentStep = currentTopic.steps[step]; + + cy.task( + 'log', + `Testing topic #${topic + 1} "${ + currentTopic.title + }", step #${step + 1}...` + ); + + if (!currentStep.optional) { + cy.wait(2000); + + if (currentStep.nextButton) { + if (currentStep.focus) { + if (currentStep.focus === true) { + cy.get(currentStep.target as string) + .first() + .type(randomId, { force: true }); + } else { + cy.get(currentStep.target as string) + .first() + .find(currentStep.focus) + .first() + .type(randomId, { force: true }); + } + } + cy.get('[data-testid="DEMO_NEXT_BUTTON"]').click({ + force: true, + }); + } else { + cy.get(currentStep.target as string) + .first() + .click({ + force: true, + }); + } + } + } + } + }); +}); diff --git a/frontend/cypress/integration/feature/feature.spec.ts b/frontend/cypress/integration/feature/feature.spec.ts index 0003da5f16..5fae05fa18 100644 --- a/frontend/cypress/integration/feature/feature.spec.ts +++ b/frontend/cypress/integration/feature/feature.spec.ts @@ -6,7 +6,6 @@ describe('feature', () => { const variant1 = 'variant1'; const variant2 = 'variant2'; - let strategyId = ''; before(() => { cy.runBefore(); @@ -40,26 +39,20 @@ describe('feature', () => { ); }); - it('can add, update and delete a gradual rollout strategy to the development environment', async () => { + it('can add, update and delete a gradual rollout strategy to the development environment', () => { cy.addFlexibleRolloutStrategyToFeature_UI({ featureToggleName, - }).then(value => { - strategyId = value; - cy.updateFlexibleRolloutStrategy_UI( - featureToggleName, - strategyId - ).then(() => - cy.deleteFeatureStrategy_UI(featureToggleName, strategyId) + }).then(() => { + cy.updateFlexibleRolloutStrategy_UI(featureToggleName).then(() => + cy.deleteFeatureStrategy_UI(featureToggleName) ); }); }); it('can add a userId strategy to the development environment', () => { - cy.addUserIdStrategyToFeature_UI(featureToggleName, strategyId).then( - value => { - cy.deleteFeatureStrategy_UI(featureToggleName, value, false); - } - ); + cy.addUserIdStrategyToFeature_UI(featureToggleName).then(() => { + cy.deleteFeatureStrategy_UI(featureToggleName, false); + }); }); it('can add variants to the development environment', () => { diff --git a/frontend/cypress/integration/import/import.spec.ts b/frontend/cypress/integration/import/import.spec.ts index 0c67d8b8c1..25bcae50b1 100644 --- a/frontend/cypress/integration/import/import.spec.ts +++ b/frontend/cypress/integration/import/import.spec.ts @@ -34,7 +34,7 @@ describe('imports', () => { it('can import data', () => { cy.visit('/projects/default'); - cy.get("[data-testid='IMPORT_BUTTON']").click(); + cy.get("[data-testid='IMPORT_BUTTON']").click({ force: true }); const exportText = { features: [ @@ -114,6 +114,9 @@ describe('imports', () => { // cy.contains('Import completed'); cy.visit(`/projects/default/features/${randomFeatureName}`); + + cy.wait(500); + cy.get( "[data-testid='feature-toggle-status'] input[type='checkbox']:checked" ) diff --git a/frontend/cypress/plugins/index.ts b/frontend/cypress/plugins/index.ts deleted file mode 100644 index 59b2bab6e4..0000000000 --- a/frontend/cypress/plugins/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/// -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** - -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) - -/** - * @type {Cypress.PluginConfig} - */ -// eslint-disable-next-line no-unused-vars -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config -} diff --git a/frontend/cypress/support/API.ts b/frontend/cypress/support/API.ts index d0dde3d2f4..15ef005513 100644 --- a/frontend/cypress/support/API.ts +++ b/frontend/cypress/support/API.ts @@ -6,11 +6,12 @@ const password = Cypress.env(`AUTH_PASSWORD`) + '_A'; const PROJECT_MEMBER = 5; export const createFeature_API = ( featureName: string, - projectName?: string + projectName?: string, + options?: Partial ): Chainable => { const project = projectName || 'default'; return cy.request({ - url: `/api/admin/projects/${project}/features`, + url: `${baseUrl}/api/admin/projects/${project}/features`, method: 'POST', body: { name: `${featureName}`, @@ -18,6 +19,7 @@ export const createFeature_API = ( type: 'release', impressionData: false, }, + ...options, }); }; @@ -32,9 +34,12 @@ export const deleteFeature_API = (name: string): Chainable => { }); }; -export const createProject_API = (project: string): Chainable => { +export const createProject_API = ( + project: string, + options?: Partial +): Chainable => { return cy.request({ - url: `/api/admin/projects`, + url: `${baseUrl}/api/admin/projects`, method: 'POST', body: { id: project, @@ -42,6 +47,7 @@ export const createProject_API = (project: string): Chainable => { description: project, impressionData: false, }, + ...options, }); }; @@ -101,3 +107,20 @@ export const addUserToProject_API = ( } ); }; + +interface IEnvironment { + name: string; + type: 'development' | 'preproduction' | 'test' | 'production'; +} + +export const createEnvironment_API = ( + environment: IEnvironment, + options?: Partial +): Chainable => { + return cy.request({ + url: `${baseUrl}/api/admin/environments`, + method: 'POST', + body: environment, + ...options, + }); +}; diff --git a/frontend/cypress/support/UI.ts b/frontend/cypress/support/UI.ts index a3f97ecf3d..f3be3186df 100644 --- a/frontend/cypress/support/UI.ts +++ b/frontend/cypress/support/UI.ts @@ -5,6 +5,9 @@ import AddStrategyOptions = Cypress.AddFlexibleRolloutStrategyOptions; const AUTH_USER = Cypress.env('AUTH_USER'); const AUTH_PASSWORD = Cypress.env('AUTH_PASSWORD'); const ENTERPRISE = Boolean(Cypress.env('ENTERPRISE')); + +let strategyId: string | undefined; + const disableActiveSplashScreens = () => { return cy.visit(`/splash/operators`); }; @@ -90,19 +93,14 @@ export const createProject_UI = ( export const createSegment_UI = (segmentName: string): Chainable => { cy.get("[data-testid='NAVIGATE_TO_CREATE_SEGMENT']").click(); - let segmentId; - cy.intercept('POST', '/api/admin/segments', req => { - req.continue(res => { - segmentId = res.body.id; - }); - }).as('createSegment'); + + cy.intercept('POST', '/api/admin/segments').as('createSegment'); cy.get("[data-testid='SEGMENT_NAME_ID']").type(segmentName); cy.get("[data-testid='SEGMENT_DESC_ID']").type('hello-world'); cy.get("[data-testid='SEGMENT_NEXT_BTN_ID']").click(); cy.get("[data-testid='SEGMENT_CREATE_BTN_ID']").click(); - cy.wait('@createSegment'); - return cy.wrap(segmentId); + return cy.wait('@createSegment'); }; export const deleteSegment_UI = (segmentName: string): Chainable => { @@ -121,7 +119,7 @@ export const addFlexibleRolloutStrategyToFeature_UI = ( const defaultStickiness = stickiness || 'default'; cy.visit(`/projects/default/features/${featureToggleName}`); - let strategyId; + cy.intercept( 'POST', `/api/admin/projects/${projectName}/features/${featureToggleName}/environments/development/strategies`, @@ -154,13 +152,11 @@ export const addFlexibleRolloutStrategyToFeature_UI = ( cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click(); } cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`).first().click(); - cy.wait('@addStrategyToFeature'); - return cy.wrap(strategyId); + return cy.wait('@addStrategyToFeature'); }; export const updateFlexibleRolloutStrategy_UI = ( featureToggleName: string, - strategyId: string, projectName?: string ) => { const project = projectName || 'default'; @@ -183,7 +179,6 @@ export const updateFlexibleRolloutStrategy_UI = ( .clear() .type('new-group-id'); - cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`).first().click(); cy.intercept( 'PUT', `/api/admin/projects/${project}/features/${featureToggleName}/environments/*/strategies/${strategyId}`, @@ -203,12 +198,13 @@ export const updateFlexibleRolloutStrategy_UI = ( }); } ).as('updateStrategy'); + + cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`).first().click(); return cy.wait('@updateStrategy'); }; export const deleteFeatureStrategy_UI = ( featureToggleName: string, - strategyId: string, shouldWait?: boolean, projectName?: string ): Chainable => { @@ -225,7 +221,7 @@ export const deleteFeatureStrategy_UI = ( ).as('deleteUserStrategy'); cy.visit(`/projects/${project}/features/${featureToggleName}`); cy.get('[data-testid=FEATURE_ENVIRONMENT_ACCORDION_development]').click(); - cy.get('[data-testid=STRATEGY_FORM_REMOVE_ID]').click(); + cy.get('[data-testid=STRATEGY_FORM_REMOVE_ID]').first().click(); if (!shouldWait) return cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click(); else cy.get('[data-testid=DIALOGUE_CONFIRM_ID]').click(); return cy.wait('@deleteUserStrategy'); @@ -254,7 +250,7 @@ export const addUserIdStrategyToFeature_UI = ( .type('user2') .type('{enter}'); cy.get('[data-testid=ADD_TO_STRATEGY_INPUT_LIST]').click(); - let strategyId; + cy.intercept( 'POST', `/api/admin/projects/default/features/${featureToggleName}/environments/*/strategies`, @@ -276,8 +272,7 @@ export const addUserIdStrategyToFeature_UI = ( ).as('addStrategyToFeature'); cy.get(`[data-testid=STRATEGY_FORM_SUBMIT_ID]`).first().click(); - cy.wait('@addStrategyToFeature'); - return cy.wrap(strategyId); + return cy.wait('@addStrategyToFeature'); }; export const addVariantsToFeature_UI = ( diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index b76560c09d..a726f50926 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -24,6 +24,7 @@ import { deleteFeature_API, deleteProject_API, updateUserPassword_API, + createEnvironment_API, //@ts-ignore } from './API'; @@ -35,6 +36,7 @@ Cypress.Commands.add('deleteFeature_API', deleteFeature_API); Cypress.Commands.add('deleteProject_API', deleteProject_API); Cypress.Commands.add('logout_UI', logout_UI); Cypress.Commands.add('createProject_UI', createProject_UI); +Cypress.Commands.add('createProject_API', createProject_API); Cypress.Commands.add('createUser_API', createUser_API); Cypress.Commands.add('addUserToProject_API', addUserToProject_API); Cypress.Commands.add('updateUserPassword_API', updateUserPassword_API); @@ -55,3 +57,4 @@ Cypress.Commands.add( 'updateFlexibleRolloutStrategy_UI', updateFlexibleRolloutStrategy_UI ); +Cypress.Commands.add('createEnvironment_API', createEnvironment_API); diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts new file mode 100644 index 0000000000..f80f74f8e1 --- /dev/null +++ b/frontend/cypress/support/e2e.ts @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/e2e.ts 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 +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 2dbc5a5104..02c4e9be0d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -67,7 +67,8 @@ "classnames": "2.3.2", "copy-to-clipboard": "3.3.3", "countries-and-timezones": "^3.4.0", - "cypress": "9.7.0", + "cypress": "12.11.0", + "cypress-vite": "^1.4.0", "date-fns": "2.29.3", "date-fns-tz": "^2.0.0", "debounce": "1.2.1", diff --git a/frontend/src/component/demo/DemoDialog/DemoDialogFinish/DemoDialogFinish.tsx b/frontend/src/component/demo/DemoDialog/DemoDialogFinish/DemoDialogFinish.tsx index b278ad3209..9557c9361e 100644 --- a/frontend/src/component/demo/DemoDialog/DemoDialogFinish/DemoDialogFinish.tsx +++ b/frontend/src/component/demo/DemoDialog/DemoDialogFinish/DemoDialogFinish.tsx @@ -57,6 +57,7 @@ export const DemoDialogFinish = ({ variant="contained" color="primary" onClick={onClose} + data-testid="DEMO_FINISH_BUTTON" > Continue diff --git a/frontend/src/component/demo/DemoDialog/DemoDialogWelcome/DemoDialogWelcome.tsx b/frontend/src/component/demo/DemoDialog/DemoDialogWelcome/DemoDialogWelcome.tsx index e280eba4b1..e26517fe33 100644 --- a/frontend/src/component/demo/DemoDialog/DemoDialogWelcome/DemoDialogWelcome.tsx +++ b/frontend/src/component/demo/DemoDialog/DemoDialogWelcome/DemoDialogWelcome.tsx @@ -100,6 +100,7 @@ export const DemoDialogWelcome = ({ variant="contained" color="primary" onClick={onStart} + data-testid="DEMO_START_BUTTON" > Try Unleash demo diff --git a/frontend/src/component/demo/DemoSteps/DemoStepTooltip/DemoStepTooltip.tsx b/frontend/src/component/demo/DemoSteps/DemoStepTooltip/DemoStepTooltip.tsx index 1bf1cc7fcc..53b1670742 100644 --- a/frontend/src/component/demo/DemoSteps/DemoStepTooltip/DemoStepTooltip.tsx +++ b/frontend/src/component/demo/DemoSteps/DemoStepTooltip/DemoStepTooltip.tsx @@ -134,6 +134,7 @@ export const DemoStepTooltip = ({ onClick={() => onNext(stepIndex)} variant="contained" sx={{ alignSelf: 'flex-end' }} + data-testid="DEMO_NEXT_BUTTON" > {topic === topics.length - 1 && stepIndex === @@ -189,6 +190,7 @@ export const DemoStepTooltip = ({ onClick={() => onNext(stepIndex)} variant="contained" sx={{ alignSelf: 'flex-end' }} + data-testid="DEMO_NEXT_BUTTON" > {topic === topics.length - 1 && stepIndex === topics[topic].steps.length - 1 diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 22556220ab..d3013fd25a 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -3772,10 +3772,10 @@ commander@^2.20.3: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -commander@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" - integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== +commander@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== common-tags@^1.8.0: version "1.8.2" @@ -3919,10 +3919,18 @@ cuid@^2.1.8: resolved "https://registry.yarnpkg.com/cuid/-/cuid-2.1.8.tgz#cbb88f954171e0d5747606c0139fb65c5101eac0" integrity sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg== -cypress@9.7.0: - version "9.7.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-9.7.0.tgz#bf55b2afd481f7a113ef5604aa8b693564b5e744" - integrity sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q== +cypress-vite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cypress-vite/-/cypress-vite-1.4.0.tgz#4d2889d62c11aed7188b1082af16210240aac2e6" + integrity sha512-BHmOku8q6nRtDGPiBcE7zcAZs56/OsiX5SFoldHEMSQ+I6nnPUU2tcrRNeRsCArONQAvwTu2Da7R/rFGA/DSEg== + dependencies: + chokidar "^3.5.3" + debug "^4.3.4" + +cypress@12.11.0: + version "12.11.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-12.11.0.tgz#b46dc6a1d0387f59a4b5c6a18cc03884fd61876e" + integrity sha512-TJE+CCWI26Hwr5Msb9GpQhFLubdYooW0fmlPwTsfiyxmngqc7+SZGLPeIkj2dTSSZSEtpQVzOzvcnzH0o8G7Vw== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -3938,12 +3946,12 @@ cypress@9.7.0: check-more-types "^2.24.0" cli-cursor "^3.1.0" cli-table3 "~0.6.1" - commander "^5.1.0" + commander "^6.2.1" common-tags "^1.8.0" dayjs "^1.10.4" - debug "^4.3.2" + debug "^4.3.4" enquirer "^2.3.6" - eventemitter2 "^6.4.3" + eventemitter2 "6.4.7" execa "4.1.0" executable "^4.1.1" extract-zip "2.0.1" @@ -3956,7 +3964,7 @@ cypress@9.7.0: listr2 "^3.8.3" lodash "^4.17.21" log-symbols "^4.0.0" - minimist "^1.2.6" + minimist "^1.2.8" ospath "^1.2.2" pretty-bytes "^5.6.0" proxy-from-env "1.0.0" @@ -5117,10 +5125,10 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter2@^6.4.3: - version "6.4.9" - resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.9.tgz#41f2750781b4230ed58827bc119d293471ecb125" - integrity sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg== +eventemitter2@6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" + integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== eventemitter3@^4.0.0: version "4.0.7" @@ -7046,6 +7054,11 @@ minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18" integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g== +minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + mlly@^1.1.1, mlly@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.2.0.tgz#f0f6c2fc8d2d12ea6907cd869066689b5031b613"