From b892d66a8621672eb4c227bb96204c95933dd327 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Tue, 27 Aug 2024 15:00:43 +0100 Subject: [PATCH] fix(testing): application generators should accurately configure e2e projects (#27453) - feat(devkit): add util for determining the e2e web server info - feat(vite): add util for determining the e2e web server info - feat(webpack): add util for determining the e2e web server info - fix(webpack): allow port override - fix(devkit): e2e web server info util should handle target defaults - feat(webpack): export the e2e web server info utils - fix(vite): rename util - fix(devkit): util should determine the devTarget for cypress - fix(react): improve accuracy of e2e project generation ## Current Behavior The logic for finding the correct targets and web addresses to use when setting up e2e projects is flawed and missing some key considerations. ## Expected Behavior The logic is accurate and usage is simplified across plugins Projects: - [x] Angular - [x] Expo - [x] Next - [x] Nuxt - [x] Vue - [x] Web - [x] Remix - [x] React - [x] React Native ## Related Issue(s) Fixes # (cherry picked from commit 320d9f223f79fd5ec6ef5b8cf657dad72b09bd26) --- .../packages/expo/generators/application.json | 2 +- e2e/web/src/file-server-legacy.test.ts | 8 - .../src/generators/application/lib/add-e2e.ts | 64 ++++- .../application/lib/normalize-options.ts | 15 -- .../application/lib/normalized-schema.ts | 3 - .../e2e-web-server-info-utils.spec.ts | 248 ++++++++++++++++++ .../generators/e2e-web-server-info-utils.ts | 126 +++++++++ .../src/generators/application/lib/add-e2e.ts | 80 ++++-- .../application/lib/normalize-options.spec.ts | 15 -- .../application/lib/normalize-options.ts | 33 +-- .../src/generators/application/schema.json | 2 +- .../src/generators/application/lib/add-e2e.ts | 63 ++++- .../application/lib/add-linting.spec.ts | 3 - .../application/lib/normalize-options.ts | 34 --- .../src/generators/application/lib/add-e2e.ts | 62 ++++- .../application/lib/normalize-options.ts | 24 -- .../src/generators/application/schema.d.ts | 3 - .../src/generators/application/lib/add-e2e.ts | 4 - .../application/lib/normalize-options.spec.ts | 15 -- .../application/lib/normalize-options.ts | 32 --- .../application/application.spec.ts | 2 +- .../src/generators/application/lib/add-e2e.ts | 63 ++++- .../application/lib/normalize-options.ts | 54 ---- .../src/generators/application/schema.d.ts | 5 - .../application.impl.spec.ts.snap | 27 +- .../application/application.impl.ts | 2 +- .../src/generators/application/lib/add-e2e.ts | 67 ++++- .../application/lib/normalize-options.ts | 33 --- .../plugins/__snapshots__/plugin.spec.ts.snap | 18 ++ packages/remix/src/plugins/plugin.ts | 12 + packages/vite/index.ts | 1 + .../utils/e2e-web-server-info-utils.spec.ts | 149 +++++++++++ .../src/utils/e2e-web-server-info-utils.ts | 39 +++ .../__snapshots__/application.spec.ts.snap | 6 +- .../src/generators/application/lib/add-e2e.ts | 43 +-- .../application/application.spec.ts | 13 +- .../src/generators/application/application.ts | 115 ++++---- packages/webpack/index.ts | 1 + .../utils/e2e-web-server-info-utils.spec.ts | 149 +++++++++++ .../src/utils/e2e-web-server-info-utils.ts | 39 +++ 40 files changed, 1220 insertions(+), 454 deletions(-) create mode 100644 packages/devkit/src/generators/e2e-web-server-info-utils.spec.ts create mode 100644 packages/devkit/src/generators/e2e-web-server-info-utils.ts create mode 100644 packages/vite/src/utils/e2e-web-server-info-utils.spec.ts create mode 100644 packages/vite/src/utils/e2e-web-server-info-utils.ts create mode 100644 packages/webpack/src/utils/e2e-web-server-info-utils.spec.ts create mode 100644 packages/webpack/src/utils/e2e-web-server-info-utils.ts diff --git a/docs/generated/packages/expo/generators/application.json b/docs/generated/packages/expo/generators/application.json index de17035d2ab38..c9648c5cf6c07 100644 --- a/docs/generated/packages/expo/generators/application.json +++ b/docs/generated/packages/expo/generators/application.json @@ -76,7 +76,7 @@ "description": "Adds the specified e2e test runner", "type": "string", "enum": ["playwright", "cypress", "detox", "none"], - "default": "playwright" + "default": "none" }, "standaloneConfig": { "description": "Split the project configuration into `/project.json` rather than including it inside `workspace.json`.", diff --git a/e2e/web/src/file-server-legacy.test.ts b/e2e/web/src/file-server-legacy.test.ts index b2971f76def3f..ae7c105442d32 100644 --- a/e2e/web/src/file-server-legacy.test.ts +++ b/e2e/web/src/file-server-legacy.test.ts @@ -35,14 +35,6 @@ describe('file-server', () => { }, } ); - runCLI( - `generate @nx/web:static-config --buildTarget=${ngAppName}:build --outputPath=dist/apps/${ngAppName}/browser --no-interactive`, - { - env: { - NX_ADD_PLUGINS: 'false', - }, - } - ); runCLI( `generate @nx/web:static-config --buildTarget=${reactAppName}:build --targetName=custom-serve-static --no-interactive`, { diff --git a/packages/angular/src/generators/application/lib/add-e2e.ts b/packages/angular/src/generators/application/lib/add-e2e.ts index 7c3de1a055e27..717ea779862be 100644 --- a/packages/angular/src/generators/application/lib/add-e2e.ts +++ b/packages/angular/src/generators/application/lib/add-e2e.ts @@ -1,4 +1,4 @@ -import type { Tree } from '@nx/devkit'; +import { Tree } from '@nx/devkit'; import { addDependenciesToPackageJson, addProjectConfiguration, @@ -13,6 +13,7 @@ import { nxVersion } from '../../../utils/versions'; import { getInstalledAngularVersionInfo } from '../../utils/version-utils'; import type { NormalizedSchema } from './normalized-schema'; import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; +import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; export async function addE2e(tree: Tree, options: NormalizedSchema) { // since e2e are separate projects, default to adding plugins @@ -21,12 +22,19 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) { process.env.NX_ADD_PLUGINS !== 'false' && nxJson.useInferencePlugins !== false; + const e2eWebServerInfo = getAngularE2EWebServerInfo( + tree, + options.name, + options.port + ); + // TODO: This can call `@nx/web:static-config` generator when ready + addFileServerTarget(tree, options, 'serve-static', e2eWebServerInfo.e2ePort); + if (options.e2eTestRunner === 'cypress') { const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); - // TODO: This can call `@nx/web:static-config` generator when ready - addFileServerTarget(tree, options, 'serve-static'); + addProjectConfiguration(tree, options.e2eProjectName, { projectType: 'application', root: options.e2eProjectRoot, @@ -41,8 +49,14 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) { linter: options.linter, skipPackageJson: options.skipPackageJson, skipFormat: true, - devServerTarget: `${options.name}:${options.e2eWebServerTarget}:development`, - baseUrl: options.e2eWebServerAddress, + devServerTarget: e2eWebServerInfo.e2eDevServerTarget, + baseUrl: e2eWebServerInfo.e2eWebServerAddress, + webServerCommands: { + default: e2eWebServerInfo.e2eWebServerCommand, + production: e2eWebServerInfo.e2eCiWebServerCommand, + }, + ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl, rootProject: options.rootProject, addPlugin, }); @@ -73,10 +87,8 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) { js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, - webServerCommand: `${getPackageManagerCommand().exec} nx ${ - options.e2eWebServerTarget - } ${options.name}`, - webServerAddress: options.e2eWebServerAddress, + webServerCommand: e2eWebServerInfo.e2eWebServerCommand, + webServerAddress: e2eWebServerInfo.e2eWebServerAddress, rootProject: options.rootProject, addPlugin, }); @@ -94,7 +106,8 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) { function addFileServerTarget( tree: Tree, options: NormalizedSchema, - targetName: string + targetName: string, + e2ePort: number ) { if (!options.skipPackageJson) { addDependenciesToPackageJson(tree, {}, { '@nx/web': nxVersion }); @@ -109,7 +122,7 @@ function addFileServerTarget( executor: '@nx/web:file-server', options: { buildTarget: `${options.name}:build`, - port: options.e2ePort, + port: e2ePort, staticFilePath: isUsingApplicationBuilder ? joinPathFragments(options.outputPath, 'browser') : undefined, @@ -118,3 +131,32 @@ function addFileServerTarget( }; updateProjectConfiguration(tree, options.name, projectConfig); } + +function getAngularE2EWebServerInfo( + tree: Tree, + projectName: string, + portOverride: number +): E2EWebServerDetails & { e2ePort: number } { + const nxJson = readNxJson(tree); + let e2ePort = portOverride ?? 4200; + + if ( + nxJson.targetDefaults?.['serve'] && + (nxJson.targetDefaults?.['serve'].options?.port || + nxJson.targetDefaults?.['serve'].options?.env?.PORT) + ) { + e2ePort = + nxJson.targetDefaults?.['serve'].options?.port || + nxJson.targetDefaults?.['serve'].options?.env?.PORT; + } + + const pm = getPackageManagerCommand(); + return { + e2eCiBaseUrl: 'http://localhost:4200', + e2eCiWebServerCommand: `${pm.exec} nx run ${projectName}:serve-static`, + e2eWebServerCommand: `${pm.exec} nx run ${projectName}:serve`, + e2eWebServerAddress: `http://localhost:${e2ePort}`, + e2eDevServerTarget: `${projectName}:serve`, + e2ePort, + }; +} diff --git a/packages/angular/src/generators/application/lib/normalize-options.ts b/packages/angular/src/generators/application/lib/normalize-options.ts index 41e4993561ce0..8ecc6276d1a3c 100644 --- a/packages/angular/src/generators/application/lib/normalize-options.ts +++ b/packages/angular/src/generators/application/lib/normalize-options.ts @@ -26,21 +26,9 @@ export async function normalizeOptions( options.projectNameAndRootFormat = projectNameAndRootFormat; const nxJson = readNxJson(host); - let e2eWebServerTarget = 'serve'; - let e2ePort = options.port ?? 4200; - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - (nxJson.targetDefaults?.[e2eWebServerTarget].options?.port || - nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT) - ) { - e2ePort = - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port || - nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT; - } const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`; const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) @@ -72,9 +60,6 @@ export async function normalizeOptions( appProjectSourceRoot: `${appProjectRoot}/src`, e2eProjectRoot, e2eProjectName, - e2eWebServerAddress, - e2eWebServerTarget, - e2ePort, parsedTags, bundler, outputPath: joinPathFragments( diff --git a/packages/angular/src/generators/application/lib/normalized-schema.ts b/packages/angular/src/generators/application/lib/normalized-schema.ts index ff3f2d0034f00..30ac5e19e0297 100644 --- a/packages/angular/src/generators/application/lib/normalized-schema.ts +++ b/packages/angular/src/generators/application/lib/normalized-schema.ts @@ -12,9 +12,6 @@ export interface NormalizedSchema extends Schema { appProjectSourceRoot: string; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2ePort: number; parsedTags: string[]; outputPath: string; } diff --git a/packages/devkit/src/generators/e2e-web-server-info-utils.spec.ts b/packages/devkit/src/generators/e2e-web-server-info-utils.spec.ts new file mode 100644 index 0000000000000..20f09b749e6c2 --- /dev/null +++ b/packages/devkit/src/generators/e2e-web-server-info-utils.spec.ts @@ -0,0 +1,248 @@ +import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; +import { type Tree, readNxJson, updateNxJson } from 'nx/src/devkit-exports'; +import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; +import { getE2EWebServerInfo } from './e2e-web-server-info-utils'; + +describe('getE2EWebServerInfo', () => { + let tree: Tree; + let tempFs: TempFs; + beforeEach(() => { + tempFs = new TempFs('e2e-webserver-info'); + tree = createTreeWithEmptyWorkspace(); + tree.root = tempFs.tempDir; + + tree.write(`app/vite.config.ts`, ``); + tempFs.createFileSync(`app/vite.config.ts`, ``); + }); + + afterEach(() => { + tempFs.cleanup(); + jest.resetModules(); + }); + + it('should use the default values when no plugin is registered and plugins are not being used', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getE2EWebServerInfo( + tree, + 'app', + { + plugin: '@nx/vite/plugin', + configFilePath: 'app/vite.config.ts', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'previewTargetName', + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'preview', + defaultE2EWebServerAddress: 'http://localhost:4200', + defaultE2ECiBaseUrl: 'http://localhost:4300', + defaultE2EPort: 4200, + }, + false + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:preview", + "e2eDevServerTarget": "app:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:serve", + } + `); + }); + + it('should use the default values of the plugin when the plugin is just a string', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins = ['@nx/vite/plugin']; + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getE2EWebServerInfo( + tree, + 'app', + { + plugin: '@nx/vite/plugin', + configFilePath: 'app/vite.config.ts', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'previewTargetName', + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'preview', + defaultE2EWebServerAddress: 'http://localhost:4200', + defaultE2ECiBaseUrl: 'http://localhost:4300', + defaultE2EPort: 4200, + }, + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:preview", + "e2eDevServerTarget": "app:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:serve", + } + `); + }); + + it('should use the values of the registered plugin when there is no includes or excludes defined', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + nxJson.plugins.push({ + plugin: '@nx/vite/plugin', + options: { + serveTargetName: 'vite:serve', + previewTargetName: 'vite:preview', + }, + }); + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getE2EWebServerInfo( + tree, + 'app', + { + plugin: '@nx/vite/plugin', + configFilePath: 'app/vite.config.ts', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'previewTargetName', + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'preview', + defaultE2EWebServerAddress: 'http://localhost:4200', + defaultE2ECiBaseUrl: 'http://localhost:4300', + defaultE2EPort: 4200, + }, + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:vite:preview", + "e2eDevServerTarget": "app:vite:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:vite:serve", + } + `); + }); + + it('should handle targetDefaults', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + nxJson.plugins.push({ + plugin: '@nx/vite/plugin', + options: { + serveTargetName: 'vite:serve', + previewTargetName: 'vite:preview', + }, + }); + nxJson.targetDefaults ??= {}; + nxJson.targetDefaults['vite:serve'] = { + options: { + port: 4400, + }, + }; + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getE2EWebServerInfo( + tree, + 'app', + { + plugin: '@nx/vite/plugin', + configFilePath: 'app/vite.config.ts', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'previewTargetName', + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'preview', + defaultE2EWebServerAddress: 'http://localhost:4200', + defaultE2ECiBaseUrl: 'http://localhost:4300', + defaultE2EPort: 4200, + }, + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:vite:preview", + "e2eDevServerTarget": "app:vite:serve", + "e2eWebServerAddress": "http://localhost:4400", + "e2eWebServerCommand": "npx nx run app:vite:serve", + } + `); + }); + + it('should use the values of the correct registered plugin when there are includes or excludes defined', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + nxJson.plugins.push({ + plugin: '@nx/vite/plugin', + options: { + serveTargetName: 'vite:serve', + previewTargetName: 'vite:preview', + }, + include: ['libs/**'], + }); + nxJson.plugins.push({ + plugin: '@nx/vite/plugin', + options: { + serveTargetName: 'vite-serve', + previewTargetName: 'vite-preview', + }, + include: ['app/**'], + }); + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getE2EWebServerInfo( + tree, + 'app', + { + plugin: '@nx/vite/plugin', + configFilePath: 'app/vite.config.ts', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'previewTargetName', + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'preview', + defaultE2EWebServerAddress: 'http://localhost:4200', + defaultE2ECiBaseUrl: 'http://localhost:4300', + defaultE2EPort: 4400, + }, + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:vite-preview", + "e2eDevServerTarget": "app:vite-serve", + "e2eWebServerAddress": "http://localhost:4400", + "e2eWebServerCommand": "npx nx run app:vite-serve", + } + `); + }); +}); diff --git a/packages/devkit/src/generators/e2e-web-server-info-utils.ts b/packages/devkit/src/generators/e2e-web-server-info-utils.ts new file mode 100644 index 0000000000000..18272fa6e28ed --- /dev/null +++ b/packages/devkit/src/generators/e2e-web-server-info-utils.ts @@ -0,0 +1,126 @@ +import { + type Tree, + getPackageManagerCommand, + readNxJson, +} from 'nx/src/devkit-exports'; +import type { PackageManagerCommands } from 'nx/src/utils/package-manager'; +import { findPluginForConfigFile } from '../utils/find-plugin-for-config-file'; + +interface E2EWebServerDefaultValues { + defaultServeTargetName: string; + defaultServeStaticTargetName: string; + defaultE2EWebServerAddress: string; + defaultE2ECiBaseUrl: string; + defaultE2EPort: number; +} + +interface E2EWebServerPluginOptions { + plugin: string; + configFilePath: string; + serveTargetName: string; + serveStaticTargetName: string; +} + +export interface E2EWebServerDetails { + e2eWebServerAddress: string; + e2eWebServerCommand: string; + e2eCiWebServerCommand: string; + e2eCiBaseUrl: string; + e2eDevServerTarget: string; +} + +export async function getE2EWebServerInfo( + tree: Tree, + projectName: string, + pluginOptions: E2EWebServerPluginOptions, + defaultValues: E2EWebServerDefaultValues, + isPluginBeingAdded: boolean +): Promise { + const pm = getPackageManagerCommand(); + if (isPluginBeingAdded) { + return await getE2EWebServerInfoForPlugin( + tree, + projectName, + pluginOptions, + defaultValues, + pm + ); + } else { + return { + e2eWebServerAddress: defaultValues.defaultE2EWebServerAddress, + e2eWebServerCommand: `${pm.exec} nx run ${projectName}:${defaultValues.defaultServeTargetName}`, + e2eCiWebServerCommand: `${pm.exec} nx run ${projectName}:${defaultValues.defaultServeStaticTargetName}`, + e2eCiBaseUrl: defaultValues.defaultE2ECiBaseUrl, + e2eDevServerTarget: `${projectName}:${defaultValues.defaultServeTargetName}`, + }; + } +} + +async function getE2EWebServerInfoForPlugin( + tree: Tree, + projectName: string, + pluginOptions: E2EWebServerPluginOptions, + defaultValues: E2EWebServerDefaultValues, + pm: PackageManagerCommands +): Promise { + const foundPlugin = await findPluginForConfigFile( + tree, + pluginOptions.plugin, + pluginOptions.configFilePath + ); + if ( + !foundPlugin || + typeof foundPlugin === 'string' || + !foundPlugin?.options + ) { + return { + e2eWebServerAddress: defaultValues.defaultE2EWebServerAddress, + e2eWebServerCommand: `${pm.exec} nx run ${projectName}:${defaultValues.defaultServeTargetName}`, + e2eCiWebServerCommand: `${pm.exec} nx run ${projectName}:${defaultValues.defaultServeStaticTargetName}`, + e2eCiBaseUrl: defaultValues.defaultE2ECiBaseUrl, + e2eDevServerTarget: `${projectName}:${defaultValues.defaultServeTargetName}`, + }; + } + + const nxJson = readNxJson(tree); + let e2ePort = defaultValues.defaultE2EPort ?? 4200; + + if ( + nxJson.targetDefaults?.[ + foundPlugin.options[pluginOptions.serveTargetName] ?? + defaultValues.defaultServeTargetName + ] && + nxJson.targetDefaults?.[ + foundPlugin.options[pluginOptions.serveTargetName] ?? + defaultValues.defaultServeTargetName + ].options?.port + ) { + e2ePort = + nxJson.targetDefaults?.[ + foundPlugin.options[pluginOptions.serveTargetName] ?? + defaultValues.defaultServeTargetName + ].options?.port; + } + + const e2eWebServerAddress = defaultValues.defaultE2EWebServerAddress.replace( + /:\d+/, + `:${e2ePort}` + ); + + return { + e2eWebServerAddress, + e2eWebServerCommand: `${pm.exec} nx run ${projectName}:${ + foundPlugin.options[pluginOptions.serveTargetName] ?? + defaultValues.defaultServeTargetName + }`, + e2eCiWebServerCommand: `${pm.exec} nx run ${projectName}:${ + foundPlugin.options[pluginOptions.serveStaticTargetName] ?? + defaultValues.defaultServeStaticTargetName + }`, + e2eCiBaseUrl: defaultValues.defaultE2ECiBaseUrl, + e2eDevServerTarget: `${projectName}:${ + foundPlugin.options[pluginOptions.serveTargetName] ?? + defaultValues.defaultServeTargetName + }`, + }; +} diff --git a/packages/expo/src/generators/application/lib/add-e2e.ts b/packages/expo/src/generators/application/lib/add-e2e.ts index 9b059213f80c2..71f0242024133 100644 --- a/packages/expo/src/generators/application/lib/add-e2e.ts +++ b/packages/expo/src/generators/application/lib/add-e2e.ts @@ -1,4 +1,4 @@ -import type { GeneratorCallback, Tree } from '@nx/devkit'; +import { GeneratorCallback, Tree } from '@nx/devkit'; import { addProjectConfiguration, ensurePackage, @@ -13,21 +13,29 @@ import { hasExpoPlugin } from '../../../utils/has-expo-plugin'; import { NormalizedSchema } from './normalize-options'; import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; +import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; export async function addE2e( tree: Tree, options: NormalizedSchema ): Promise { const hasPlugin = hasExpoPlugin(tree); + if (!hasPlugin) { + await webStaticServeGenerator(tree, { + buildTarget: `${options.projectName}:export`, + targetName: 'serve-static', + }); + } + + const e2eWebServerInfo = await getExpoE2EWebServerInfo( + tree, + options.projectName, + joinPathFragments(options.appProjectRoot, 'app.json'), + options.addPlugin + ); + switch (options.e2eTestRunner) { case 'cypress': { - if (!hasPlugin) { - await webStaticServeGenerator(tree, { - buildTarget: `${options.projectName}:export`, - targetName: 'serve-static', - }); - } - const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); @@ -48,12 +56,14 @@ export async function addE2e( // the name and root are already normalized, instruct the generator to use them as is bundler: 'none', skipFormat: true, - devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`, - port: options.e2ePort, - baseUrl: options.e2eWebServerAddress, - ciWebServerCommand: hasPlugin - ? `nx run ${options.projectName}:serve-static` - : undefined, + devServerTarget: e2eWebServerInfo.e2eDevServerTarget, + baseUrl: e2eWebServerInfo.e2eWebServerAddress, + ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + webServerCommands: { + default: e2eWebServerInfo.e2eWebServerCommand, + production: e2eWebServerInfo.e2eCiWebServerCommand, + }, + ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl, jsx: true, rootProject: options.rootProject, }); @@ -112,10 +122,8 @@ export async function addE2e( js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, - webServerCommand: `${getPackageManagerCommand().exec} nx ${ - options.e2eWebServerTarget - } ${options.name}`, - webServerAddress: options.e2eWebServerAddress, + webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + webServerAddress: e2eWebServerInfo.e2eCiBaseUrl, rootProject: options.rootProject, addPlugin: options.addPlugin, }); @@ -172,3 +180,39 @@ export async function addE2e( return () => {}; } } + +async function getExpoE2EWebServerInfo( + tree: Tree, + projectName: string, + configFilePath: string, + isPluginBeingAdded: boolean +) { + const nxJson = readNxJson(tree); + let e2ePort = isPluginBeingAdded ? 8081 : 4200; + + if ( + nxJson.targetDefaults?.['serve'] && + nxJson.targetDefaults?.['serve'].options?.port + ) { + e2ePort = nxJson.targetDefaults?.['serve'].options?.port; + } + + return getE2EWebServerInfo( + tree, + projectName, + { + plugin: '@nx/expo/plugin', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'serveTargetName', + configFilePath, + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'serve-static', + defaultE2EWebServerAddress: `http://localhost:${e2ePort}`, + defaultE2ECiBaseUrl: 'http://localhost:4200', + defaultE2EPort: e2ePort, + }, + isPluginBeingAdded + ); +} diff --git a/packages/expo/src/generators/application/lib/normalize-options.spec.ts b/packages/expo/src/generators/application/lib/normalize-options.spec.ts index ad39102795aa8..5ceeb32822f3b 100644 --- a/packages/expo/src/generators/application/lib/normalize-options.spec.ts +++ b/packages/expo/src/generators/application/lib/normalize-options.spec.ts @@ -40,9 +40,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'my-app-e2e', - e2ePort: 8081, - e2eWebServerAddress: 'http://localhost:8081', - e2eWebServerTarget: 'serve', } as NormalizedSchema); }); @@ -75,9 +72,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'myApp-e2e', e2eProjectRoot: 'myApp-e2e', - e2ePort: 8081, - e2eWebServerAddress: 'http://localhost:8081', - e2eWebServerTarget: 'serve', } as NormalizedSchema); }); @@ -112,9 +106,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'directory-e2e', - e2ePort: 8081, - e2eWebServerAddress: 'http://localhost:8081', - e2eWebServerTarget: 'serve', } as NormalizedSchema); }); @@ -147,9 +138,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'directory/my-app-e2e', - e2ePort: 8081, - e2eWebServerAddress: 'http://localhost:8081', - e2eWebServerTarget: 'serve', } as NormalizedSchema); }); @@ -183,9 +171,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'my-app-e2e', - e2ePort: 8081, - e2eWebServerAddress: 'http://localhost:8081', - e2eWebServerTarget: 'serve', } as NormalizedSchema); }); }); diff --git a/packages/expo/src/generators/application/lib/normalize-options.ts b/packages/expo/src/generators/application/lib/normalize-options.ts index dc835166d8a6b..6f38a24d472eb 100644 --- a/packages/expo/src/generators/application/lib/normalize-options.ts +++ b/packages/expo/src/generators/application/lib/normalize-options.ts @@ -12,9 +12,6 @@ export interface NormalizedSchema extends Schema { rootProject: boolean; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2ePort: number; } export async function normalizeOptions( @@ -46,38 +43,13 @@ export async function normalizeOptions( : []; const rootProject = appProjectRoot === '.'; - let e2eWebServerTarget = 'serve'; - if (options.addPlugin) { - if (nxJson.plugins) { - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'object' && - plugin.plugin === '@nx/expo/plugin' && - (plugin.options as ExpoPluginOptions).serveTargetName - ) { - e2eWebServerTarget = (plugin.options as ExpoPluginOptions) - .serveTargetName; - } - } - } - } - - let e2ePort = options.addPlugin ? 8081 : 4200; - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port - ) { - e2ePort = nxJson.targetDefaults?.[e2eWebServerTarget].options.port; - } - const e2eProjectName = rootProject ? 'e2e' : `${appProjectName}-e2e`; const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; return { ...options, unitTestRunner: options.unitTestRunner || 'jest', - e2eTestRunner: options.e2eTestRunner, + e2eTestRunner: options.e2eTestRunner || 'none', name: projectNames.projectSimpleName, className, lowerCaseName: className.toLowerCase(), @@ -88,8 +60,5 @@ export async function normalizeOptions( rootProject, e2eProjectName, e2eProjectRoot, - e2eWebServerAddress, - e2eWebServerTarget, - e2ePort, }; } diff --git a/packages/expo/src/generators/application/schema.json b/packages/expo/src/generators/application/schema.json index d7c4a827a8660..d4358034acc75 100644 --- a/packages/expo/src/generators/application/schema.json +++ b/packages/expo/src/generators/application/schema.json @@ -76,7 +76,7 @@ "description": "Adds the specified e2e test runner", "type": "string", "enum": ["playwright", "cypress", "detox", "none"], - "default": "playwright" + "default": "none" }, "standaloneConfig": { "description": "Split the project configuration into `/project.json` rather than including it inside `workspace.json`.", diff --git a/packages/next/src/generators/application/lib/add-e2e.ts b/packages/next/src/generators/application/lib/add-e2e.ts index 11cb0eb3f98b6..0b37908cf0da0 100644 --- a/packages/next/src/generators/application/lib/add-e2e.ts +++ b/packages/next/src/generators/application/lib/add-e2e.ts @@ -13,6 +13,7 @@ import { NormalizedSchema } from './normalize-options'; import { webStaticServeGenerator } from '@nx/web'; import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; +import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; export async function addE2e(host: Tree, options: NormalizedSchema) { const nxJson = readNxJson(host); @@ -22,6 +23,13 @@ export async function addE2e(host: Tree, options: NormalizedSchema) { : p.plugin === '@nx/next/plugin' ); + const e2eWebServerInfo = await getNextE2EWebServerInfo( + host, + options.projectName, + joinPathFragments(options.appProjectRoot, 'next.config.js'), + options.addPlugin + ); + if (options.e2eTestRunner === 'cypress') { const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') @@ -50,17 +58,16 @@ export async function addE2e(host: Tree, options: NormalizedSchema) { project: options.e2eProjectName, directory: 'src', skipFormat: true, - devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`, - baseUrl: options.e2eWebServerAddress, + devServerTarget: e2eWebServerInfo.e2eDevServerTarget, + baseUrl: e2eWebServerInfo.e2eWebServerAddress, jsx: true, webServerCommands: hasPlugin ? { - default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`, + default: e2eWebServerInfo.e2eWebServerCommand, } : undefined, - ciWebServerCommand: hasPlugin - ? `nx run ${options.projectName}:serve-static` - : undefined, + ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl, }); if ( @@ -116,10 +123,8 @@ export async function addE2e(host: Tree, options: NormalizedSchema) { js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, - webServerAddress: `http://127.0.0.1:${options.e2ePort}`, - webServerCommand: `${getPackageManagerCommand().exec} nx ${ - options.e2eWebServerTarget - } ${options.projectName}`, + webServerAddress: e2eWebServerInfo.e2eCiBaseUrl, + webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, addPlugin: options.addPlugin, }); @@ -156,3 +161,41 @@ export async function addE2e(host: Tree, options: NormalizedSchema) { } return () => {}; } + +async function getNextE2EWebServerInfo( + tree: Tree, + projectName: string, + configFilePath: string, + isPluginBeingAdded: boolean +) { + const nxJson = readNxJson(tree); + let e2ePort = isPluginBeingAdded ? 3000 : 4200; + + const defaultServeTarget = isPluginBeingAdded ? 'dev' : 'serve'; + + if ( + nxJson.targetDefaults?.[defaultServeTarget] && + nxJson.targetDefaults?.[defaultServeTarget].options?.port + ) { + e2ePort = nxJson.targetDefaults?.[defaultServeTarget].options?.port; + } + + return getE2EWebServerInfo( + tree, + projectName, + { + plugin: '@nx/next/plugin', + serveTargetName: 'devTargetName', + serveStaticTargetName: 'serveStaticTargetName', + configFilePath, + }, + { + defaultServeTargetName: defaultServeTarget, + defaultServeStaticTargetName: 'serve-static', + defaultE2EWebServerAddress: `http://127.0.0.1:${e2ePort}`, + defaultE2ECiBaseUrl: `http://localhost:${e2ePort}`, + defaultE2EPort: e2ePort, + }, + isPluginBeingAdded + ); +} diff --git a/packages/next/src/generators/application/lib/add-linting.spec.ts b/packages/next/src/generators/application/lib/add-linting.spec.ts index 1a79152d9a5d6..a955cd54bacbe 100644 --- a/packages/next/src/generators/application/lib/add-linting.spec.ts +++ b/packages/next/src/generators/application/lib/add-linting.spec.ts @@ -21,9 +21,6 @@ describe('updateEslint', () => { unitTestRunner: 'jest', e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'my-app-e2e', - e2ePort: 3000, - e2eWebServerTarget: 'start', - e2eWebServerAddress: 'http://localhost:4200', outputPath: 'dist/my-app', name: 'my-app', parsedTags: [], diff --git a/packages/next/src/generators/application/lib/normalize-options.ts b/packages/next/src/generators/application/lib/normalize-options.ts index 02d7bd96a7b53..34c58ab52571a 100644 --- a/packages/next/src/generators/application/lib/normalize-options.ts +++ b/packages/next/src/generators/application/lib/normalize-options.ts @@ -11,9 +11,6 @@ export interface NormalizedSchema extends Schema { outputPath: string; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2ePort: number; parsedTags: string[]; fileName: string; styledModule: null | string; @@ -46,36 +43,8 @@ export async function normalizeOptions( options.addPlugin ??= addPlugin; - let e2eWebServerTarget = options.addPlugin ? 'start' : 'serve'; - if (options.addPlugin) { - if (nxJson.plugins) { - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'object' && - plugin.plugin === '@nx/next/plugin' && - (plugin.options as NextPluginOptions).startTargetName - ) { - e2eWebServerTarget = (plugin.options as NextPluginOptions) - .startTargetName; - } - } - } - } - - let e2ePort = options.addPlugin ? 3000 : 4200; - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - (nxJson.targetDefaults?.[e2eWebServerTarget].options?.port || - nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT) - ) { - e2ePort = - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port || - nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT; - } - const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`; const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; const name = names(options.name).fileName; @@ -107,9 +76,6 @@ export async function normalizeOptions( appProjectRoot, e2eProjectName, e2eProjectRoot, - e2eWebServerAddress, - e2eWebServerTarget, - e2ePort, e2eTestRunner: options.e2eTestRunner || 'playwright', fileName, linter: options.linter || Linter.EsLint, diff --git a/packages/nuxt/src/generators/application/lib/add-e2e.ts b/packages/nuxt/src/generators/application/lib/add-e2e.ts index 3c7bc78fe1082..624f53e2ff66d 100644 --- a/packages/nuxt/src/generators/application/lib/add-e2e.ts +++ b/packages/nuxt/src/generators/application/lib/add-e2e.ts @@ -3,14 +3,24 @@ import { ensurePackage, getPackageManagerCommand, joinPathFragments, + readNxJson, Tree, } from '@nx/devkit'; +import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; import { nxVersion } from '../../../utils/versions'; import { NormalizedSchema } from '../schema'; import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; export async function addE2e(host: Tree, options: NormalizedSchema) { + const e2eWebServerInfo = await getNuxtE2EWebServerInfo( + host, + options.projectName, + joinPathFragments( + options.appProjectRoot, + `nuxt.config.${options.js ? 'js' : 'ts'}` + ) + ); if (options.e2eTestRunner === 'cypress') { const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') @@ -29,14 +39,13 @@ export async function addE2e(host: Tree, options: NormalizedSchema) { directory: 'src', bundler: 'vite', skipFormat: true, - devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`, + devServerTarget: e2eWebServerInfo.e2eDevServerTarget, webServerCommands: { - default: `${getPackageManagerCommand().exec} nx ${ - options.e2eWebServerTarget - } ${options.projectName}`, + default: e2eWebServerInfo.e2eWebServerCommand, }, - ciWebServerCommand: `nx run ${options.projectName}:serve-static`, - baseUrl: options.e2eWebServerAddress, + ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + baseUrl: e2eWebServerInfo.e2eWebServerAddress, + ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl, jsx: true, addPlugin: true, }); @@ -85,10 +94,8 @@ export async function addE2e(host: Tree, options: NormalizedSchema) { js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, - webServerAddress: options.e2eWebServerAddress, - webServerCommand: `${getPackageManagerCommand().exec} nx ${ - options.e2eWebServerTarget - } ${options.projectName}`, + webServerAddress: e2eWebServerInfo.e2eCiWebServerCommand, + webServerCommand: e2eWebServerInfo.e2eCiBaseUrl, addPlugin: true, }); @@ -118,3 +125,38 @@ export async function addE2e(host: Tree, options: NormalizedSchema) { } return () => {}; } + +async function getNuxtE2EWebServerInfo( + tree: Tree, + projectName: string, + configFilePath: string +) { + const nxJson = readNxJson(tree); + let e2ePort = 4200; + + if ( + nxJson.targetDefaults?.['serve'] && + nxJson.targetDefaults?.['serve'].options?.port + ) { + e2ePort = nxJson.targetDefaults?.['serve'].options?.port; + } + + return getE2EWebServerInfo( + tree, + projectName, + { + plugin: '@nx/nuxt/plugin', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'serveStaticTargetName', + configFilePath, + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'serve-static', + defaultE2EWebServerAddress: `http://localhost:${e2ePort}`, + defaultE2ECiBaseUrl: 'http://localhost:4200', + defaultE2EPort: e2ePort, + }, + true + ); +} diff --git a/packages/nuxt/src/generators/application/lib/normalize-options.ts b/packages/nuxt/src/generators/application/lib/normalize-options.ts index 4fe2d629f8152..020e9d2f754c9 100644 --- a/packages/nuxt/src/generators/application/lib/normalize-options.ts +++ b/packages/nuxt/src/generators/application/lib/normalize-options.ts @@ -32,30 +32,9 @@ export async function normalizeOptions( options.projectNameAndRootFormat = projectNameAndRootFormat; const nxJson = readNxJson(host); - let e2eWebServerTarget = 'serve'; - if (nxJson.plugins) { - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'object' && - plugin.plugin === '@nx/nuxt/plugin' && - (plugin.options as NuxtPluginOptions).serveTargetName - ) { - e2eWebServerTarget = (plugin.options as NuxtPluginOptions) - .serveTargetName; - } - } - } - let e2ePort = 4200; - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port - ) { - e2ePort = nxJson.targetDefaults?.[e2eWebServerTarget].options?.port; - } const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`; const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) @@ -68,9 +47,6 @@ export async function normalizeOptions( appProjectRoot, e2eProjectName, e2eProjectRoot, - e2eWebServerAddress, - e2eWebServerTarget, - e2ePort, parsedTags, style: options.style ?? 'none', } as NormalizedSchema; diff --git a/packages/nuxt/src/generators/application/schema.d.ts b/packages/nuxt/src/generators/application/schema.d.ts index b14d2e0609ba7..596b214406539 100644 --- a/packages/nuxt/src/generators/application/schema.d.ts +++ b/packages/nuxt/src/generators/application/schema.d.ts @@ -23,8 +23,5 @@ export interface NormalizedSchema extends Schema { appProjectRoot: string; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2ePort: number; parsedTags: string[]; } diff --git a/packages/react-native/src/generators/application/lib/add-e2e.ts b/packages/react-native/src/generators/application/lib/add-e2e.ts index c3e21a0f1b628..6aff1fc81dd2f 100644 --- a/packages/react-native/src/generators/application/lib/add-e2e.ts +++ b/packages/react-native/src/generators/application/lib/add-e2e.ts @@ -18,8 +18,6 @@ export async function addE2e( styledModule: null, hasStyles: false, unitTestRunner: 'none', - e2eCiWebServerTarget: options.e2eWebServerTarget, - e2eCiBaseUrl: options.e2eWebServerAddress, }); case 'playwright': return addE2eReact(host, { @@ -29,8 +27,6 @@ export async function addE2e( styledModule: null, hasStyles: false, unitTestRunner: 'none', - e2eCiWebServerTarget: options.e2eWebServerTarget, - e2eCiBaseUrl: options.e2eWebServerAddress, }); case 'detox': const { detoxApplicationGenerator } = ensurePackage< diff --git a/packages/react-native/src/generators/application/lib/normalize-options.spec.ts b/packages/react-native/src/generators/application/lib/normalize-options.spec.ts index 83cee42a2801e..e140ba10fb910 100644 --- a/packages/react-native/src/generators/application/lib/normalize-options.spec.ts +++ b/packages/react-native/src/generators/application/lib/normalize-options.spec.ts @@ -44,9 +44,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'my-app-e2e', - e2ePort: 4200, - e2eWebServerAddress: 'http://localhost:4200', - e2eWebServerTarget: 'serve', }); }); @@ -83,9 +80,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'myApp-e2e', - e2ePort: 4200, - e2eWebServerAddress: 'http://localhost:4200', - e2eWebServerTarget: 'serve', }); }); @@ -124,9 +118,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'directory/my-app-e2e', - e2ePort: 4200, - e2eWebServerAddress: 'http://localhost:4200', - e2eWebServerTarget: 'serve', }); }); @@ -163,9 +154,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'directory/my-app-e2e', e2eProjectRoot: 'directory/my-app-e2e', - e2ePort: 4200, - e2eWebServerAddress: 'http://localhost:4200', - e2eWebServerTarget: 'serve', }); }); @@ -203,9 +191,6 @@ describe('Normalize Options', () => { rootProject: false, e2eProjectName: 'my-app-e2e', e2eProjectRoot: 'my-app-e2e', - e2ePort: 4200, - e2eWebServerAddress: 'http://localhost:4200', - e2eWebServerTarget: 'serve', }); }); }); diff --git a/packages/react-native/src/generators/application/lib/normalize-options.ts b/packages/react-native/src/generators/application/lib/normalize-options.ts index 4d8e237aa7b7f..2ce774753cc37 100644 --- a/packages/react-native/src/generators/application/lib/normalize-options.ts +++ b/packages/react-native/src/generators/application/lib/normalize-options.ts @@ -17,9 +17,6 @@ export interface NormalizedSchema extends Schema { rootProject: boolean; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2ePort: number; } export async function normalizeOptions( @@ -50,34 +47,8 @@ export async function normalizeOptions( const androidProjectRoot = joinPathFragments(appProjectRoot, 'android'); const rootProject = appProjectRoot === '.'; - let e2eWebServerTarget = 'serve'; - if (options.addPlugin) { - if (nxJson.plugins) { - for (const plugin of nxJson.plugins) { - if ( - options.bundler === 'vite' && - typeof plugin === 'object' && - plugin.plugin === '@nx/vite/plugin' && - (plugin.options as VitePluginOptions).serveTargetName - ) { - e2eWebServerTarget = (plugin.options as ReactNativePluginOptions) - .startTargetName; - } - } - } - } - - let e2ePort = 4200; - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port - ) { - e2ePort = nxJson.targetDefaults?.[e2eWebServerTarget].options?.port; - } - const e2eProjectName = rootProject ? 'e2e' : `${fileName}-e2e`; const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) @@ -101,8 +72,5 @@ export async function normalizeOptions( rootProject, e2eProjectName, e2eProjectRoot, - e2eWebServerAddress, - e2eWebServerTarget, - e2ePort, }; } diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts index d1d84e6a767bb..06fa078d3c347 100644 --- a/packages/react/src/generators/application/application.spec.ts +++ b/packages/react/src/generators/application/application.spec.ts @@ -86,7 +86,7 @@ describe('app', () => { import { defineConfig } from 'cypress'; export default defineConfig({ - e2e: { ...nxE2EPreset(__filename, {"cypressDir":"src","bundler":"vite","webServerCommands":{"default":"nx run my-app:serve","production":"nx run my-app:preview"},"ciWebServerCommand":"nx run my-app:preview","ciBaseUrl":"http://localhost:4300"}), + e2e: { ...nxE2EPreset(__filename, {"cypressDir":"src","bundler":"vite","webServerCommands":{"default":"npx nx run my-app:serve","production":"npx nx run my-app:preview"},"ciWebServerCommand":"npx nx run my-app:preview","ciBaseUrl":"http://localhost:4300"}), baseUrl: 'http://localhost:4200' } }); " diff --git a/packages/react/src/generators/application/lib/add-e2e.ts b/packages/react/src/generators/application/lib/add-e2e.ts index 2f09da931de21..c0c67f01ff9ee 100644 --- a/packages/react/src/generators/application/lib/add-e2e.ts +++ b/packages/react/src/generators/application/lib/add-e2e.ts @@ -14,6 +14,7 @@ import { hasVitePlugin } from '../../../utils/has-vite-plugin'; import { NormalizedSchema } from '../schema'; import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; +import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; export async function addE2e( tree: Tree, @@ -22,6 +23,49 @@ export async function addE2e( const hasNxBuildPlugin = (options.bundler === 'webpack' && hasWebpackPlugin(tree)) || (options.bundler === 'vite' && hasVitePlugin(tree)); + + let e2eWebServerInfo: E2EWebServerDetails = { + e2eWebServerAddress: `http://localhost:${options.devServerPort ?? 4200}`, + e2eWebServerCommand: `${getPackageManagerCommand().exec} nx run ${ + options.projectName + }:serve`, + e2eCiWebServerCommand: `${getPackageManagerCommand().exec} nx run ${ + options.projectName + }:serve-static`, + e2eCiBaseUrl: `http://localhost:4200`, + e2eDevServerTarget: `${options.projectName}:serve`, + }; + + if (options.bundler === 'webpack') { + const { getWebpackE2EWebServerInfo } = ensurePackage< + typeof import('@nx/webpack') + >('@nx/webpack', nxVersion); + e2eWebServerInfo = await getWebpackE2EWebServerInfo( + tree, + options.projectName, + joinPathFragments( + options.appProjectRoot, + `webpack.config.${options.js ? 'js' : 'ts'}` + ), + options.addPlugin, + options.devServerPort ?? 4200 + ); + } else if (options.bundler === 'vite') { + const { getViteE2EWebServerInfo } = ensurePackage< + typeof import('@nx/vite') + >('@nx/vite', nxVersion); + e2eWebServerInfo = await getViteE2EWebServerInfo( + tree, + options.projectName, + joinPathFragments( + options.appProjectRoot, + `vite.config.${options.js ? 'js' : 'ts'}` + ), + options.addPlugin, + options.devServerPort ?? 4200 + ); + } + if (!hasNxBuildPlugin) { await webStaticServeGenerator(tree, { buildTarget: `${options.projectName}:build`, @@ -51,21 +95,20 @@ export async function addE2e( // the name and root are already normalized, instruct the generator to use them as is bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler, skipFormat: true, - devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`, - baseUrl: options.e2eWebServerAddress, + devServerTarget: e2eWebServerInfo.e2eDevServerTarget, + baseUrl: e2eWebServerInfo.e2eWebServerAddress, jsx: true, rootProject: options.rootProject, webServerCommands: hasNxBuildPlugin ? { - default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`, - production: `nx run ${options.projectName}:preview`, + default: e2eWebServerInfo.e2eWebServerCommand, + production: e2eWebServerInfo.e2eCiWebServerCommand, } : undefined, ciWebServerCommand: hasNxBuildPlugin - ? `nx run ${options.projectName}:${options.e2eCiWebServerTarget}` + ? e2eWebServerInfo.e2eCiWebServerCommand : undefined, - ciBaseUrl: - options.bundler === 'vite' ? options.e2eCiBaseUrl : undefined, + ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl, }); if ( @@ -127,10 +170,8 @@ export async function addE2e( js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, - webServerCommand: `${getPackageManagerCommand().exec} nx run ${ - options.projectName - }:${options.e2eCiWebServerTarget}`, - webServerAddress: options.e2eCiBaseUrl, + webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + webServerAddress: e2eWebServerInfo.e2eCiBaseUrl, rootProject: options.rootProject, addPlugin: options.addPlugin, }); diff --git a/packages/react/src/generators/application/lib/normalize-options.ts b/packages/react/src/generators/application/lib/normalize-options.ts index 5031c90b9f303..bf328fc60572b 100644 --- a/packages/react/src/generators/application/lib/normalize-options.ts +++ b/packages/react/src/generators/application/lib/normalize-options.ts @@ -46,57 +46,8 @@ export async function normalizeOptions( options.rootProject = appProjectRoot === '.'; options.projectNameAndRootFormat = projectNameAndRootFormat; - let e2ePort = options.devServerPort ?? 4200; - - let e2eWebServerTarget = 'serve'; - let e2eCiWebServerTarget = - options.bundler === 'vite' ? 'preview' : 'serve-static'; - if (options.addPlugin) { - if (nxJson.plugins) { - for (const plugin of nxJson.plugins) { - if ( - options.bundler === 'vite' && - typeof plugin === 'object' && - plugin.plugin === '@nx/vite/plugin' - ) { - e2eCiWebServerTarget = - (plugin.options as VitePluginOptions)?.previewTargetName ?? - e2eCiWebServerTarget; - - e2eWebServerTarget = - (plugin.options as VitePluginOptions)?.serveTargetName ?? - e2eWebServerTarget; - } else if ( - options.bundler === 'webpack' && - typeof plugin === 'object' && - plugin.plugin === '@nx/webpack/plugin' - ) { - e2eCiWebServerTarget = - (plugin.options as WebpackPluginOptions)?.serveStaticTargetName ?? - e2eCiWebServerTarget; - - e2eWebServerTarget = - (plugin.options as WebpackPluginOptions)?.serveTargetName ?? - e2eWebServerTarget; - } - } - } - } - - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port - ) { - e2ePort = nxJson.targetDefaults?.[e2eWebServerTarget].options?.port; - } - const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`; const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; - const e2eCiBaseUrl = - options.bundler === 'vite' - ? 'http://localhost:4300' - : `http://localhost:${e2ePort}`; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) @@ -117,11 +68,6 @@ export async function normalizeOptions( appProjectRoot, e2eProjectName, e2eProjectRoot, - e2eWebServerAddress, - e2eWebServerTarget, - e2eCiWebServerTarget, - e2eCiBaseUrl, - e2ePort, parsedTags, fileName, styledModule, diff --git a/packages/react/src/generators/application/schema.d.ts b/packages/react/src/generators/application/schema.d.ts index 068682a0a3fea..14f51eb03c0a4 100644 --- a/packages/react/src/generators/application/schema.d.ts +++ b/packages/react/src/generators/application/schema.d.ts @@ -37,11 +37,6 @@ export interface NormalizedSchema extends T { appProjectRoot: string; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2eCiWebServerTarget: string; - e2eCiBaseUrl: string; - e2ePort: number; parsedTags: string[]; fileName: string; styledModule: null | SupportedStyles; diff --git a/packages/remix/src/generators/application/__snapshots__/application.impl.spec.ts.snap b/packages/remix/src/generators/application/__snapshots__/application.impl.spec.ts.snap index fde183522ad23..8e5a43be98a7e 100644 --- a/packages/remix/src/generators/application/__snapshots__/application.impl.spec.ts.snap +++ b/packages/remix/src/generators/application/__snapshots__/application.impl.spec.ts.snap @@ -153,7 +153,12 @@ export default defineConfig({ e2e: { ...nxE2EPreset(__filename, { cypressDir: 'src', - webServerCommands: { default: 'nx run test:dev:development' }, + webServerCommands: { + default: 'npx nx run test:dev', + production: 'npx nx run test:serve-static', + }, + ciWebServerCommand: 'npx nx run test:serve-static', + ciBaseUrl: 'http://localhost:3000', }), baseUrl: 'http://localhost:3000', }, @@ -189,7 +194,7 @@ export default defineConfig({ }, /* Run your local dev server before starting the tests */ webServer: { - command: 'npx nx dev test', + command: 'npx nx run test:serve-static', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, cwd: workspaceRoot, @@ -664,7 +669,12 @@ export default defineConfig({ e2e: { ...nxE2EPreset(__filename, { cypressDir: 'src', - webServerCommands: { default: 'nx run test:dev:development' }, + webServerCommands: { + default: 'npx nx run test:dev', + production: 'npx nx run test:serve-static', + }, + ciWebServerCommand: 'npx nx run test:serve-static', + ciBaseUrl: 'http://localhost:3000', }), baseUrl: 'http://localhost:3000', }, @@ -700,7 +710,7 @@ export default defineConfig({ }, /* Run your local dev server before starting the tests */ webServer: { - command: 'npx nx dev test', + command: 'npx nx run test:serve-static', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, cwd: workspaceRoot, @@ -1031,7 +1041,12 @@ export default defineConfig({ e2e: { ...nxE2EPreset(__filename, { cypressDir: 'src', - webServerCommands: { default: 'nx run test:dev:development' }, + webServerCommands: { + default: 'npx nx run test:dev', + production: 'npx nx run test:serve-static', + }, + ciWebServerCommand: 'npx nx run test:serve-static', + ciBaseUrl: 'http://localhost:3000', }), baseUrl: 'http://localhost:3000', }, @@ -1431,7 +1446,7 @@ export default defineConfig({ }, /* Run your local dev server before starting the tests */ webServer: { - command: 'npx nx dev test', + command: 'npx nx run test:serve-static', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, cwd: workspaceRoot, diff --git a/packages/remix/src/generators/application/application.impl.ts b/packages/remix/src/generators/application/application.impl.ts index 9198e91510c58..73e572a736cba 100644 --- a/packages/remix/src/generators/application/application.impl.ts +++ b/packages/remix/src/generators/application/application.impl.ts @@ -97,7 +97,7 @@ export async function remixApplicationGeneratorInternal( cwd: options.projectRoot, }, }, - ['static-serve']: { + ['serve-static']: { dependsOn: ['build'], command: `remix-serve build/index.js`, options: { diff --git a/packages/remix/src/generators/application/lib/add-e2e.ts b/packages/remix/src/generators/application/lib/add-e2e.ts index 43283705b7b02..0d8a3d1c89e57 100644 --- a/packages/remix/src/generators/application/lib/add-e2e.ts +++ b/packages/remix/src/generators/application/lib/add-e2e.ts @@ -12,6 +12,7 @@ import { type NormalizedSchema } from './normalize-options'; import { getPackageVersion } from '../../../utils/versions'; import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; +import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; export async function addE2E(tree: Tree, options: NormalizedSchema) { const hasRemixPlugin = readNxJson(tree).plugins?.find((p) => @@ -19,6 +20,14 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) { ? p === '@nx/remix/plugin' : p.plugin === '@nx/remix/plugin' ); + + let e2eWebsServerInfo = await getRemixE2EWebServerInfo( + tree, + options.projectName, + joinPathFragments(options.projectRoot, 'remix.config.js'), + options.addPlugin ?? Boolean(hasRemixPlugin) + ); + if (options.e2eTestRunner === 'cypress') { const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') @@ -37,8 +46,18 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) { project: options.e2eProjectName, directory: 'src', skipFormat: true, - devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}:development`, - baseUrl: options.e2eWebServerAddress, + devServerTarget: e2eWebsServerInfo.e2eDevServerTarget, + baseUrl: e2eWebsServerInfo.e2eWebServerAddress, + webServerCommands: hasRemixPlugin + ? { + default: e2eWebsServerInfo.e2eWebServerCommand, + production: e2eWebsServerInfo.e2eCiWebServerCommand, + } + : undefined, + ciWebServerCommand: hasRemixPlugin + ? e2eWebsServerInfo.e2eCiWebServerCommand + : undefined, + ciBaseUrl: e2eWebsServerInfo.e2eCiBaseUrl, addPlugin: options.addPlugin, }); @@ -97,10 +116,8 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) { js: false, linter: options.linter, setParserOptionsProject: false, - webServerCommand: `${getPackageManagerCommand().exec} nx ${ - options.e2eWebServerTarget - } ${options.name}`, - webServerAddress: options.e2eWebServerAddress, + webServerCommand: e2eWebsServerInfo.e2eCiWebServerCommand, + webServerAddress: e2eWebsServerInfo.e2eCiBaseUrl, rootProject: options.rootProject, addPlugin: options.addPlugin, }); @@ -139,3 +156,41 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) { return () => {}; } } + +async function getRemixE2EWebServerInfo( + tree: Tree, + projectName: string, + configFilePath: string, + isPluginBeingAdded: boolean +) { + const nxJson = readNxJson(tree); + let e2ePort = isPluginBeingAdded ? 3000 : 4200; + + const defaultServeTarget = isPluginBeingAdded ? 'dev' : 'serve'; + + if ( + nxJson.targetDefaults?.[defaultServeTarget] && + nxJson.targetDefaults?.[defaultServeTarget].options?.port + ) { + e2ePort = nxJson.targetDefaults?.[defaultServeTarget].options?.port; + } + + return getE2EWebServerInfo( + tree, + projectName, + { + plugin: '@nx/remix/plugin', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'serveStaticTargetName', + configFilePath, + }, + { + defaultServeTargetName: defaultServeTarget, + defaultServeStaticTargetName: 'serve-static', + defaultE2EWebServerAddress: `http://localhost:${e2ePort}`, + defaultE2ECiBaseUrl: 'http://localhost:3000', + defaultE2EPort: e2ePort, + }, + isPluginBeingAdded + ); +} diff --git a/packages/remix/src/generators/application/lib/normalize-options.ts b/packages/remix/src/generators/application/lib/normalize-options.ts index 0124714fc8e7f..220259961a1f9 100644 --- a/packages/remix/src/generators/application/lib/normalize-options.ts +++ b/packages/remix/src/generators/application/lib/normalize-options.ts @@ -9,9 +9,6 @@ export interface NormalizedSchema extends NxRemixGeneratorSchema { projectRoot: string; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2ePort: number; parsedTags: string[]; } @@ -36,35 +33,8 @@ export async function normalizeOptions( nxJson.useInferencePlugins !== false; options.addPlugin ??= addPluginDefault; - let e2eWebServerTarget = options.addPlugin ? 'dev' : 'serve'; - if (options.addPlugin) { - if (nxJson.plugins) { - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'object' && - plugin.plugin === '@nx/remix/plugin' && - (plugin.options as RemixPluginOptions).devTargetName - ) { - e2eWebServerTarget = (plugin.options as RemixPluginOptions) - .devTargetName; - } - } - } - } - - let e2ePort = options.addPlugin ? 3000 : 4200; - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - (nxJson.targetDefaults?.[e2eWebServerTarget].options?.port || - nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT) - ) { - e2ePort = - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port || - nxJson.targetDefaults?.[e2eWebServerTarget].options?.env?.PORT; - } const e2eProjectName = options.rootProject ? 'e2e' : `${projectName}-e2e`; const e2eProjectRoot = options.rootProject ? 'e2e' : `${projectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; const parsedTags = options.tags ? options.tags.split(',').map((s) => s.trim()) @@ -77,9 +47,6 @@ export async function normalizeOptions( projectRoot, e2eProjectName, e2eProjectRoot, - e2eWebServerAddress, - e2eWebServerTarget, - e2ePort, parsedTags, }; } diff --git a/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap b/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap index c62b4f292a5a9..2de78a52b63e7 100644 --- a/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap +++ b/packages/remix/src/plugins/__snapshots__/plugin.spec.ts.snap @@ -35,6 +35,15 @@ exports[`@nx/remix/plugin non-root project should create nodes 1`] = ` "cwd": "my-app", }, }, + "serve-static": { + "command": "remix-serve build/index.js", + "dependsOn": [ + "build", + ], + "options": { + "cwd": "my-app", + }, + }, "start": { "command": "remix-serve build/index.js", "dependsOn": [ @@ -110,6 +119,15 @@ exports[`@nx/remix/plugin root project should create nodes 1`] = ` "cwd": ".", }, }, + "serve-static": { + "command": "remix-serve build/index.js", + "dependsOn": [ + "build", + ], + "options": { + "cwd": ".", + }, + }, "start": { "command": "remix-serve build/index.js", "dependsOn": [ diff --git a/packages/remix/src/plugins/plugin.ts b/packages/remix/src/plugins/plugin.ts index d48bc6eadd4c8..2a65d594ef850 100644 --- a/packages/remix/src/plugins/plugin.ts +++ b/packages/remix/src/plugins/plugin.ts @@ -45,7 +45,11 @@ export interface RemixPluginOptions { devTargetName?: string; startTargetName?: string; typecheckTargetName?: string; + /** + * @deprecated Use serveStaticTargetName instead. This option will be removed in Nx 21. + */ staticServeTargetName?: string; + serveStaticTargetName?: string; } export const createNodes: CreateNodes = [ @@ -116,11 +120,17 @@ async function buildRemixTargets( serverBuildPath, options.buildTargetName ); + // TODO(colum): Remove for Nx 21 targets[options.staticServeTargetName] = startTarget( projectRoot, serverBuildPath, options.buildTargetName ); + targets[options.serveStaticTargetName] = startTarget( + projectRoot, + serverBuildPath, + options.buildTargetName + ); targets[options.typecheckTargetName] = typecheckTarget( projectRoot, namedInputs, @@ -233,7 +243,9 @@ function normalizeOptions(options: RemixPluginOptions) { options.devTargetName ??= 'dev'; options.startTargetName ??= 'start'; options.typecheckTargetName ??= 'typecheck'; + // TODO(colum): remove for Nx 21 options.staticServeTargetName ??= 'static-serve'; + options.serveStaticTargetName ??= 'serve-static'; return options; } diff --git a/packages/vite/index.ts b/packages/vite/index.ts index 740e3c64838a9..8175316ff5495 100644 --- a/packages/vite/index.ts +++ b/packages/vite/index.ts @@ -1,5 +1,6 @@ export * from './src/utils/versions'; export * from './src/utils/generator-utils'; +export * from './src/utils/e2e-web-server-info-utils'; export { type ViteConfigurationGeneratorSchema } from './src/generators/configuration/schema'; export { viteConfigurationGenerator } from './src/generators/configuration/configuration'; export { type VitestGeneratorSchema } from './src/generators/vitest/schema'; diff --git a/packages/vite/src/utils/e2e-web-server-info-utils.spec.ts b/packages/vite/src/utils/e2e-web-server-info-utils.spec.ts new file mode 100644 index 0000000000000..8c7cf1736548f --- /dev/null +++ b/packages/vite/src/utils/e2e-web-server-info-utils.spec.ts @@ -0,0 +1,149 @@ +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import { type Tree, readNxJson, updateNxJson } from 'nx/src/devkit-exports'; +import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; +import { getViteE2EWebServerInfo } from './e2e-web-server-info-utils'; + +describe('getViteE2EWebServerInfo', () => { + let tree: Tree; + let tempFs: TempFs; + beforeEach(() => { + tempFs = new TempFs('e2e-webserver-info'); + tree = createTreeWithEmptyWorkspace(); + tree.root = tempFs.tempDir; + + tree.write(`app/vite.config.ts`, ``); + tempFs.createFileSync(`app/vite.config.ts`, ``); + }); + + afterEach(() => { + tempFs.cleanup(); + jest.resetModules(); + }); + + it('should use the default values when no plugin is registered and plugins are not being used', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getViteE2EWebServerInfo( + tree, + 'app', + 'app/vite.config.ts', + false + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:preview", + "e2eDevServerTarget": "app:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:serve", + } + `); + }); + + it('should use the default values of the plugin when the plugin is just a string', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins = ['@nx/vite/plugin']; + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getViteE2EWebServerInfo( + tree, + 'app', + 'app/vite.config.ts', + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:preview", + "e2eDevServerTarget": "app:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:serve", + } + `); + }); + + it('should use the values of the registered plugin when there is no includes or excludes defined', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + nxJson.plugins.push({ + plugin: '@nx/vite/plugin', + options: { + serveTargetName: 'vite:serve', + previewTargetName: 'vite:preview', + }, + }); + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getViteE2EWebServerInfo( + tree, + 'app', + 'app/vite.config.ts', + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:vite:preview", + "e2eDevServerTarget": "app:vite:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:vite:serve", + } + `); + }); + + it('should use the values of the correct registered plugin when there are includes or excludes defined', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + nxJson.plugins.push({ + plugin: '@nx/vite/plugin', + options: { + serveTargetName: 'vite:serve', + previewTargetName: 'vite:preview', + }, + include: ['libs/**'], + }); + nxJson.plugins.push({ + plugin: '@nx/vite/plugin', + options: { + serveTargetName: 'vite-serve', + previewTargetName: 'vite-preview', + }, + include: ['app/**'], + }); + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getViteE2EWebServerInfo( + tree, + 'app', + 'app/vite.config.ts', + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4300", + "e2eCiWebServerCommand": "npx nx run app:vite-preview", + "e2eDevServerTarget": "app:vite-serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:vite-serve", + } + `); + }); +}); diff --git a/packages/vite/src/utils/e2e-web-server-info-utils.ts b/packages/vite/src/utils/e2e-web-server-info-utils.ts new file mode 100644 index 0000000000000..8a0e192215b9d --- /dev/null +++ b/packages/vite/src/utils/e2e-web-server-info-utils.ts @@ -0,0 +1,39 @@ +import { type Tree, readNxJson } from '@nx/devkit'; +import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; + +export async function getViteE2EWebServerInfo( + tree: Tree, + projectName: string, + configFilePath: string, + isPluginBeingAdded: boolean, + e2ePortOverride?: number +) { + const nxJson = readNxJson(tree); + let e2ePort = e2ePortOverride ?? 4200; + + if ( + nxJson.targetDefaults?.['serve'] && + nxJson.targetDefaults?.['serve'].options?.port + ) { + e2ePort = nxJson.targetDefaults?.['serve'].options?.port; + } + + return getE2EWebServerInfo( + tree, + projectName, + { + plugin: '@nx/vite/plugin', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'previewTargetName', + configFilePath, + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'preview', + defaultE2EWebServerAddress: `http://localhost:${e2ePort}`, + defaultE2ECiBaseUrl: 'http://localhost:4300', + defaultE2EPort: e2ePort, + }, + isPluginBeingAdded + ); +} diff --git a/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap index f318cac011b93..b891ddbe6adff 100644 --- a/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap +++ b/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap @@ -140,10 +140,10 @@ export default defineConfig({ cypressDir: 'src', bundler: 'vite', webServerCommands: { - default: 'nx run test:serve', - production: 'nx run test:preview', + default: 'npx nx run test:serve', + production: 'npx nx run test:preview', }, - ciWebServerCommand: 'nx run test:preview', + ciWebServerCommand: 'npx nx run test:preview', ciBaseUrl: 'http://localhost:4300', }), baseUrl: 'http://localhost:4200', diff --git a/packages/vue/src/generators/application/lib/add-e2e.ts b/packages/vue/src/generators/application/lib/add-e2e.ts index ae2578e334e9c..9616bdf6a0ba7 100644 --- a/packages/vue/src/generators/application/lib/add-e2e.ts +++ b/packages/vue/src/generators/application/lib/add-e2e.ts @@ -23,16 +23,21 @@ export async function addE2e( ? p === '@nx/vite/plugin' : p.plugin === '@nx/vite/plugin' ); - const e2eWebServerTarget = hasPlugin - ? typeof hasPlugin === 'string' - ? 'serve' - : (hasPlugin.options as any)?.serveTargetName ?? 'serve' - : 'serve'; - const e2eCiWebServerTarget = hasPlugin - ? typeof hasPlugin === 'string' - ? 'preview' - : (hasPlugin.options as any)?.previewTargetName ?? 'preview' - : 'preview'; + const { getViteE2EWebServerInfo } = ensurePackage( + '@nx/vite', + nxVersion + ); + const e2eWebServerInfo = await getViteE2EWebServerInfo( + tree, + options.projectName, + joinPathFragments( + options.appProjectRoot, + `vite.config.${options.js ? 'js' : 'ts'}` + ), + options.addPlugin, + options.devServerPort ?? 4200 + ); + switch (options.e2eTestRunner) { case 'cypress': { if (!hasPlugin) { @@ -60,17 +65,17 @@ export async function addE2e( directory: 'src', bundler: 'vite', skipFormat: true, - devServerTarget: `${options.projectName}:${e2eWebServerTarget}`, - baseUrl: 'http://localhost:4200', + devServerTarget: e2eWebServerInfo.e2eDevServerTarget, + baseUrl: e2eWebServerInfo.e2eWebServerAddress, jsx: true, webServerCommands: hasPlugin ? { - default: `nx run ${options.projectName}:${e2eWebServerTarget}`, - production: `nx run ${options.projectName}:preview`, + default: e2eWebServerInfo.e2eWebServerCommand, + production: e2eWebServerInfo.e2eCiWebServerCommand, } : undefined, - ciWebServerCommand: `nx run ${options.projectName}:${e2eCiWebServerTarget}`, - ciBaseUrl: 'http://localhost:4300', + ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl, }); if ( @@ -130,10 +135,8 @@ export async function addE2e( js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, - webServerCommand: `${getPackageManagerCommand().exec} nx run ${ - options.projectName - }:${e2eCiWebServerTarget}`, - webServerAddress: 'http://localhost:4300', + webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + webServerAddress: e2eWebServerInfo.e2eCiBaseUrl, }); if ( diff --git a/packages/web/src/generators/application/application.spec.ts b/packages/web/src/generators/application/application.spec.ts index cab0c67e7d4c2..050c75e42740c 100644 --- a/packages/web/src/generators/application/application.spec.ts +++ b/packages/web/src/generators/application/application.spec.ts @@ -192,10 +192,10 @@ describe('app', () => { cypressDir: 'src', bundler: 'vite', webServerCommands: { - default: 'nx run cool-app:serve', - production: 'nx run cool-app:preview', + default: 'npx nx run cool-app:serve', + production: 'npx nx run cool-app:preview', }, - ciWebServerCommand: 'nx run cool-app:preview', + ciWebServerCommand: 'npx nx run cool-app:preview', ciBaseUrl: 'http://localhost:4300', }), baseUrl: 'http://localhost:4200', @@ -225,10 +225,11 @@ describe('app', () => { ...nxE2EPreset(__filename, { cypressDir: 'src', webServerCommands: { - default: 'nx run cool-app:serve', - production: 'nx run cool-app:preview', + default: 'npx nx run cool-app:serve', + production: 'npx nx run cool-app:serve-static', }, - ciWebServerCommand: 'nx run cool-app:serve-static', + ciWebServerCommand: 'npx nx run cool-app:serve-static', + ciBaseUrl: 'http://localhost:4200', }), baseUrl: 'http://localhost:4200', }, diff --git a/packages/web/src/generators/application/application.ts b/packages/web/src/generators/application/application.ts index 9dbed0511df91..c8ab77c0a7e0a 100644 --- a/packages/web/src/generators/application/application.ts +++ b/packages/web/src/generators/application/application.ts @@ -47,17 +47,13 @@ import { VitePluginOptions } from '@nx/vite/src/plugins/plugin'; import { WebpackPluginOptions } from '@nx/webpack/src/plugins/plugin'; import staticServeConfiguration from '../static-serve/static-serve-configuration'; import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; +import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; interface NormalizedSchema extends Schema { projectName: string; appProjectRoot: string; e2eProjectName: string; e2eProjectRoot: string; - e2eWebServerAddress: string; - e2eWebServerTarget: string; - e2eCiWebServerTarget: string; - e2eCiBaseUrl: string; - e2ePort: number; parsedTags: string[]; } @@ -391,6 +387,43 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { spa: true, }); } + + let e2eWebServerInfo: E2EWebServerDetails = { + e2eWebServerAddress: `http://localhost:4200`, + e2eWebServerCommand: `${getPackageManagerCommand().exec} nx run ${ + options.projectName + }:serve`, + e2eCiWebServerCommand: `${getPackageManagerCommand().exec} nx run ${ + options.projectName + }:serve-static`, + e2eCiBaseUrl: `http://localhost:4200`, + e2eDevServerTarget: `${options.projectName}:serve`, + }; + + if (options.bundler === 'webpack') { + const { getWebpackE2EWebServerInfo } = ensurePackage< + typeof import('@nx/webpack') + >('@nx/webpack', nxVersion); + e2eWebServerInfo = await getWebpackE2EWebServerInfo( + host, + options.projectName, + joinPathFragments(options.appProjectRoot, `webpack.config.js`), + options.addPlugin, + 4200 + ); + } else if (options.bundler === 'vite') { + const { getViteE2EWebServerInfo } = ensurePackage< + typeof import('@nx/vite') + >('@nx/vite', nxVersion); + e2eWebServerInfo = await getViteE2EWebServerInfo( + host, + options.projectName, + joinPathFragments(options.appProjectRoot, `vite.config.ts`), + options.addPlugin, + 4200 + ); + } + if (options.e2eTestRunner === 'cypress') { const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') @@ -406,20 +439,20 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { const cypressTask = await configurationGenerator(host, { ...options, project: options.e2eProjectName, - devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`, - baseUrl: options.e2eWebServerAddress, + devServerTarget: e2eWebServerInfo.e2eDevServerTarget, + baseUrl: e2eWebServerInfo.e2eWebServerAddress, directory: 'src', skipFormat: true, webServerCommands: hasPlugin ? { - default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`, - production: `nx run ${options.projectName}:preview`, + default: e2eWebServerInfo.e2eWebServerCommand, + production: e2eWebServerInfo.e2eCiWebServerCommand, } : undefined, ciWebServerCommand: hasPlugin - ? `nx run ${options.projectName}:${options.e2eCiWebServerTarget}` + ? e2eWebServerInfo.e2eCiWebServerCommand : undefined, - ciBaseUrl: options.bundler === 'vite' ? options.e2eCiBaseUrl : undefined, + ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl, }); if ( @@ -472,10 +505,8 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, - webServerCommand: `${getPackageManagerCommand().exec} nx run ${ - options.projectName - }:${options.e2eCiWebServerTarget}`, - webServerAddress: options.e2eCiBaseUrl, + webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand, + webServerAddress: e2eWebServerInfo.e2eCiBaseUrl, addPlugin: options.addPlugin, }); @@ -590,57 +621,8 @@ async function normalizeOptions( nxJson.useInferencePlugins !== false; options.addPlugin ??= addPluginDefault; - let e2ePort = 4200; - - let e2eWebServerTarget = 'serve'; - let e2eCiWebServerTarget = - options.bundler === 'vite' ? 'preview' : 'serve-static'; - if (options.addPlugin) { - if (nxJson.plugins) { - for (const plugin of nxJson.plugins) { - if ( - options.bundler === 'vite' && - typeof plugin === 'object' && - plugin.plugin === '@nx/vite/plugin' - ) { - e2eCiWebServerTarget = - (plugin.options as VitePluginOptions)?.previewTargetName ?? - e2eCiWebServerTarget; - - e2eWebServerTarget = - (plugin.options as VitePluginOptions)?.serveTargetName ?? - e2eWebServerTarget; - } else if ( - options.bundler === 'webpack' && - typeof plugin === 'object' && - plugin.plugin === '@nx/webpack/plugin' - ) { - e2eCiWebServerTarget = - (plugin.options as WebpackPluginOptions)?.serveStaticTargetName ?? - e2eCiWebServerTarget; - - e2eWebServerTarget = - (plugin.options as WebpackPluginOptions)?.serveTargetName ?? - e2eWebServerTarget; - } - } - } - } - - if ( - nxJson.targetDefaults?.[e2eWebServerTarget] && - nxJson.targetDefaults?.[e2eWebServerTarget].options?.port - ) { - e2ePort = nxJson.targetDefaults?.[e2eWebServerTarget].options?.port; - } - const e2eProjectName = `${appProjectName}-e2e`; const e2eProjectRoot = `${appProjectRoot}-e2e`; - const e2eWebServerAddress = `http://localhost:${e2ePort}`; - const e2eCiBaseUrl = - options.bundler === 'vite' - ? 'http://localhost:4300' - : `http://localhost:${e2ePort}`; const npmScope = getNpmScope(host); @@ -664,11 +646,6 @@ async function normalizeOptions( appProjectRoot, e2eProjectRoot, e2eProjectName, - e2eWebServerAddress, - e2eWebServerTarget, - e2eCiWebServerTarget, - e2eCiBaseUrl, - e2ePort, parsedTags, }; } diff --git a/packages/webpack/index.ts b/packages/webpack/index.ts index 882f88d3ce7f0..01590ba79ef74 100644 --- a/packages/webpack/index.ts +++ b/packages/webpack/index.ts @@ -37,3 +37,4 @@ export * from './src/utils/get-css-module-local-ident'; export * from './src/utils/with-nx'; export * from './src/utils/with-web'; export * from './src/utils/module-federation/public-api'; +export * from './src/utils/e2e-web-server-info-utils'; diff --git a/packages/webpack/src/utils/e2e-web-server-info-utils.spec.ts b/packages/webpack/src/utils/e2e-web-server-info-utils.spec.ts new file mode 100644 index 0000000000000..9d878161196a7 --- /dev/null +++ b/packages/webpack/src/utils/e2e-web-server-info-utils.spec.ts @@ -0,0 +1,149 @@ +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import { type Tree, readNxJson, updateNxJson } from 'nx/src/devkit-exports'; +import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; +import { getWebpackE2EWebServerInfo } from './e2e-web-server-info-utils'; + +describe('getWebpackE2EWebServerInfo', () => { + let tree: Tree; + let tempFs: TempFs; + beforeEach(() => { + tempFs = new TempFs('e2e-webserver-info'); + tree = createTreeWithEmptyWorkspace(); + tree.root = tempFs.tempDir; + + tree.write(`app/webpack.config.ts`, ``); + tempFs.createFileSync(`app/webpack.config.ts`, ``); + }); + + afterEach(() => { + tempFs.cleanup(); + jest.resetModules(); + }); + + it('should use the default values when no plugin is registered and plugins are not being used', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getWebpackE2EWebServerInfo( + tree, + 'app', + 'app/webpack.config.ts', + false + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4200", + "e2eCiWebServerCommand": "npx nx run app:serve-static", + "e2eDevServerTarget": "app:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:serve", + } + `); + }); + + it('should use the default values of the plugin when the plugin is just a string', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins = ['@nx/webpack/plugin']; + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getWebpackE2EWebServerInfo( + tree, + 'app', + 'app/webpack.config.ts', + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4200", + "e2eCiWebServerCommand": "npx nx run app:serve-static", + "e2eDevServerTarget": "app:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:serve", + } + `); + }); + + it('should use the values of the registered plugin when there is no includes or excludes defined', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + nxJson.plugins.push({ + plugin: '@nx/webpack/plugin', + options: { + serveTargetName: 'webpack:serve', + serveStaticTargetName: 'webpack:preview', + }, + }); + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getWebpackE2EWebServerInfo( + tree, + 'app', + 'app/webpack.config.ts', + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4200", + "e2eCiWebServerCommand": "npx nx run app:webpack:preview", + "e2eDevServerTarget": "app:webpack:serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:webpack:serve", + } + `); + }); + + it('should use the values of the correct registered plugin when there are includes or excludes defined', async () => { + // ARRANGE + const nxJson = readNxJson(tree); + nxJson.plugins ??= []; + nxJson.plugins.push({ + plugin: '@nx/webpack/plugin', + options: { + serveTargetName: 'webpack:serve', + serveStaticTargetName: 'webpack:preview', + }, + include: ['libs/**'], + }); + nxJson.plugins.push({ + plugin: '@nx/webpack/plugin', + options: { + serveTargetName: 'webpack-serve', + serveStaticTargetName: 'webpack-preview', + }, + include: ['app/**'], + }); + updateNxJson(tree, nxJson); + + // ACT + const e2eWebServerInfo = await getWebpackE2EWebServerInfo( + tree, + 'app', + 'app/webpack.config.ts', + true + ); + + // ASSERT + expect(e2eWebServerInfo).toMatchInlineSnapshot(` + { + "e2eCiBaseUrl": "http://localhost:4200", + "e2eCiWebServerCommand": "npx nx run app:webpack-preview", + "e2eDevServerTarget": "app:webpack-serve", + "e2eWebServerAddress": "http://localhost:4200", + "e2eWebServerCommand": "npx nx run app:webpack-serve", + } + `); + }); +}); diff --git a/packages/webpack/src/utils/e2e-web-server-info-utils.ts b/packages/webpack/src/utils/e2e-web-server-info-utils.ts new file mode 100644 index 0000000000000..03599526df612 --- /dev/null +++ b/packages/webpack/src/utils/e2e-web-server-info-utils.ts @@ -0,0 +1,39 @@ +import { type Tree, readNxJson } from '@nx/devkit'; +import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; + +export async function getWebpackE2EWebServerInfo( + tree: Tree, + projectName: string, + configFilePath: string, + isPluginBeingAdded: boolean, + e2ePortOverride?: number +) { + const nxJson = readNxJson(tree); + let e2ePort = e2ePortOverride ?? 4200; + + if ( + nxJson.targetDefaults?.['serve'] && + nxJson.targetDefaults?.['serve'].options?.port + ) { + e2ePort = nxJson.targetDefaults?.['serve'].options?.port; + } + + return getE2EWebServerInfo( + tree, + projectName, + { + plugin: '@nx/webpack/plugin', + serveTargetName: 'serveTargetName', + serveStaticTargetName: 'serveStaticTargetName', + configFilePath, + }, + { + defaultServeTargetName: 'serve', + defaultServeStaticTargetName: 'serve-static', + defaultE2EWebServerAddress: `http://localhost:${e2ePort}`, + defaultE2ECiBaseUrl: 'http://localhost:4200', + defaultE2EPort: e2ePort, + }, + isPluginBeingAdded + ); +}