fix(testing): avoid overwriting environment variables in nx cypress preset (#20748)

This commit is contained in:
Craigory Coppola 2023-12-14 11:47:57 -05:00 committed by GitHub
parent cac2c173c5
commit d047ad5927
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 21 deletions

View File

@ -113,6 +113,9 @@ export default defineConfig({
...nxE2EPreset(__dirname), ...nxE2EPreset(__dirname),
fixturesFolder: undefined, 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' '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`); const run3 = runCLI(`e2e ${myapp}-e2e --no-watch`);

View File

@ -3,10 +3,19 @@ import { dirname, join, relative } from 'path';
import { lstatSync } from 'fs'; import { lstatSync } from 'fs';
import vitePreprocessor from '../src/plugins/preprocessor-vite'; import vitePreprocessor from '../src/plugins/preprocessor-vite';
import { NX_PLUGIN_OPTIONS } from '../src/utils/symbols';
import { exec } from 'child_process'; import { exec } from 'child_process';
import { request as httpRequest } from 'http'; import { request as httpRequest } from 'http';
import { request as httpsRequest } from 'https'; 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 { interface BaseCypressPreset {
videosFolder: string; videosFolder: string;
screenshotsFolder: string; screenshotsFolder: string;
@ -86,25 +95,35 @@ export function nxE2EPreset(
options?: NxCypressE2EPresetOptions options?: NxCypressE2EPresetOptions
) { ) {
const basePath = options?.cypressDir || 'src'; const basePath = options?.cypressDir || 'src';
const baseConfig: any /** Cypress.EndToEndConfigOptions */ = {
const baseConfig: any /*Cypress.EndToEndConfigOptions & {
[NX_PLUGIN_OPTIONS]: unknown;
}*/ = {
...nxBaseCypressPreset(pathToConfig), ...nxBaseCypressPreset(pathToConfig),
fileServerFolder: '.', fileServerFolder: '.',
supportFile: `${basePath}/support/e2e.ts`, supportFile: `${basePath}/support/e2e.ts`,
specPattern: `${basePath}/**/*.cy.{js,jsx,ts,tsx}`, specPattern: `${basePath}/**/*.cy.{js,jsx,ts,tsx}`,
fixturesFolder: `${basePath}/fixtures`, fixturesFolder: `${basePath}/fixtures`,
env: {
[NX_PLUGIN_OPTIONS]: {
webServerCommand: options?.webServerCommands?.default, webServerCommand: options?.webServerCommands?.default,
webServerCommands: options?.webServerCommands, webServerCommands: options?.webServerCommands,
ciWebServerCommand: options?.ciWebServerCommand, ciWebServerCommand: options?.ciWebServerCommand,
}, },
async setupNodeEvents(on, config) { async setupNodeEvents(on, config) {
const webServerCommands =
config.env?.webServerCommands ?? options?.webServerCommands;
const webServerCommand =
config.env?.webServerCommand ?? webServerCommands?.default;
if (options?.bundler === 'vite') { if (options?.bundler === 'vite') {
on('file:preprocessor', vitePreprocessor()); on('file:preprocessor', vitePreprocessor());
} }
if (!config.env.webServerCommands) {
if (!options?.webServerCommands) {
return; return;
} }
const webServerCommand = config.env.webServerCommand;
if (!webServerCommand) { if (!webServerCommand) {
return; return;
@ -216,7 +235,19 @@ export type NxCypressE2EPresetOptions = {
**/ **/
cypressDir?: string; cypressDir?: string;
/**
* A map of commandName -> command to start the web server for testing.
* Currently only default is read.
*/
webServerCommands?: Record<string, string>; webServerCommands?: Record<string, string>;
/**
* A command to start the web server - used for e2e tests distributed by Nx.
*/
ciWebServerCommand?: string; ciWebServerCommand?: string;
/**
* Configures how the web server command is started and monitored.
*/
webServerConfig?: WebServerConfig; webServerConfig?: WebServerConfig;
}; };

View File

@ -4,6 +4,7 @@ import { defineConfig } from 'cypress';
import { createNodes } from './plugin'; import { createNodes } from './plugin';
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
import { join } from 'path'; import { join } from 'path';
import { nxE2EPreset } from '../../plugins/cypress-preset';
describe('@nx/cypress/plugin', () => { describe('@nx/cypress/plugin', () => {
let createNodesFunction = createNodes[1]; let createNodesFunction = createNodes[1];
@ -15,8 +16,9 @@ describe('@nx/cypress/plugin', () => {
await tempFs.createFiles({ await tempFs.createFiles({
'package.json': '{}', 'package.json': '{}',
'test.cy.ts': '', 'src/test.cy.ts': '',
}); });
process.chdir(tempFs.tempDir);
context = { context = {
nxJsonConfiguration: { nxJsonConfiguration: {
// These defaults should be overridden by plugin // These defaults should be overridden by plugin
@ -44,12 +46,12 @@ describe('@nx/cypress/plugin', () => {
mockCypressConfig( mockCypressConfig(
defineConfig({ defineConfig({
e2e: { e2e: {
env: { ...nxE2EPreset('.', {
webServerCommands: { webServerCommands: {
default: 'nx run my-app:serve', default: 'nx run my-app:serve',
production: 'nx run my-app:serve:production', production: 'nx run my-app:serve:production',
}, },
}, }),
videosFolder: './dist/videos', videosFolder: './dist/videos',
screenshotsFolder: './dist/screenshots', screenshotsFolder: './dist/screenshots',
}, },
@ -162,13 +164,13 @@ describe('@nx/cypress/plugin', () => {
specPattern: '**/*.cy.ts', specPattern: '**/*.cy.ts',
videosFolder: './dist/videos', videosFolder: './dist/videos',
screenshotsFolder: './dist/screenshots', screenshotsFolder: './dist/screenshots',
env: { ...nxE2EPreset('.', {
webServerCommands: { webServerCommands: {
default: 'my-app:serve', default: 'my-app:serve',
production: 'my-app:serve:production', production: 'my-app:serve:production',
}, },
ciWebServerCommand: 'my-app:serve-static', ciWebServerCommand: 'my-app:serve-static',
}, }),
}, },
}) })
); );
@ -207,8 +209,8 @@ describe('@nx/cypress/plugin', () => {
"cwd": ".", "cwd": ".",
}, },
"outputs": [ "outputs": [
"{projectRoot}/dist/videos", "{projectRoot}/dist/cypress/videos",
"{projectRoot}/dist/screenshots", "{projectRoot}/dist/cypress/screenshots",
], ],
}, },
"e2e-ci": { "e2e-ci": {
@ -217,7 +219,7 @@ describe('@nx/cypress/plugin', () => {
{ {
"params": "forward", "params": "forward",
"projects": "self", "projects": "self",
"target": "e2e-ci--test.cy.ts", "target": "e2e-ci--src/test.cy.ts",
}, },
], ],
"executor": "nx:noop", "executor": "nx:noop",
@ -231,13 +233,13 @@ describe('@nx/cypress/plugin', () => {
}, },
], ],
"outputs": [ "outputs": [
"{projectRoot}/dist/videos", "{projectRoot}/dist/cypress/videos",
"{projectRoot}/dist/screenshots", "{projectRoot}/dist/cypress/screenshots",
], ],
}, },
"e2e-ci--test.cy.ts": { "e2e-ci--src/test.cy.ts": {
"cache": true, "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": [ "inputs": [
"default", "default",
"^production", "^production",
@ -251,8 +253,8 @@ describe('@nx/cypress/plugin', () => {
"cwd": ".", "cwd": ".",
}, },
"outputs": [ "outputs": [
"{projectRoot}/dist/videos", "{projectRoot}/dist/cypress/videos",
"{projectRoot}/dist/screenshots", "{projectRoot}/dist/cypress/screenshots",
], ],
}, },
}, },

View File

@ -19,6 +19,7 @@ import { existsSync, readdirSync } from 'fs';
import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context'; import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context';
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory'; import { projectGraphCacheDirectory } from 'nx/src/utils/cache-directory';
import { NX_PLUGIN_OPTIONS } from '../utils/symbols';
export interface CypressPluginOptions { export interface CypressPluginOptions {
ciTargetName?: string; ciTargetName?: string;
@ -147,13 +148,14 @@ function buildCypressTargets(
) { ) {
const cypressConfig = getCypressConfig(configFilePath, context); const cypressConfig = getCypressConfig(configFilePath, context);
const cypressEnv = { const pluginPresetOptions = {
...cypressConfig.e2e?.[NX_PLUGIN_OPTIONS],
...cypressConfig.env, ...cypressConfig.env,
...cypressConfig.e2e?.env, ...cypressConfig.e2e?.env,
}; };
const webServerCommands: Record<string, string> = const webServerCommands: Record<string, string> =
cypressEnv?.webServerCommands; pluginPresetOptions?.webServerCommands;
const relativeConfigPath = relative(projectRoot, configFilePath); const relativeConfigPath = relative(projectRoot, configFilePath);
@ -185,7 +187,7 @@ function buildCypressTargets(
} }
} }
const ciWebServerCommand: string = cypressEnv?.ciWebServerCommand; const ciWebServerCommand: string = pluginPresetOptions?.ciWebServerCommand;
if (ciWebServerCommand) { if (ciWebServerCommand) {
const specPatterns = Array.isArray(cypressConfig.e2e.specPattern) const specPatterns = Array.isArray(cypressConfig.e2e.specPattern)
? cypressConfig.e2e.specPattern.map((p) => join(projectRoot, p)) ? cypressConfig.e2e.specPattern.map((p) => join(projectRoot, p))

View File

@ -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');