From 26cf6eac4442d646e629f93d9c8725ca62f4f53f Mon Sep 17 00:00:00 2001 From: Nick Lanam <314133+NickLanam@users.noreply.github.com> Date: Tue, 1 Aug 2023 15:29:55 -0700 Subject: [PATCH] Update Cypress to v12 (#1641) Summary: Update Cypress from 9.x to 12.x, and perform all relevant migrations. Changes are the results of [10.0 migration](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-100), [11.0 migration](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-110), and [12.0 migration](https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-120) guides. The reason for using `cypress.config.mjs` instead of `cypress.config.ts` is that the latter is not working with Yarn 3 yet ([1](https://github.com/cypress-io/cypress/issues/24209), [2](https://github.com/cypress-io/cypress/issues/22747), [3](https://github.com/cypress-io/cypress/issues/25958)). If that changes, we can revisit. Notably, one of the larger changes is that test isolation is now on by default. This means the page is refreshed between each test rather than each suite, so some tests needed to be reconfigured to work with that paradigm. Cypress' UI has gotten a major refresh as well, so I changed the commands to account for it. Relevant Issues: N/A Type of change: /kind cleanup Test Plan: Follow instructions in `src/ui/cypress/README.md`. In particular, try `yarn run cypress:run:chrome`. All of the tests should pass, totally headlessly. Signed-off-by: Nick Lanam --- src/ui/.eslintrc.json | 6 +- src/ui/cypress.config.mjs | 46 +++++++++++ src/ui/cypress.json | 3 - src/ui/cypress/README.md | 6 +- .../admin/api-and-deployment-keys.spec.ts | 4 +- .../live/keyboard-shortcuts.spec.ts | 20 ++--- .../cypress/integration/live/navbars.spec.ts | 4 +- .../integration/live/share-dialog.spec.ts | 2 +- .../integration/live/sidebar-scripts.spec.ts | 10 +-- .../unauthenticated/credits.spec.ts | 3 +- src/ui/cypress/support/utils/grpc.ts | 2 +- src/ui/cypress/tsconfig.json | 2 +- src/ui/package.json | 10 ++- src/ui/yarn.lock | 76 +++++++------------ 14 files changed, 102 insertions(+), 92 deletions(-) create mode 100644 src/ui/cypress.config.mjs delete mode 100644 src/ui/cypress.json diff --git a/src/ui/.eslintrc.json b/src/ui/.eslintrc.json index 77cf540ecb2..1b69000ecff 100644 --- a/src/ui/.eslintrc.json +++ b/src/ui/.eslintrc.json @@ -101,7 +101,8 @@ "src/testing/**/*" ], "excludedFiles": [ - "cypress/**/*" + "cypress/**/*", + "cypress.config.mjs" ], "env": { "node": true, @@ -137,7 +138,8 @@ "*.tsx" ], "excludedFiles": [ - "cypress/**/*" + "cypress/**/*", + "cypress.config.mjs" ], "extends": [ "airbnb-typescript/base", diff --git a/src/ui/cypress.config.mjs b/src/ui/cypress.config.mjs new file mode 100644 index 00000000000..2af0b6905da --- /dev/null +++ b/src/ui/cypress.config.mjs @@ -0,0 +1,46 @@ +/* + * Copyright 2018- The Pixie Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import { defineConfig } from 'cypress'; +// import loadPlugins from 'plugins/index'; + +export default defineConfig({ + e2e: { + specPattern: 'cypress/integration/**/*.spec.{js,jsx,ts,tsx}', + supportFile: 'cypress/support/index.ts', + baseUrl: 'https://dev.withpixie.dev', + video: false, // Turn this on only if you are struggling to debug something, it only works locally and in Chrome. + setupNodeEvents(on/*, config*/) { + // Reduce motion + on('before:browser:launch', (browser, launchOptions) => { + if (browser.family === 'chromium') { + if (browser.name === 'electron') { + // Electron doesn't seem to have a setting for this. + // https://www.electronjs.org/docs/latest/api/browser-window#new-browserwindowoptions + // launchOptions.preferences.SOMETHING = true; + } else { + launchOptions.args.push('--force-prefers-reduced-motion'); + } + } else if (browser.family === 'firefox') { + launchOptions.preferences['ui.prefersReducedMotion'] = 1; + } + return launchOptions; + }); + }, + }, +}); diff --git a/src/ui/cypress.json b/src/ui/cypress.json deleted file mode 100644 index 64316ab4169..00000000000 --- a/src/ui/cypress.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "baseUrl": "https://dev.withpixie.dev" -} diff --git a/src/ui/cypress/README.md b/src/ui/cypress/README.md index 11d6a448144..770ebcb19eb 100644 --- a/src/ui/cypress/README.md +++ b/src/ui/cypress/README.md @@ -8,10 +8,10 @@ To run them, you need two things: To get this, load the UI, open the dev tools, and look for the `default-sessionSOME_NUMBER` cookie. That is what you'll use to set `CYPRESS_GOOGLE_SESSION_COOKIE`. The name of that cookie will set `CYPRESS_GOOGLE_SESSION_COOKIE_KEY`. -Then, run this command: -`CYPRESS_BASE_URL='https://dev.withpixie.dev' CYPRESS_GOOGLE_SESSION_COOKIE_KEY='default-sessionSOME_NUMBER' CYPRESS_GOOGLE_SESSION_COOKIE='paste-your-session-cookie-value-here' yarn cypress:open` +Then, run this command to access Cypress' UI: +`CYPRESS_BASE_URL='https://dev.withpixie.dev' CYPRESS_GOOGLE_SESSION_COOKIE_KEY='default-sessionSOME_NUMBER' CYPRESS_GOOGLE_SESSION_COOKIE='paste-your-session-cookie-value-here' yarn cypress open` -You can use `... yarn cypress:run` instead if you want to run the tests immediately and headlessly. +You can use `... yarn cypress:run:chrome` (or `... yarn cypress:run:firefox`) instead if you want to run the tests immediately and headlessly. If you don't want to set these environment variables every time, you can override everything except the base URL in `cypress.env.json` (copy from `cypress.template.env.json`): ```json diff --git a/src/ui/cypress/integration/admin/api-and-deployment-keys.spec.ts b/src/ui/cypress/integration/admin/api-and-deployment-keys.spec.ts index 143db6cf262..687f6b9e166 100644 --- a/src/ui/cypress/integration/admin/api-and-deployment-keys.spec.ts +++ b/src/ui/cypress/integration/admin/api-and-deployment-keys.spec.ts @@ -129,5 +129,5 @@ function keyTests(prefix: string, url: string) { }); } -keyTests('API', '/admin/api-keys'); -keyTests('Deployment', '/admin/deployment-keys'); +keyTests('API', '/admin/keys/api'); +keyTests('Deployment', '/admin/keys/deployment'); diff --git a/src/ui/cypress/integration/live/keyboard-shortcuts.spec.ts b/src/ui/cypress/integration/live/keyboard-shortcuts.spec.ts index 26afedf2a06..15a82404b07 100644 --- a/src/ui/cypress/integration/live/keyboard-shortcuts.spec.ts +++ b/src/ui/cypress/integration/live/keyboard-shortcuts.spec.ts @@ -24,9 +24,7 @@ describe('Live view keyboard shortcuts', () => { const modalTitle = 'Available Shortcuts'; - // Note: this is a before, not a beforeEach. - // Each test needs to close whatever its shortcut opened to reset properly and test that. - before(() => { + beforeEach(() => { cy.loginGoogle(); cy.visit('/'); @@ -36,10 +34,6 @@ describe('Live view keyboard shortcuts', () => { cy.wait('@exec-auto'); }); - beforeEach(() => { - cy.loginGoogle(); - }); - it('Opens shortcut help from profile menu', () => { cy.get('header.MuiPaper-root > .MuiToolbar-root > *:last-child').as('profile-menu-trigger'); cy.get('@profile-menu-trigger').click(); @@ -62,13 +56,11 @@ describe('Live view keyboard shortcuts', () => { // Note: the way :nth-child works is weird; n+2 means "everything after the first child" cy.contains(modalTitle).parent().find('> div:nth-child(n+2)').as('rows'); cy.get('@rows').should('have.length', 5); - cy.get('@rows').within(() => { - cy.contains('Show/hide script editor').should('exist'); - cy.contains('Show/hide data drawer').should('exist'); - cy.contains('Show/hide command palette').should('exist'); - cy.contains('Execute current Live View script').should('exist'); - cy.contains('Show all keyboard shortcuts').should('exist'); - }); + cy.get('@rows').contains('Show/hide script editor').should('exist'); + cy.get('@rows').contains('Show/hide data drawer').should('exist'); + cy.get('@rows').contains('Show/hide command palette').should('exist'); + cy.get('@rows').contains('Execute current Live View script').should('exist'); + cy.get('@rows').contains('Show all keyboard shortcuts').should('exist'); cy.get('body').type('{esc}'); cy.contains(modalTitle).should('not.exist'); }); diff --git a/src/ui/cypress/integration/live/navbars.spec.ts b/src/ui/cypress/integration/live/navbars.spec.ts index 937cfe171c8..1c006e8a05e 100644 --- a/src/ui/cypress/integration/live/navbars.spec.ts +++ b/src/ui/cypress/integration/live/navbars.spec.ts @@ -24,13 +24,13 @@ describe('Live View navbars', () => { before(() => { cy.loginGoogle(); stubExecuteScript(); - cy.visit('/'); }); beforeEach(() => { // Re-apply one-time intercepts each run. cy.loginGoogle(); stubExecuteScript(); + cy.visit('/'); cy.get('.MuiToolbar-root').as('topbar'); }); @@ -42,7 +42,7 @@ describe('Live View navbars', () => { it('Has the right contents', () => { cy.get('@topbar').should('exist').within(() => { cy.get('a[href="/"]').should('exist'); - cy.contains('Cluster:').find('+span').should(($span) => expect($span.text()).not.to.be.empty); + cy.contains('cluster:').find('+span').should(($span) => expect($span.text()).not.to.be.empty); // Items that have tooltips: the share/edit/move/run buttons. // The sidebar expander also has an aria-label but isn't a Material tooltip. // The trigger for the Command Palette sets aria-label in the same way. diff --git a/src/ui/cypress/integration/live/share-dialog.spec.ts b/src/ui/cypress/integration/live/share-dialog.spec.ts index 70419511679..2fe5593ba33 100644 --- a/src/ui/cypress/integration/live/share-dialog.spec.ts +++ b/src/ui/cypress/integration/live/share-dialog.spec.ts @@ -48,7 +48,7 @@ describe('Share dialog', () => { ]); }); - // TODO(nick,PC-1450): This only tests for a Google org; need to test email/password too. + // TODO(NickLanam): This only tests for a Google org; need to test email/password too. cy.location('href').then((href) => { cy.get('@copy-to-clipboard').should('be.calledOnceWithExactly', href); }); diff --git a/src/ui/cypress/integration/live/sidebar-scripts.spec.ts b/src/ui/cypress/integration/live/sidebar-scripts.spec.ts index b7a74111739..b7990c129d7 100644 --- a/src/ui/cypress/integration/live/sidebar-scripts.spec.ts +++ b/src/ui/cypress/integration/live/sidebar-scripts.spec.ts @@ -19,17 +19,13 @@ import { stubExecuteScript, waitExecuteScript } from 'support/utils/grpc'; describe('Sidebar script shortcuts', () => { - before(() => { - cy.loginGoogle(); - stubExecuteScript().as('exec-auto'); - cy.visit('/'); - }); - beforeEach(() => { - // Once in before all for the auto exec; + // Once for the auto exec; // Once each for the manual clicks that fire more requests. // Remember, Cypress intercepts only trigger once each by default. cy.loginGoogle(); + stubExecuteScript().as('exec-auto'); + cy.visit('/'); }); it('Auto-runs cluster script before anything is pressed', () => { diff --git a/src/ui/cypress/integration/unauthenticated/credits.spec.ts b/src/ui/cypress/integration/unauthenticated/credits.spec.ts index 0ef8ad013a6..1e7c96df980 100644 --- a/src/ui/cypress/integration/unauthenticated/credits.spec.ts +++ b/src/ui/cypress/integration/unauthenticated/credits.spec.ts @@ -17,8 +17,7 @@ */ describe('Credits view', () => { - // Only need to load the page once for this test suite. - before(() => { + beforeEach(() => { cy.visit('/credits'); }); diff --git a/src/ui/cypress/support/utils/grpc.ts b/src/ui/cypress/support/utils/grpc.ts index 04e50049b9a..da42c072da0 100644 --- a/src/ui/cypress/support/utils/grpc.ts +++ b/src/ui/cypress/support/utils/grpc.ts @@ -16,7 +16,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { Interception, RouteHandler } from 'cypress/types/net-stubbing'; +import type { Interception, RouteHandler } from 'cypress/types/net-stubbing'; import { deserializeExecuteScriptRequest, deserializeExecuteScriptResponse } from 'app/testing/utils/grpc'; import { ExecuteScriptRequest, ExecuteScriptResponse } from 'app/types/generated/vizierapi_pb'; diff --git a/src/ui/cypress/tsconfig.json b/src/ui/cypress/tsconfig.json index 0e0fe1c963c..043c59a6234 100644 --- a/src/ui/cypress/tsconfig.json +++ b/src/ui/cypress/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": ["es5", "dom"], + "lib": ["es5", "es6", "dom", "es2016", "es2017", "es2018", "es2019", "es2020"], "types": ["cypress"], "baseUrl": ".", "paths": { diff --git a/src/ui/package.json b/src/ui/package.json index b8e118b4804..81427439d31 100644 --- a/src/ui/package.json +++ b/src/ui/package.json @@ -38,7 +38,7 @@ "compression-webpack-plugin": "^4.0.0", "concurrently": "^6.2.0", "css-loader": "^5.2.6", - "cypress": "^9.3.0", + "cypress": "^12.17.2", "esbuild": "^0.18.2", "esbuild-jest": "^0.5.0", "esbuild-loader": "^3.0.1", @@ -46,7 +46,7 @@ "eslint-config-airbnb-typescript": "^17.0.0", "eslint-import-resolver-node": "^0.3.7", "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-cypress": "^2.12.1", + "eslint-plugin-cypress": "^2.13.3", "eslint-plugin-import": "^2.27.5", "eslint-plugin-jest": "^27.2.1", "eslint-plugin-react": "^7.32.2", @@ -158,8 +158,10 @@ "coverage_ci": "jest --coverage --maxWorkers=4", "license_check": "yarn pnpify license-checker --relativeLicensePath", "lint": "yarn typecheck && eslint -c .eslintrc.json .", - "cypress:open": "cypress open", - "cypress:run": "cypress run" + "cypress:open:chrome": "cypress open --e2e --browser chrome", + "cypress:open:firefox": "cypress open --e2e --browser firefox", + "cypress:run:chrome": "cypress run --e2e --browser chrome", + "cypress:run:firefox": "cypress run --e2e --browser firefox" }, "resolutions": { "@types/react": "^18.0.9", diff --git a/src/ui/yarn.lock b/src/ui/yarn.lock index c9ee85f059c..5f2f666ce97 100644 --- a/src/ui/yarn.lock +++ b/src/ui/yarn.lock @@ -1451,7 +1451,7 @@ __metadata: languageName: node linkType: hard -"@cypress/request@npm:^2.88.10": +"@cypress/request@npm:^2.88.11": version: 2.88.12 resolution: "@cypress/request@npm:2.88.12" dependencies: @@ -2646,7 +2646,7 @@ __metadata: concurrently: ^6.2.0 cross-fetch: ^3.1.5 css-loader: ^5.2.6 - cypress: ^9.3.0 + cypress: ^12.17.2 date-fns: ^2.29.3 esbuild: ^0.18.2 esbuild-jest: ^0.5.0 @@ -2655,7 +2655,7 @@ __metadata: eslint-config-airbnb-typescript: ^17.0.0 eslint-import-resolver-node: ^0.3.7 eslint-import-resolver-typescript: ^3.5.5 - eslint-plugin-cypress: ^2.12.1 + eslint-plugin-cypress: ^2.13.3 eslint-plugin-import: ^2.27.5 eslint-plugin-jest: ^27.2.1 eslint-plugin-react: ^7.32.2 @@ -5496,10 +5496,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:^5.1.0": - version: 5.1.0 - resolution: "commander@npm:5.1.0" - checksum: 0b7fec1712fbcc6230fcb161d8d73b4730fa91a21dc089515489402ad78810547683f058e2a9835929c212fead1d6a6ade70db28bbb03edbc2829a9ab7d69447 +"commander@npm:^6.2.1": + version: 6.2.1 + resolution: "commander@npm:6.2.1" + checksum: d7090410c0de6bc5c67d3ca41c41760d6d268f3c799e530aafb73b7437d1826bbf0d2a3edac33f8b57cc9887b4a986dce307fa5557e109be40eadb7c43b21742 languageName: node linkType: hard @@ -5877,11 +5877,11 @@ __metadata: languageName: node linkType: hard -"cypress@npm:^9.3.0": - version: 9.3.0 - resolution: "cypress@npm:9.3.0" +"cypress@npm:^12.17.2": + version: 12.17.2 + resolution: "cypress@npm:12.17.2" dependencies: - "@cypress/request": ^2.88.10 + "@cypress/request": ^2.88.11 "@cypress/xvfb": ^1.2.4 "@types/node": ^14.14.31 "@types/sinonjs__fake-timers": 8.1.1 @@ -5895,12 +5895,12 @@ __metadata: 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 @@ -5913,19 +5913,19 @@ __metadata: listr2: ^3.8.3 lodash: ^4.17.21 log-symbols: ^4.0.0 - minimist: ^1.2.5 + minimist: ^1.2.8 ospath: ^1.2.2 pretty-bytes: ^5.6.0 proxy-from-env: 1.0.0 request-progress: ^3.0.0 + semver: ^7.5.3 supports-color: ^8.1.1 tmp: ~0.2.1 untildify: ^4.0.0 - url: ^0.11.0 yauzl: ^2.10.0 bin: cypress: bin/cypress - checksum: a40009b3dcb4c269f7d935b6c5a9c77feab1bb96e79d59684f153a3a53a1c059af60f5ca117438afb3812006c8914b8890d05541621dce494dfae141217a99ce + checksum: 19144db1fe02d92270de71f69ece324affd2f60bafa2f7018440c00907f837b1f8556926206df8b6e7b1c9890d250435730656ccb4a5a31e7872b24dd79c0af8 languageName: node linkType: hard @@ -7115,14 +7115,14 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-cypress@npm:^2.12.1": - version: 2.12.1 - resolution: "eslint-plugin-cypress@npm:2.12.1" +"eslint-plugin-cypress@npm:^2.13.3": + version: 2.13.3 + resolution: "eslint-plugin-cypress@npm:2.13.3" dependencies: globals: ^11.12.0 peerDependencies: eslint: ">= 3.2.1" - checksum: 1f1c36e149304e9a6f58e2292a761abad58274da33b3a48b24ad55ad20cbce3ac7467321f2b6fcb052f9563c89f67004de4766eba2e2bdbcb010a6a0666989cf + checksum: 9affbcee29e030a4251c4794f7533e8e8c0e3b98ab3470a2c730ed059f733c5857a04c7ac214cc0ca7aeef1b11242e72595de7fc1f6b8b4d4578d9eca10af203 languageName: node linkType: hard @@ -7359,10 +7359,10 @@ __metadata: languageName: node linkType: hard -"eventemitter2@npm:^6.4.3": - version: 6.4.5 - resolution: "eventemitter2@npm:6.4.5" - checksum: 84504f9cf0cc30205cdd46783fe9df3733435e5097f13070b678023110b5ef07847651808ae280cd94c42cd5976880211c7a40321a8ff8fa56f7c5f9c5c11960 +"eventemitter2@npm:6.4.7": + version: 6.4.7 + resolution: "eventemitter2@npm:6.4.7" + checksum: 1b36a77e139d6965ebf3a36c01fa00c089ae6b80faa1911e52888f40b3a7057b36a2cc45dcd1ad87cda3798fe7b97a0aabcbb8175a8b96092a23bb7d0f039e66 languageName: node linkType: hard @@ -11049,7 +11049,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.1.1, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6": +"minimist@npm:^1.1.1, minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6, minimist@npm:^1.2.8": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 @@ -12419,13 +12419,6 @@ __metadata: languageName: node linkType: hard -"punycode@npm:1.3.2": - version: 1.3.2 - resolution: "punycode@npm:1.3.2" - checksum: b8807fd594b1db33335692d1f03e8beeddde6fda7fbb4a2e32925d88d20a3aa4cd8dcc0c109ccaccbd2ba761c208dfaaada83007087ea8bfb0129c9ef1b99ed6 - languageName: node - linkType: hard - "punycode@npm:^2.1.0, punycode@npm:^2.1.1": version: 2.1.1 resolution: "punycode@npm:2.1.1" @@ -12463,13 +12456,6 @@ __metadata: languageName: node linkType: hard -"querystring@npm:0.2.0": - version: 0.2.0 - resolution: "querystring@npm:0.2.0" - checksum: 8258d6734f19be27e93f601758858c299bdebe71147909e367101ba459b95446fbe5b975bf9beb76390156a592b6f4ac3a68b6087cea165c259705b8b4e56a69 - languageName: node - linkType: hard - "querystringify@npm:^2.1.1": version: 2.2.0 resolution: "querystringify@npm:2.2.0" @@ -15072,16 +15058,6 @@ __metadata: languageName: node linkType: hard -"url@npm:^0.11.0": - version: 0.11.0 - resolution: "url@npm:0.11.0" - dependencies: - punycode: 1.3.2 - querystring: 0.2.0 - checksum: 50d100d3dd2d98b9fe3ada48cadb0b08aa6be6d3ac64112b867b56b19be4bfcba03c2a9a0d7922bfd7ac17d4834e88537749fe182430dfd9b68e520175900d90 - languageName: node - linkType: hard - "use-deep-compare-effect@npm:^1.8.0": version: 1.8.1 resolution: "use-deep-compare-effect@npm:1.8.1"