From f4bdfe6480abb9f5f1268fe4498b7e0f2410b990 Mon Sep 17 00:00:00 2001 From: Jason Kuhrt Date: Fri, 14 Feb 2025 16:17:19 -0500 Subject: [PATCH] e2e tests that work --- cypress.config.ts | 5 +- .../laboratory-environment-variables.cy.ts | 64 +++++++++++-------- cypress/e2e/laboratory-preflight.cy.ts | 8 +-- cypress/support/e2e.ts | 1 + cypress/support/testkit.ts | 41 ++++++++++++ package.json | 1 + .../app/src/lib/preflight/graphiql-plugin.tsx | 2 - pnpm-lock.yaml | 13 ++++ 8 files changed, 103 insertions(+), 32 deletions(-) diff --git a/cypress.config.ts b/cypress.config.ts index 41ac7a1225..3d20a57d9f 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,6 +1,7 @@ import * as fs from 'node:fs'; // eslint-disable-next-line import/no-extraneous-dependencies -- cypress SHOULD be a dev dependency import { defineConfig } from 'cypress'; +import cypressPluginLocalStorageCommands from 'cypress-localstorage-commands/plugin'; import { initSeed } from './integration-tests/testkit/seed'; if (!process.env.RUN_AGAINST_LOCAL_SERVICES) { @@ -25,7 +26,9 @@ export default defineConfig({ defaultCommandTimeout: 15_000, // sometimes the app takes longer to load, especially in the CI retries: isCI ? 2 : 0, e2e: { - setupNodeEvents(on) { + setupNodeEvents(on, config) { + cypressPluginLocalStorageCommands(on, config); + on('task', { async seedTarget() { const owner = await seed.createOwner(); diff --git a/cypress/e2e/laboratory-environment-variables.cy.ts b/cypress/e2e/laboratory-environment-variables.cy.ts index b65134d1da..4f4796e3fe 100644 --- a/cypress/e2e/laboratory-environment-variables.cy.ts +++ b/cypress/e2e/laboratory-environment-variables.cy.ts @@ -1,3 +1,9 @@ +import { persistAuthenticationCookies } from '../support/testkit'; + +Cypress.Cookies.debug(true); + +const as = <$Type>() => undefined as $Type; + const selectors = { editorEnvironmentVariables: '[data-cy="preflight-editor-mini"]', buttonGraphiQLPreflight: '[aria-label*="Preflight Script"]', @@ -30,55 +36,63 @@ const data = { envarsJson: '{"foo":"123"}', }; -const as = <$Type>() => undefined as $Type; - const ctx = { - // test export interfaces from testKit + // todo get an exported type from testKit targetDevelopment: as<{ id: string; slug: string; path: string }>(), targetProduction: as<{ id: string; slug: string; path: string }>(), + cookies: [] as Cypress.Cookie[], }; before(() => { - cy.clearLocalStorage().then(async () => { - cy.task('seedTarget').then(({ refreshToken, targets }: any) => { - cy.setCookie('sRefreshToken', refreshToken); - ctx.targetDevelopment = targets.development; - ctx.targetProduction = targets.production; - }); + cy.task('seedTarget').then(({ refreshToken, targets }: any) => { + cy.setCookie('sRefreshToken', refreshToken); + ctx.targetDevelopment = targets.development; + ctx.targetProduction = targets.production; }); }); -const visitTargetDevelopment = () => cy.visit(`/${ctx.targetDevelopment.path}/laboratory`); -const visitTargetProduction = () => cy.visit(`/${ctx.targetProduction.path}/laboratory`); +persistAuthenticationCookies(); + +const visitTargetDevelopment = () => cy.visit(`${ctx.targetDevelopment.path}/laboratory`); +// const visitTargetProduction = () => cy.visit(`${ctx.targetProduction.path}/laboratory`); + const openPreflightTab = () => cy.get(selectors.buttonGraphiQLPreflight).click(); +const storageGlobalGet = () => cy.getLocalStorage(environmentVariablesStorageKey.global); +const storageGlobalSet = (value: string) => cy.setLocalStorage(environmentVariablesStorageKey.global, value); // prettier-ignore + +const storageTargetDevelopmentGet = () => cy.getLocalStorage(environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id)); // prettier-ignore +const storageTargetDevelopmentSet = (value: string) => cy.setLocalStorage(environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id), value); // prettier-ignore + +beforeEach(() => { + cy.removeLocalStorage(environmentVariablesStorageKey.global); + cy.removeLocalStorage(environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id)); + cy.removeLocalStorage(environmentVariablesStorageKey.scoped(ctx.targetProduction.id)); +}); + describe('tab editor', () => { it('if state empty, is null', () => { visitTargetDevelopment(); openPreflightTab(); - expect( - window.localStorage.getItem( - environmentVariablesStorageKey.scoped(ctx.targetDevelopment.slug), - ), - ).equals(null); - expect(window.localStorage.getItem(environmentVariablesStorageKey.global)).equals(null); - // cy.dataCy('preflight-editor-mini').should('have.text', ''); + storageTargetDevelopmentGet().should('equal', null); + storageGlobalGet().should('equal', null); }); - it('if state just global value, shows that', () => { - window.localStorage.setItem(environmentVariablesStorageKey.global, data.envarsJson); + it('if state just scoped value, shows that', () => { + storageTargetDevelopmentSet(data.envarsJson); visitTargetDevelopment(); openPreflightTab(); cy.contains(data.envarsJson); + storageGlobalGet().should('equal', null); }); - it.only('if state just scoped value, shows that', () => { - window.localStorage.setItem( - environmentVariablesStorageKey.scoped(ctx.targetDevelopment.id), - data.envarsJson, - ); + it('if state just global value, copied to scoped, shows that', () => { + storageTargetDevelopmentGet().should('equal', null); + storageGlobalSet(data.envarsJson); visitTargetDevelopment(); openPreflightTab(); cy.contains(data.envarsJson); + storageTargetDevelopmentGet().should('equal', data.envarsJson); + storageGlobalGet().should('equal', data.envarsJson); }); }); diff --git a/cypress/e2e/laboratory-preflight.cy.ts b/cypress/e2e/laboratory-preflight.cy.ts index 645dd3931f..919d831bc7 100644 --- a/cypress/e2e/laboratory-preflight.cy.ts +++ b/cypress/e2e/laboratory-preflight.cy.ts @@ -17,15 +17,15 @@ const selectors = { }, }; -const data: { slug: string } = { - slug: '', +const ctx = { + targetSlug: '', }; beforeEach(() => { cy.clearLocalStorage().then(async () => { cy.task('seedTarget').then(({ slug, refreshToken }: any) => { cy.setCookie('sRefreshToken', refreshToken); - data.slug = slug; + ctx.targetSlug = slug; cy.visit(`/${slug}/laboratory`); cy.get(selectors.buttonGraphiQLPreflight).click(); }); @@ -59,7 +59,7 @@ describe('Laboratory > Preflight Script', () => { // https://github.com/graphql-hive/console/pull/6450 it('regression: loads even if local storage is set to {}', () => { window.localStorage.setItem('hive:laboratory:environment', '{}'); - cy.visit(`/${data.slug}/laboratory`); + cy.visit(`/${ctx.targetSlug}/laboratory`); cy.get(selectors.buttonGraphiQLPreflight).click(); }); it('mini script editor is read only', () => { diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index 7149352f73..94986a1df5 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -1,4 +1,5 @@ import './commands'; +import 'cypress-localstorage-commands'; Cypress.on('uncaught:exception', (_err, _runnable) => { return false; diff --git a/cypress/support/testkit.ts b/cypress/support/testkit.ts index 44f20faae2..7a00cb3307 100644 --- a/cypress/support/testkit.ts +++ b/cypress/support/testkit.ts @@ -1,3 +1,44 @@ +export function persistAuthenticationCookies() { + const ctx = { + cookies: [] as Cypress.Cookie[], + }; + + before(() => { + cy.getCookie('sRefreshToken').should('exist'); + cy.visit('/'); + cy.wait(2000); + + cy.getCookie('sAccessToken').should('exist'); + cy.getCookie('sFrontToken').should('exist'); + cy.getCookie('st-last-access-token-update').should('exist'); + + cy.getCookie('sAccessToken').then(sAccessToken => { + ctx.cookies.push(sAccessToken); + }); + cy.getCookie('sFrontToken').then(sFrontToken => { + ctx.cookies.push(sFrontToken); + }); + cy.getCookie('sRefreshToken').then(sRefreshToken => { + ctx.cookies.push(sRefreshToken); + }); + + cy.getCookie('st-last-access-token-update').then(stLastAccessTokenUpdate => { + ctx.cookies.push(stLastAccessTokenUpdate); + }); + + cy.clearCookie('st-last-access-token-update'); + cy.clearCookie('sRefreshToken'); + cy.clearCookie('sAccessToken'); + cy.clearCookie('sFrontToken'); + }); + + beforeEach(() => { + ctx.cookies.forEach(cookie => { + cy.setCookie(cookie.name, cookie.value, cookie); + }); + }); +} + export function generateRandomSlug() { return Math.random().toString(36).substring(2); } diff --git a/package.json b/package.json index 3773cbd104..dfb46f06a2 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@types/node": "22.10.5", "bob-the-bundler": "7.0.1", "cypress": "13.17.0", + "cypress-localstorage-commands": "^2.2.7", "dotenv": "16.4.7", "eslint": "8.57.1", "eslint-plugin-cypress": "4.1.0", diff --git a/packages/web/app/src/lib/preflight/graphiql-plugin.tsx b/packages/web/app/src/lib/preflight/graphiql-plugin.tsx index 4d7b3af1fd..1f96fe0c69 100644 --- a/packages/web/app/src/lib/preflight/graphiql-plugin.tsx +++ b/packages/web/app/src/lib/preflight/graphiql-plugin.tsx @@ -160,8 +160,6 @@ export function usePreflight(args: { const target = useFragment(PreflightScript_TargetFragment, args.target); const [isEnabled, setIsEnabled] = useLocalStorageJson( - // todo - // 'hive:laboratory:isPreflightEnabled', 'hive:laboratory:isPreflightScriptEnabled', z.boolean().default(false), ); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26a9451b34..576e6e6b8a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -137,6 +137,9 @@ importers: cypress: specifier: 13.17.0 version: 13.17.0 + cypress-localstorage-commands: + specifier: ^2.2.7 + version: 2.2.7(cypress@13.17.0) dotenv: specifier: 16.4.7 version: 16.4.7 @@ -9397,6 +9400,12 @@ packages: csv-stringify@6.5.2: resolution: {integrity: sha512-RFPahj0sXcmUyjrObAK+DOWtMvMIFV328n4qZJhgX3x2RqkQgOTU2mCUmiFR0CzM6AzChlRSUErjiJeEt8BaQA==} + cypress-localstorage-commands@2.2.7: + resolution: {integrity: sha512-hUe6hz/3TD9Ph70CUHJLSiTzL0INikUQ4W3CRd7XmaGCDjwR6jGAlvTCGmxZ6yGc4Mq/WN6L8xJAu+dOrIvYCA==} + engines: {node: '>=14.0.0'} + peerDependencies: + cypress: '>=2.1.0' + cypress@13.17.0: resolution: {integrity: sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==} engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} @@ -26078,6 +26087,10 @@ snapshots: csv-stringify@6.5.2: {} + cypress-localstorage-commands@2.2.7(cypress@13.17.0): + dependencies: + cypress: 13.17.0 + cypress@13.17.0: dependencies: '@cypress/request': 3.0.6