From d047ad5927164494d2fd0ce9a3f61b35b35de6e9 Mon Sep 17 00:00:00 2001 From: Craigory Coppola Date: Thu, 14 Dec 2023 11:47:57 -0500 Subject: [PATCH] fix(testing): avoid overwriting environment variables in nx cypress preset (#20748) --- e2e/cypress/src/cypress.test.ts | 10 ++++++ packages/cypress/plugins/cypress-preset.ts | 39 ++++++++++++++++++--- packages/cypress/src/plugins/plugin.spec.ts | 30 ++++++++-------- packages/cypress/src/plugins/plugin.ts | 8 +++-- packages/cypress/src/utils/symbols.ts | 4 +++ 5 files changed, 70 insertions(+), 21 deletions(-) create mode 100644 packages/cypress/src/utils/symbols.ts diff --git a/e2e/cypress/src/cypress.test.ts b/e2e/cypress/src/cypress.test.ts index 5a9f532f03..56b2db3826 100644 --- a/e2e/cypress/src/cypress.test.ts +++ b/e2e/cypress/src/cypress.test.ts @@ -113,6 +113,9 @@ export default defineConfig({ ...nxE2EPreset(__dirname), fixturesFolder: undefined, }, + env: { + fromCyConfig: 'i am from the cypress config file' + } });` ); @@ -144,6 +147,13 @@ describe('env vars', () => { 'i am from the nx project json file' ); }); + + it('should have cypress config vars', () => { + assert.equal( + Cypress.env('fromCyConfig'), + 'i am from the cypress config file' + ); + }); });` ); const run3 = runCLI(`e2e ${myapp}-e2e --no-watch`); diff --git a/packages/cypress/plugins/cypress-preset.ts b/packages/cypress/plugins/cypress-preset.ts index 3ef5576251..54fc3a61e7 100644 --- a/packages/cypress/plugins/cypress-preset.ts +++ b/packages/cypress/plugins/cypress-preset.ts @@ -3,10 +3,19 @@ import { dirname, join, relative } from 'path'; import { lstatSync } from 'fs'; import vitePreprocessor from '../src/plugins/preprocessor-vite'; +import { NX_PLUGIN_OPTIONS } from '../src/utils/symbols'; + import { exec } from 'child_process'; import { request as httpRequest } from 'http'; import { request as httpsRequest } from 'https'; +// Importing the cypress type here causes the angular and next unit +// tests to fail when transpiling, it seems like the cypress types are +// clobbering jest's types. A bit weird. Leaving the commented out import +// and usage, as its helpful when modifying this code. +// +// import type * as Cypress from 'cypress'; + interface BaseCypressPreset { videosFolder: string; screenshotsFolder: string; @@ -86,25 +95,35 @@ export function nxE2EPreset( options?: NxCypressE2EPresetOptions ) { const basePath = options?.cypressDir || 'src'; - const baseConfig: any /** Cypress.EndToEndConfigOptions */ = { + + const baseConfig: any /*Cypress.EndToEndConfigOptions & { + [NX_PLUGIN_OPTIONS]: unknown; + }*/ = { ...nxBaseCypressPreset(pathToConfig), fileServerFolder: '.', supportFile: `${basePath}/support/e2e.ts`, specPattern: `${basePath}/**/*.cy.{js,jsx,ts,tsx}`, fixturesFolder: `${basePath}/fixtures`, - env: { + + [NX_PLUGIN_OPTIONS]: { webServerCommand: options?.webServerCommands?.default, webServerCommands: options?.webServerCommands, ciWebServerCommand: options?.ciWebServerCommand, }, + async setupNodeEvents(on, config) { + const webServerCommands = + config.env?.webServerCommands ?? options?.webServerCommands; + const webServerCommand = + config.env?.webServerCommand ?? webServerCommands?.default; + if (options?.bundler === 'vite') { on('file:preprocessor', vitePreprocessor()); } - if (!config.env.webServerCommands) { + + if (!options?.webServerCommands) { return; } - const webServerCommand = config.env.webServerCommand; if (!webServerCommand) { return; @@ -216,7 +235,19 @@ export type NxCypressE2EPresetOptions = { **/ cypressDir?: string; + /** + * A map of commandName -> command to start the web server for testing. + * Currently only default is read. + */ webServerCommands?: Record; + + /** + * A command to start the web server - used for e2e tests distributed by Nx. + */ ciWebServerCommand?: string; + + /** + * Configures how the web server command is started and monitored. + */ webServerConfig?: WebServerConfig; }; diff --git a/packages/cypress/src/plugins/plugin.spec.ts b/packages/cypress/src/plugins/plugin.spec.ts index e57776a2cb..ba8c50c71d 100644 --- a/packages/cypress/src/plugins/plugin.spec.ts +++ b/packages/cypress/src/plugins/plugin.spec.ts @@ -4,6 +4,7 @@ import { defineConfig } from 'cypress'; import { createNodes } from './plugin'; import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; import { join } from 'path'; +import { nxE2EPreset } from '../../plugins/cypress-preset'; describe('@nx/cypress/plugin', () => { let createNodesFunction = createNodes[1]; @@ -15,8 +16,9 @@ describe('@nx/cypress/plugin', () => { await tempFs.createFiles({ 'package.json': '{}', - 'test.cy.ts': '', + 'src/test.cy.ts': '', }); + process.chdir(tempFs.tempDir); context = { nxJsonConfiguration: { // These defaults should be overridden by plugin @@ -44,12 +46,12 @@ describe('@nx/cypress/plugin', () => { mockCypressConfig( defineConfig({ e2e: { - env: { + ...nxE2EPreset('.', { webServerCommands: { default: 'nx run my-app:serve', production: 'nx run my-app:serve:production', }, - }, + }), videosFolder: './dist/videos', screenshotsFolder: './dist/screenshots', }, @@ -162,13 +164,13 @@ describe('@nx/cypress/plugin', () => { specPattern: '**/*.cy.ts', videosFolder: './dist/videos', screenshotsFolder: './dist/screenshots', - env: { + ...nxE2EPreset('.', { webServerCommands: { default: 'my-app:serve', production: 'my-app:serve:production', }, ciWebServerCommand: 'my-app:serve-static', - }, + }), }, }) ); @@ -207,8 +209,8 @@ describe('@nx/cypress/plugin', () => { "cwd": ".", }, "outputs": [ - "{projectRoot}/dist/videos", - "{projectRoot}/dist/screenshots", + "{projectRoot}/dist/cypress/videos", + "{projectRoot}/dist/cypress/screenshots", ], }, "e2e-ci": { @@ -217,7 +219,7 @@ describe('@nx/cypress/plugin', () => { { "params": "forward", "projects": "self", - "target": "e2e-ci--test.cy.ts", + "target": "e2e-ci--src/test.cy.ts", }, ], "executor": "nx:noop", @@ -231,13 +233,13 @@ describe('@nx/cypress/plugin', () => { }, ], "outputs": [ - "{projectRoot}/dist/videos", - "{projectRoot}/dist/screenshots", + "{projectRoot}/dist/cypress/videos", + "{projectRoot}/dist/cypress/screenshots", ], }, - "e2e-ci--test.cy.ts": { + "e2e-ci--src/test.cy.ts": { "cache": true, - "command": "cypress run --config-file cypress.config.js --e2e --env webServerCommand="my-app:serve-static" --spec test.cy.ts", + "command": "cypress run --config-file cypress.config.js --e2e --env webServerCommand="my-app:serve-static" --spec src/test.cy.ts", "inputs": [ "default", "^production", @@ -251,8 +253,8 @@ describe('@nx/cypress/plugin', () => { "cwd": ".", }, "outputs": [ - "{projectRoot}/dist/videos", - "{projectRoot}/dist/screenshots", + "{projectRoot}/dist/cypress/videos", + "{projectRoot}/dist/cypress/screenshots", ], }, }, diff --git a/packages/cypress/src/plugins/plugin.ts b/packages/cypress/src/plugins/plugin.ts index 0a97ae00a1..6e05c9185d 100644 --- a/packages/cypress/src/plugins/plugin.ts +++ b/packages/cypress/src/plugins/plugin.ts @@ -19,6 +19,7 @@ import { existsSync, readdirSync } from 'fs'; import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context'; import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory'; +import { NX_PLUGIN_OPTIONS } from '../utils/symbols'; export interface CypressPluginOptions { ciTargetName?: string; @@ -147,13 +148,14 @@ function buildCypressTargets( ) { const cypressConfig = getCypressConfig(configFilePath, context); - const cypressEnv = { + const pluginPresetOptions = { + ...cypressConfig.e2e?.[NX_PLUGIN_OPTIONS], ...cypressConfig.env, ...cypressConfig.e2e?.env, }; const webServerCommands: Record = - cypressEnv?.webServerCommands; + pluginPresetOptions?.webServerCommands; const relativeConfigPath = relative(projectRoot, configFilePath); @@ -185,7 +187,7 @@ function buildCypressTargets( } } - const ciWebServerCommand: string = cypressEnv?.ciWebServerCommand; + const ciWebServerCommand: string = pluginPresetOptions?.ciWebServerCommand; if (ciWebServerCommand) { const specPatterns = Array.isArray(cypressConfig.e2e.specPattern) ? cypressConfig.e2e.specPattern.map((p) => join(projectRoot, p)) diff --git a/packages/cypress/src/utils/symbols.ts b/packages/cypress/src/utils/symbols.ts new file mode 100644 index 0000000000..f72080df39 --- /dev/null +++ b/packages/cypress/src/utils/symbols.ts @@ -0,0 +1,4 @@ +/** + * Key used to store options used by the nx plugin for @nx/cypress. + */ +export const NX_PLUGIN_OPTIONS = Symbol('Nx Plugin Options');