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 <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> 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 <!-- This is the behavior we should expect with the changes in this PR --> 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) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
57f3701372
commit
320d9f223f
@ -76,7 +76,7 @@
|
|||||||
"description": "Adds the specified e2e test runner",
|
"description": "Adds the specified e2e test runner",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["playwright", "cypress", "detox", "none"],
|
"enum": ["playwright", "cypress", "detox", "none"],
|
||||||
"default": "playwright"
|
"default": "none"
|
||||||
},
|
},
|
||||||
"standaloneConfig": {
|
"standaloneConfig": {
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
|
|||||||
@ -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(
|
runCLI(
|
||||||
`generate @nx/web:static-config --buildTarget=${reactAppName}:build --targetName=custom-serve-static --no-interactive`,
|
`generate @nx/web:static-config --buildTarget=${reactAppName}:build --targetName=custom-serve-static --no-interactive`,
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { Tree } from '@nx/devkit';
|
import { Tree } from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
@ -13,6 +13,7 @@ import { nxVersion } from '../../../utils/versions';
|
|||||||
import { getInstalledAngularVersionInfo } from '../../utils/version-utils';
|
import { getInstalledAngularVersionInfo } from '../../utils/version-utils';
|
||||||
import type { NormalizedSchema } from './normalized-schema';
|
import type { NormalizedSchema } from './normalized-schema';
|
||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
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) {
|
export async function addE2e(tree: Tree, options: NormalizedSchema) {
|
||||||
// since e2e are separate projects, default to adding plugins
|
// 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' &&
|
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||||
nxJson.useInferencePlugins !== 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') {
|
if (options.e2eTestRunner === 'cypress') {
|
||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
>('@nx/cypress', nxVersion);
|
>('@nx/cypress', nxVersion);
|
||||||
// TODO: This can call `@nx/web:static-config` generator when ready
|
|
||||||
addFileServerTarget(tree, options, 'serve-static');
|
|
||||||
addProjectConfiguration(tree, options.e2eProjectName, {
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
@ -41,8 +49,14 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) {
|
|||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
skipPackageJson: options.skipPackageJson,
|
skipPackageJson: options.skipPackageJson,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
devServerTarget: `${options.name}:${options.e2eWebServerTarget}:development`,
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
||||||
baseUrl: options.e2eWebServerAddress,
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
|
webServerCommands: {
|
||||||
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
|
production: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
|
},
|
||||||
|
ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
addPlugin,
|
addPlugin,
|
||||||
});
|
});
|
||||||
@ -73,10 +87,8 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) {
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx ${
|
webServerCommand: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
options.e2eWebServerTarget
|
webServerAddress: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
} ${options.name}`,
|
|
||||||
webServerAddress: options.e2eWebServerAddress,
|
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
addPlugin,
|
addPlugin,
|
||||||
});
|
});
|
||||||
@ -94,7 +106,8 @@ export async function addE2e(tree: Tree, options: NormalizedSchema) {
|
|||||||
function addFileServerTarget(
|
function addFileServerTarget(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: NormalizedSchema,
|
options: NormalizedSchema,
|
||||||
targetName: string
|
targetName: string,
|
||||||
|
e2ePort: number
|
||||||
) {
|
) {
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
addDependenciesToPackageJson(tree, {}, { '@nx/web': nxVersion });
|
addDependenciesToPackageJson(tree, {}, { '@nx/web': nxVersion });
|
||||||
@ -109,7 +122,7 @@ function addFileServerTarget(
|
|||||||
executor: '@nx/web:file-server',
|
executor: '@nx/web:file-server',
|
||||||
options: {
|
options: {
|
||||||
buildTarget: `${options.name}:build`,
|
buildTarget: `${options.name}:build`,
|
||||||
port: options.e2ePort,
|
port: e2ePort,
|
||||||
staticFilePath: isUsingApplicationBuilder
|
staticFilePath: isUsingApplicationBuilder
|
||||||
? joinPathFragments(options.outputPath, 'browser')
|
? joinPathFragments(options.outputPath, 'browser')
|
||||||
: undefined,
|
: undefined,
|
||||||
@ -118,3 +131,32 @@ function addFileServerTarget(
|
|||||||
};
|
};
|
||||||
updateProjectConfiguration(tree, options.name, projectConfig);
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -26,21 +26,9 @@ export async function normalizeOptions(
|
|||||||
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
||||||
|
|
||||||
const nxJson = readNxJson(host);
|
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 e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||||
const e2eWebServerAddress = `http://localhost:${e2ePort}`;
|
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
@ -72,9 +60,6 @@ export async function normalizeOptions(
|
|||||||
appProjectSourceRoot: `${appProjectRoot}/src`,
|
appProjectSourceRoot: `${appProjectRoot}/src`,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2ePort,
|
|
||||||
parsedTags,
|
parsedTags,
|
||||||
bundler,
|
bundler,
|
||||||
outputPath: joinPathFragments(
|
outputPath: joinPathFragments(
|
||||||
|
|||||||
@ -12,9 +12,6 @@ export interface NormalizedSchema extends Schema {
|
|||||||
appProjectSourceRoot: string;
|
appProjectSourceRoot: string;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2ePort: number;
|
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
outputPath: string;
|
outputPath: string;
|
||||||
}
|
}
|
||||||
|
|||||||
248
packages/devkit/src/generators/e2e-web-server-info-utils.spec.ts
Normal file
248
packages/devkit/src/generators/e2e-web-server-info-utils.spec.ts
Normal file
@ -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",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
126
packages/devkit/src/generators/e2e-web-server-info-utils.ts
Normal file
126
packages/devkit/src/generators/e2e-web-server-info-utils.ts
Normal file
@ -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<E2EWebServerDetails> {
|
||||||
|
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<E2EWebServerDetails> {
|
||||||
|
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
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
import { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
@ -13,14 +13,13 @@ import { hasExpoPlugin } from '../../../utils/has-expo-plugin';
|
|||||||
import { NormalizedSchema } from './normalize-options';
|
import { NormalizedSchema } from './normalize-options';
|
||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
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(
|
export async function addE2e(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: NormalizedSchema
|
options: NormalizedSchema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
const hasPlugin = hasExpoPlugin(tree);
|
const hasPlugin = hasExpoPlugin(tree);
|
||||||
switch (options.e2eTestRunner) {
|
|
||||||
case 'cypress': {
|
|
||||||
if (!hasPlugin) {
|
if (!hasPlugin) {
|
||||||
await webStaticServeGenerator(tree, {
|
await webStaticServeGenerator(tree, {
|
||||||
buildTarget: `${options.projectName}:export`,
|
buildTarget: `${options.projectName}:export`,
|
||||||
@ -28,6 +27,15 @@ export async function addE2e(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const e2eWebServerInfo = await getExpoE2EWebServerInfo(
|
||||||
|
tree,
|
||||||
|
options.projectName,
|
||||||
|
joinPathFragments(options.appProjectRoot, 'app.json'),
|
||||||
|
options.addPlugin
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (options.e2eTestRunner) {
|
||||||
|
case 'cypress': {
|
||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
>('@nx/cypress', nxVersion);
|
>('@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
|
// the name and root are already normalized, instruct the generator to use them as is
|
||||||
bundler: 'none',
|
bundler: 'none',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`,
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
||||||
port: options.e2ePort,
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
baseUrl: options.e2eWebServerAddress,
|
ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
ciWebServerCommand: hasPlugin
|
webServerCommands: {
|
||||||
? `nx run ${options.projectName}:serve-static`
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
: undefined,
|
production: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
|
},
|
||||||
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
jsx: true,
|
jsx: true,
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
});
|
});
|
||||||
@ -112,10 +122,8 @@ export async function addE2e(
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx ${
|
webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
options.e2eWebServerTarget
|
webServerAddress: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
} ${options.name}`,
|
|
||||||
webServerAddress: options.e2eWebServerAddress,
|
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
});
|
});
|
||||||
@ -172,3 +180,39 @@ export async function addE2e(
|
|||||||
return () => {};
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -40,9 +40,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'my-app-e2e',
|
e2eProjectRoot: 'my-app-e2e',
|
||||||
e2ePort: 8081,
|
|
||||||
e2eWebServerAddress: 'http://localhost:8081',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
} as NormalizedSchema);
|
} as NormalizedSchema);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -75,9 +72,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'myApp-e2e',
|
e2eProjectName: 'myApp-e2e',
|
||||||
e2eProjectRoot: 'myApp-e2e',
|
e2eProjectRoot: 'myApp-e2e',
|
||||||
e2ePort: 8081,
|
|
||||||
e2eWebServerAddress: 'http://localhost:8081',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
} as NormalizedSchema);
|
} as NormalizedSchema);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -112,9 +106,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'directory-e2e',
|
e2eProjectRoot: 'directory-e2e',
|
||||||
e2ePort: 8081,
|
|
||||||
e2eWebServerAddress: 'http://localhost:8081',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
} as NormalizedSchema);
|
} as NormalizedSchema);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -147,9 +138,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'directory/my-app-e2e',
|
e2eProjectRoot: 'directory/my-app-e2e',
|
||||||
e2ePort: 8081,
|
|
||||||
e2eWebServerAddress: 'http://localhost:8081',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
} as NormalizedSchema);
|
} as NormalizedSchema);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -183,9 +171,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'my-app-e2e',
|
e2eProjectRoot: 'my-app-e2e',
|
||||||
e2ePort: 8081,
|
|
||||||
e2eWebServerAddress: 'http://localhost:8081',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
} as NormalizedSchema);
|
} as NormalizedSchema);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,9 +12,6 @@ export interface NormalizedSchema extends Schema {
|
|||||||
rootProject: boolean;
|
rootProject: boolean;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2ePort: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function normalizeOptions(
|
export async function normalizeOptions(
|
||||||
@ -46,38 +43,13 @@ export async function normalizeOptions(
|
|||||||
: [];
|
: [];
|
||||||
const rootProject = appProjectRoot === '.';
|
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 e2eProjectName = rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||||
const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||||
const e2eWebServerAddress = `http://localhost:${e2ePort}`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
unitTestRunner: options.unitTestRunner || 'jest',
|
unitTestRunner: options.unitTestRunner || 'jest',
|
||||||
e2eTestRunner: options.e2eTestRunner,
|
e2eTestRunner: options.e2eTestRunner || 'none',
|
||||||
name: projectNames.projectSimpleName,
|
name: projectNames.projectSimpleName,
|
||||||
className,
|
className,
|
||||||
lowerCaseName: className.toLowerCase(),
|
lowerCaseName: className.toLowerCase(),
|
||||||
@ -88,8 +60,5 @@ export async function normalizeOptions(
|
|||||||
rootProject,
|
rootProject,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2ePort,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,7 +76,7 @@
|
|||||||
"description": "Adds the specified e2e test runner",
|
"description": "Adds the specified e2e test runner",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["playwright", "cypress", "detox", "none"],
|
"enum": ["playwright", "cypress", "detox", "none"],
|
||||||
"default": "playwright"
|
"default": "none"
|
||||||
},
|
},
|
||||||
"standaloneConfig": {
|
"standaloneConfig": {
|
||||||
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { NormalizedSchema } from './normalize-options';
|
|||||||
import { webStaticServeGenerator } from '@nx/web';
|
import { webStaticServeGenerator } from '@nx/web';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
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) {
|
export async function addE2e(host: Tree, options: NormalizedSchema) {
|
||||||
const nxJson = readNxJson(host);
|
const nxJson = readNxJson(host);
|
||||||
@ -22,6 +23,13 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
: p.plugin === '@nx/next/plugin'
|
: p.plugin === '@nx/next/plugin'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const e2eWebServerInfo = await getNextE2EWebServerInfo(
|
||||||
|
host,
|
||||||
|
options.projectName,
|
||||||
|
joinPathFragments(options.appProjectRoot, 'next.config.js'),
|
||||||
|
options.addPlugin
|
||||||
|
);
|
||||||
|
|
||||||
if (options.e2eTestRunner === 'cypress') {
|
if (options.e2eTestRunner === 'cypress') {
|
||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
@ -50,17 +58,16 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
directory: 'src',
|
directory: 'src',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`,
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
||||||
baseUrl: options.e2eWebServerAddress,
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
jsx: true,
|
jsx: true,
|
||||||
webServerCommands: hasPlugin
|
webServerCommands: hasPlugin
|
||||||
? {
|
? {
|
||||||
default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`,
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
ciWebServerCommand: hasPlugin
|
ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
? `nx run ${options.projectName}:serve-static`
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
: undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -116,10 +123,8 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
webServerAddress: `http://127.0.0.1:${options.e2ePort}`,
|
webServerAddress: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx ${
|
webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
options.e2eWebServerTarget
|
|
||||||
} ${options.projectName}`,
|
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -156,3 +161,41 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
return () => {};
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -21,9 +21,6 @@ describe('updateEslint', () => {
|
|||||||
unitTestRunner: 'jest',
|
unitTestRunner: 'jest',
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'my-app-e2e',
|
e2eProjectRoot: 'my-app-e2e',
|
||||||
e2ePort: 3000,
|
|
||||||
e2eWebServerTarget: 'start',
|
|
||||||
e2eWebServerAddress: 'http://localhost:4200',
|
|
||||||
outputPath: 'dist/my-app',
|
outputPath: 'dist/my-app',
|
||||||
name: 'my-app',
|
name: 'my-app',
|
||||||
parsedTags: [],
|
parsedTags: [],
|
||||||
|
|||||||
@ -11,9 +11,6 @@ export interface NormalizedSchema extends Schema {
|
|||||||
outputPath: string;
|
outputPath: string;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2ePort: number;
|
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
fileName: string;
|
fileName: string;
|
||||||
styledModule: null | string;
|
styledModule: null | string;
|
||||||
@ -46,36 +43,8 @@ export async function normalizeOptions(
|
|||||||
|
|
||||||
options.addPlugin ??= addPlugin;
|
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 e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||||
const e2eWebServerAddress = `http://localhost:${e2ePort}`;
|
|
||||||
|
|
||||||
const name = names(options.name).fileName;
|
const name = names(options.name).fileName;
|
||||||
|
|
||||||
@ -107,9 +76,6 @@ export async function normalizeOptions(
|
|||||||
appProjectRoot,
|
appProjectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2ePort,
|
|
||||||
e2eTestRunner: options.e2eTestRunner || 'playwright',
|
e2eTestRunner: options.e2eTestRunner || 'playwright',
|
||||||
fileName,
|
fileName,
|
||||||
linter: options.linter || Linter.EsLint,
|
linter: options.linter || Linter.EsLint,
|
||||||
|
|||||||
@ -3,14 +3,24 @@ import {
|
|||||||
ensurePackage,
|
ensurePackage,
|
||||||
getPackageManagerCommand,
|
getPackageManagerCommand,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
readNxJson,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
||||||
import { nxVersion } from '../../../utils/versions';
|
import { nxVersion } from '../../../utils/versions';
|
||||||
import { NormalizedSchema } from '../schema';
|
import { NormalizedSchema } from '../schema';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
|
|
||||||
export async function addE2e(host: Tree, options: NormalizedSchema) {
|
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') {
|
if (options.e2eTestRunner === 'cypress') {
|
||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
@ -29,14 +39,13 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
directory: 'src',
|
directory: 'src',
|
||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`,
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
||||||
webServerCommands: {
|
webServerCommands: {
|
||||||
default: `${getPackageManagerCommand().exec} nx ${
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
options.e2eWebServerTarget
|
|
||||||
} ${options.projectName}`,
|
|
||||||
},
|
},
|
||||||
ciWebServerCommand: `nx run ${options.projectName}:serve-static`,
|
ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
baseUrl: options.e2eWebServerAddress,
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
jsx: true,
|
jsx: true,
|
||||||
addPlugin: true,
|
addPlugin: true,
|
||||||
});
|
});
|
||||||
@ -85,10 +94,8 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
webServerAddress: options.e2eWebServerAddress,
|
webServerAddress: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx ${
|
webServerCommand: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
options.e2eWebServerTarget
|
|
||||||
} ${options.projectName}`,
|
|
||||||
addPlugin: true,
|
addPlugin: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -118,3 +125,38 @@ export async function addE2e(host: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
return () => {};
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -32,30 +32,9 @@ export async function normalizeOptions(
|
|||||||
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
||||||
|
|
||||||
const nxJson = readNxJson(host);
|
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 e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||||
const e2eWebServerAddress = `http://localhost:${e2ePort}`;
|
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
@ -68,9 +47,6 @@ export async function normalizeOptions(
|
|||||||
appProjectRoot,
|
appProjectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2ePort,
|
|
||||||
parsedTags,
|
parsedTags,
|
||||||
style: options.style ?? 'none',
|
style: options.style ?? 'none',
|
||||||
} as NormalizedSchema;
|
} as NormalizedSchema;
|
||||||
|
|||||||
@ -23,8 +23,5 @@ export interface NormalizedSchema extends Schema {
|
|||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2ePort: number;
|
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,8 +18,6 @@ export async function addE2e(
|
|||||||
styledModule: null,
|
styledModule: null,
|
||||||
hasStyles: false,
|
hasStyles: false,
|
||||||
unitTestRunner: 'none',
|
unitTestRunner: 'none',
|
||||||
e2eCiWebServerTarget: options.e2eWebServerTarget,
|
|
||||||
e2eCiBaseUrl: options.e2eWebServerAddress,
|
|
||||||
});
|
});
|
||||||
case 'playwright':
|
case 'playwright':
|
||||||
return addE2eReact(host, {
|
return addE2eReact(host, {
|
||||||
@ -29,8 +27,6 @@ export async function addE2e(
|
|||||||
styledModule: null,
|
styledModule: null,
|
||||||
hasStyles: false,
|
hasStyles: false,
|
||||||
unitTestRunner: 'none',
|
unitTestRunner: 'none',
|
||||||
e2eCiWebServerTarget: options.e2eWebServerTarget,
|
|
||||||
e2eCiBaseUrl: options.e2eWebServerAddress,
|
|
||||||
});
|
});
|
||||||
case 'detox':
|
case 'detox':
|
||||||
const { detoxApplicationGenerator } = ensurePackage<
|
const { detoxApplicationGenerator } = ensurePackage<
|
||||||
|
|||||||
@ -44,9 +44,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'my-app-e2e',
|
e2eProjectRoot: 'my-app-e2e',
|
||||||
e2ePort: 4200,
|
|
||||||
e2eWebServerAddress: 'http://localhost:4200',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -83,9 +80,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'myApp-e2e',
|
e2eProjectRoot: 'myApp-e2e',
|
||||||
e2ePort: 4200,
|
|
||||||
e2eWebServerAddress: 'http://localhost:4200',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -124,9 +118,6 @@ describe('Normalize Options', () => {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'directory/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,
|
rootProject: false,
|
||||||
e2eProjectName: 'directory/my-app-e2e',
|
e2eProjectName: 'directory/my-app-e2e',
|
||||||
e2eProjectRoot: '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,
|
rootProject: false,
|
||||||
e2eProjectName: 'my-app-e2e',
|
e2eProjectName: 'my-app-e2e',
|
||||||
e2eProjectRoot: 'my-app-e2e',
|
e2eProjectRoot: 'my-app-e2e',
|
||||||
e2ePort: 4200,
|
|
||||||
e2eWebServerAddress: 'http://localhost:4200',
|
|
||||||
e2eWebServerTarget: 'serve',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -17,9 +17,6 @@ export interface NormalizedSchema extends Schema {
|
|||||||
rootProject: boolean;
|
rootProject: boolean;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2ePort: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function normalizeOptions(
|
export async function normalizeOptions(
|
||||||
@ -50,34 +47,8 @@ export async function normalizeOptions(
|
|||||||
const androidProjectRoot = joinPathFragments(appProjectRoot, 'android');
|
const androidProjectRoot = joinPathFragments(appProjectRoot, 'android');
|
||||||
const rootProject = appProjectRoot === '.';
|
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 e2eProjectName = rootProject ? 'e2e' : `${fileName}-e2e`;
|
||||||
const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
const e2eProjectRoot = rootProject ? 'e2e' : `${appProjectRoot}-e2e`;
|
||||||
const e2eWebServerAddress = `http://localhost:${e2ePort}`;
|
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
@ -101,8 +72,5 @@ export async function normalizeOptions(
|
|||||||
rootProject,
|
rootProject,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2ePort,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,7 +86,7 @@ describe('app', () => {
|
|||||||
import { defineConfig } from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
|
|
||||||
export default defineConfig({
|
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' }
|
baseUrl: 'http://localhost:4200' }
|
||||||
});
|
});
|
||||||
"
|
"
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { hasVitePlugin } from '../../../utils/has-vite-plugin';
|
|||||||
import { NormalizedSchema } from '../schema';
|
import { NormalizedSchema } from '../schema';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
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(
|
export async function addE2e(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
@ -22,6 +23,49 @@ export async function addE2e(
|
|||||||
const hasNxBuildPlugin =
|
const hasNxBuildPlugin =
|
||||||
(options.bundler === 'webpack' && hasWebpackPlugin(tree)) ||
|
(options.bundler === 'webpack' && hasWebpackPlugin(tree)) ||
|
||||||
(options.bundler === 'vite' && hasVitePlugin(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) {
|
if (!hasNxBuildPlugin) {
|
||||||
await webStaticServeGenerator(tree, {
|
await webStaticServeGenerator(tree, {
|
||||||
buildTarget: `${options.projectName}:build`,
|
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
|
// the name and root are already normalized, instruct the generator to use them as is
|
||||||
bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler,
|
bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`,
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
||||||
baseUrl: options.e2eWebServerAddress,
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
jsx: true,
|
jsx: true,
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
webServerCommands: hasNxBuildPlugin
|
webServerCommands: hasNxBuildPlugin
|
||||||
? {
|
? {
|
||||||
default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`,
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
production: `nx run ${options.projectName}:preview`,
|
production: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
ciWebServerCommand: hasNxBuildPlugin
|
ciWebServerCommand: hasNxBuildPlugin
|
||||||
? `nx run ${options.projectName}:${options.e2eCiWebServerTarget}`
|
? e2eWebServerInfo.e2eCiWebServerCommand
|
||||||
: undefined,
|
: undefined,
|
||||||
ciBaseUrl:
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
options.bundler === 'vite' ? options.e2eCiBaseUrl : undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -127,10 +170,8 @@ export async function addE2e(
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx run ${
|
webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
options.projectName
|
webServerAddress: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
}:${options.e2eCiWebServerTarget}`,
|
|
||||||
webServerAddress: options.e2eCiBaseUrl,
|
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -46,57 +46,8 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
|||||||
options.rootProject = appProjectRoot === '.';
|
options.rootProject = appProjectRoot === '.';
|
||||||
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
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 e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
||||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${appProjectRoot}-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
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
@ -117,11 +68,6 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
|||||||
appProjectRoot,
|
appProjectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2eCiWebServerTarget,
|
|
||||||
e2eCiBaseUrl,
|
|
||||||
e2ePort,
|
|
||||||
parsedTags,
|
parsedTags,
|
||||||
fileName,
|
fileName,
|
||||||
styledModule,
|
styledModule,
|
||||||
|
|||||||
@ -37,11 +37,6 @@ export interface NormalizedSchema<T extends Schema = Schema> extends T {
|
|||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2eCiWebServerTarget: string;
|
|
||||||
e2eCiBaseUrl: string;
|
|
||||||
e2ePort: number;
|
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
fileName: string;
|
fileName: string;
|
||||||
styledModule: null | SupportedStyles;
|
styledModule: null | SupportedStyles;
|
||||||
|
|||||||
@ -153,7 +153,12 @@ export default defineConfig({
|
|||||||
e2e: {
|
e2e: {
|
||||||
...nxE2EPreset(__filename, {
|
...nxE2EPreset(__filename, {
|
||||||
cypressDir: 'src',
|
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',
|
baseUrl: 'http://localhost:3000',
|
||||||
},
|
},
|
||||||
@ -189,7 +194,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
/* Run your local dev server before starting the tests */
|
/* Run your local dev server before starting the tests */
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npx nx dev test',
|
command: 'npx nx run test:serve-static',
|
||||||
url: 'http://localhost:3000',
|
url: 'http://localhost:3000',
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: !process.env.CI,
|
||||||
cwd: workspaceRoot,
|
cwd: workspaceRoot,
|
||||||
@ -665,7 +670,12 @@ export default defineConfig({
|
|||||||
e2e: {
|
e2e: {
|
||||||
...nxE2EPreset(__filename, {
|
...nxE2EPreset(__filename, {
|
||||||
cypressDir: 'src',
|
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',
|
baseUrl: 'http://localhost:3000',
|
||||||
},
|
},
|
||||||
@ -701,7 +711,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
/* Run your local dev server before starting the tests */
|
/* Run your local dev server before starting the tests */
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npx nx dev test',
|
command: 'npx nx run test:serve-static',
|
||||||
url: 'http://localhost:3000',
|
url: 'http://localhost:3000',
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: !process.env.CI,
|
||||||
cwd: workspaceRoot,
|
cwd: workspaceRoot,
|
||||||
@ -1033,7 +1043,12 @@ export default defineConfig({
|
|||||||
e2e: {
|
e2e: {
|
||||||
...nxE2EPreset(__filename, {
|
...nxE2EPreset(__filename, {
|
||||||
cypressDir: 'src',
|
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',
|
baseUrl: 'http://localhost:3000',
|
||||||
},
|
},
|
||||||
@ -1434,7 +1449,7 @@ export default defineConfig({
|
|||||||
},
|
},
|
||||||
/* Run your local dev server before starting the tests */
|
/* Run your local dev server before starting the tests */
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'npx nx dev test',
|
command: 'npx nx run test:serve-static',
|
||||||
url: 'http://localhost:3000',
|
url: 'http://localhost:3000',
|
||||||
reuseExistingServer: !process.env.CI,
|
reuseExistingServer: !process.env.CI,
|
||||||
cwd: workspaceRoot,
|
cwd: workspaceRoot,
|
||||||
|
|||||||
@ -97,7 +97,7 @@ export async function remixApplicationGeneratorInternal(
|
|||||||
cwd: options.projectRoot,
|
cwd: options.projectRoot,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
['static-serve']: {
|
['serve-static']: {
|
||||||
dependsOn: ['build'],
|
dependsOn: ['build'],
|
||||||
command: `remix-serve build/index.js`,
|
command: `remix-serve build/index.js`,
|
||||||
options: {
|
options: {
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import { type NormalizedSchema } from './normalize-options';
|
|||||||
import { getPackageVersion } from '../../../utils/versions';
|
import { getPackageVersion } from '../../../utils/versions';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
||||||
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
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) {
|
export async function addE2E(tree: Tree, options: NormalizedSchema) {
|
||||||
const hasRemixPlugin = readNxJson(tree).plugins?.find((p) =>
|
const hasRemixPlugin = readNxJson(tree).plugins?.find((p) =>
|
||||||
@ -19,6 +20,14 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) {
|
|||||||
? p === '@nx/remix/plugin'
|
? p === '@nx/remix/plugin'
|
||||||
: p.plugin === '@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') {
|
if (options.e2eTestRunner === 'cypress') {
|
||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
@ -37,8 +46,18 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) {
|
|||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
directory: 'src',
|
directory: 'src',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}:development`,
|
devServerTarget: e2eWebsServerInfo.e2eDevServerTarget,
|
||||||
baseUrl: options.e2eWebServerAddress,
|
baseUrl: e2eWebsServerInfo.e2eWebServerAddress,
|
||||||
|
webServerCommands: hasRemixPlugin
|
||||||
|
? {
|
||||||
|
default: e2eWebsServerInfo.e2eWebServerCommand,
|
||||||
|
production: e2eWebsServerInfo.e2eCiWebServerCommand,
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
ciWebServerCommand: hasRemixPlugin
|
||||||
|
? e2eWebsServerInfo.e2eCiWebServerCommand
|
||||||
|
: undefined,
|
||||||
|
ciBaseUrl: e2eWebsServerInfo.e2eCiBaseUrl,
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -97,10 +116,8 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) {
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: false,
|
setParserOptionsProject: false,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx ${
|
webServerCommand: e2eWebsServerInfo.e2eCiWebServerCommand,
|
||||||
options.e2eWebServerTarget
|
webServerAddress: e2eWebsServerInfo.e2eCiBaseUrl,
|
||||||
} ${options.name}`,
|
|
||||||
webServerAddress: options.e2eWebServerAddress,
|
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
});
|
});
|
||||||
@ -139,3 +156,41 @@ export async function addE2E(tree: Tree, options: NormalizedSchema) {
|
|||||||
return () => {};
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -9,9 +9,6 @@ export interface NormalizedSchema extends NxRemixGeneratorSchema {
|
|||||||
projectRoot: string;
|
projectRoot: string;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2ePort: number;
|
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,35 +33,8 @@ export async function normalizeOptions(
|
|||||||
nxJson.useInferencePlugins !== false;
|
nxJson.useInferencePlugins !== false;
|
||||||
options.addPlugin ??= addPluginDefault;
|
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 e2eProjectName = options.rootProject ? 'e2e' : `${projectName}-e2e`;
|
||||||
const e2eProjectRoot = options.rootProject ? 'e2e' : `${projectRoot}-e2e`;
|
const e2eProjectRoot = options.rootProject ? 'e2e' : `${projectRoot}-e2e`;
|
||||||
const e2eWebServerAddress = `http://localhost:${e2ePort}`;
|
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
@ -77,9 +47,6 @@ export async function normalizeOptions(
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2ePort,
|
|
||||||
parsedTags,
|
parsedTags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,15 @@ exports[`@nx/remix/plugin non-root project should create nodes 1`] = `
|
|||||||
"cwd": "my-app",
|
"cwd": "my-app",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"serve-static": {
|
||||||
|
"command": "remix-serve build/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
},
|
||||||
"start": {
|
"start": {
|
||||||
"command": "remix-serve build/index.js",
|
"command": "remix-serve build/index.js",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
@ -110,6 +119,15 @@ exports[`@nx/remix/plugin root project should create nodes 1`] = `
|
|||||||
"cwd": ".",
|
"cwd": ".",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"serve-static": {
|
||||||
|
"command": "remix-serve build/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
"start": {
|
"start": {
|
||||||
"command": "remix-serve build/index.js",
|
"command": "remix-serve build/index.js",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
|
|||||||
@ -45,7 +45,11 @@ export interface RemixPluginOptions {
|
|||||||
devTargetName?: string;
|
devTargetName?: string;
|
||||||
startTargetName?: string;
|
startTargetName?: string;
|
||||||
typecheckTargetName?: string;
|
typecheckTargetName?: string;
|
||||||
|
/**
|
||||||
|
* @deprecated Use serveStaticTargetName instead. This option will be removed in Nx 21.
|
||||||
|
*/
|
||||||
staticServeTargetName?: string;
|
staticServeTargetName?: string;
|
||||||
|
serveStaticTargetName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createNodes: CreateNodes<RemixPluginOptions> = [
|
export const createNodes: CreateNodes<RemixPluginOptions> = [
|
||||||
@ -116,11 +120,17 @@ async function buildRemixTargets(
|
|||||||
serverBuildPath,
|
serverBuildPath,
|
||||||
options.buildTargetName
|
options.buildTargetName
|
||||||
);
|
);
|
||||||
|
// TODO(colum): Remove for Nx 21
|
||||||
targets[options.staticServeTargetName] = startTarget(
|
targets[options.staticServeTargetName] = startTarget(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
serverBuildPath,
|
serverBuildPath,
|
||||||
options.buildTargetName
|
options.buildTargetName
|
||||||
);
|
);
|
||||||
|
targets[options.serveStaticTargetName] = startTarget(
|
||||||
|
projectRoot,
|
||||||
|
serverBuildPath,
|
||||||
|
options.buildTargetName
|
||||||
|
);
|
||||||
targets[options.typecheckTargetName] = typecheckTarget(
|
targets[options.typecheckTargetName] = typecheckTarget(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
namedInputs,
|
namedInputs,
|
||||||
@ -233,7 +243,9 @@ function normalizeOptions(options: RemixPluginOptions) {
|
|||||||
options.devTargetName ??= 'dev';
|
options.devTargetName ??= 'dev';
|
||||||
options.startTargetName ??= 'start';
|
options.startTargetName ??= 'start';
|
||||||
options.typecheckTargetName ??= 'typecheck';
|
options.typecheckTargetName ??= 'typecheck';
|
||||||
|
// TODO(colum): remove for Nx 21
|
||||||
options.staticServeTargetName ??= 'static-serve';
|
options.staticServeTargetName ??= 'static-serve';
|
||||||
|
options.serveStaticTargetName ??= 'serve-static';
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
export * from './src/utils/versions';
|
export * from './src/utils/versions';
|
||||||
export * from './src/utils/generator-utils';
|
export * from './src/utils/generator-utils';
|
||||||
|
export * from './src/utils/e2e-web-server-info-utils';
|
||||||
export { type ViteConfigurationGeneratorSchema } from './src/generators/configuration/schema';
|
export { type ViteConfigurationGeneratorSchema } from './src/generators/configuration/schema';
|
||||||
export { viteConfigurationGenerator } from './src/generators/configuration/configuration';
|
export { viteConfigurationGenerator } from './src/generators/configuration/configuration';
|
||||||
export { type VitestGeneratorSchema } from './src/generators/vitest/schema';
|
export { type VitestGeneratorSchema } from './src/generators/vitest/schema';
|
||||||
|
|||||||
149
packages/vite/src/utils/e2e-web-server-info-utils.spec.ts
Normal file
149
packages/vite/src/utils/e2e-web-server-info-utils.spec.ts
Normal file
@ -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",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
39
packages/vite/src/utils/e2e-web-server-info-utils.ts
Normal file
39
packages/vite/src/utils/e2e-web-server-info-utils.ts
Normal file
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -141,10 +141,10 @@ export default defineConfig({
|
|||||||
cypressDir: 'src',
|
cypressDir: 'src',
|
||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
webServerCommands: {
|
webServerCommands: {
|
||||||
default: 'nx run test:serve',
|
default: 'npx nx run test:serve',
|
||||||
production: 'nx run test:preview',
|
production: 'npx nx run test:preview',
|
||||||
},
|
},
|
||||||
ciWebServerCommand: 'nx run test:preview',
|
ciWebServerCommand: 'npx nx run test:preview',
|
||||||
ciBaseUrl: 'http://localhost:4300',
|
ciBaseUrl: 'http://localhost:4300',
|
||||||
}),
|
}),
|
||||||
baseUrl: 'http://localhost:4200',
|
baseUrl: 'http://localhost:4200',
|
||||||
|
|||||||
@ -23,16 +23,21 @@ export async function addE2e(
|
|||||||
? p === '@nx/vite/plugin'
|
? p === '@nx/vite/plugin'
|
||||||
: p.plugin === '@nx/vite/plugin'
|
: p.plugin === '@nx/vite/plugin'
|
||||||
);
|
);
|
||||||
const e2eWebServerTarget = hasPlugin
|
const { getViteE2EWebServerInfo } = ensurePackage<typeof import('@nx/vite')>(
|
||||||
? typeof hasPlugin === 'string'
|
'@nx/vite',
|
||||||
? 'serve'
|
nxVersion
|
||||||
: (hasPlugin.options as any)?.serveTargetName ?? 'serve'
|
);
|
||||||
: 'serve';
|
const e2eWebServerInfo = await getViteE2EWebServerInfo(
|
||||||
const e2eCiWebServerTarget = hasPlugin
|
tree,
|
||||||
? typeof hasPlugin === 'string'
|
options.projectName,
|
||||||
? 'preview'
|
joinPathFragments(
|
||||||
: (hasPlugin.options as any)?.previewTargetName ?? 'preview'
|
options.appProjectRoot,
|
||||||
: 'preview';
|
`vite.config.${options.js ? 'js' : 'ts'}`
|
||||||
|
),
|
||||||
|
options.addPlugin,
|
||||||
|
options.devServerPort ?? 4200
|
||||||
|
);
|
||||||
|
|
||||||
switch (options.e2eTestRunner) {
|
switch (options.e2eTestRunner) {
|
||||||
case 'cypress': {
|
case 'cypress': {
|
||||||
if (!hasPlugin) {
|
if (!hasPlugin) {
|
||||||
@ -60,17 +65,17 @@ export async function addE2e(
|
|||||||
directory: 'src',
|
directory: 'src',
|
||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
devServerTarget: `${options.projectName}:${e2eWebServerTarget}`,
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
||||||
baseUrl: 'http://localhost:4200',
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
jsx: true,
|
jsx: true,
|
||||||
webServerCommands: hasPlugin
|
webServerCommands: hasPlugin
|
||||||
? {
|
? {
|
||||||
default: `nx run ${options.projectName}:${e2eWebServerTarget}`,
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
production: `nx run ${options.projectName}:preview`,
|
production: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
ciWebServerCommand: `nx run ${options.projectName}:${e2eCiWebServerTarget}`,
|
ciWebServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
ciBaseUrl: 'http://localhost:4300',
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -130,10 +135,8 @@ export async function addE2e(
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx run ${
|
webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
options.projectName
|
webServerAddress: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
}:${e2eCiWebServerTarget}`,
|
|
||||||
webServerAddress: 'http://localhost:4300',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -192,10 +192,10 @@ describe('app', () => {
|
|||||||
cypressDir: 'src',
|
cypressDir: 'src',
|
||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
webServerCommands: {
|
webServerCommands: {
|
||||||
default: 'nx run cool-app:serve',
|
default: 'npx nx run cool-app:serve',
|
||||||
production: 'nx run cool-app:preview',
|
production: 'npx nx run cool-app:preview',
|
||||||
},
|
},
|
||||||
ciWebServerCommand: 'nx run cool-app:preview',
|
ciWebServerCommand: 'npx nx run cool-app:preview',
|
||||||
ciBaseUrl: 'http://localhost:4300',
|
ciBaseUrl: 'http://localhost:4300',
|
||||||
}),
|
}),
|
||||||
baseUrl: 'http://localhost:4200',
|
baseUrl: 'http://localhost:4200',
|
||||||
@ -225,10 +225,11 @@ describe('app', () => {
|
|||||||
...nxE2EPreset(__filename, {
|
...nxE2EPreset(__filename, {
|
||||||
cypressDir: 'src',
|
cypressDir: 'src',
|
||||||
webServerCommands: {
|
webServerCommands: {
|
||||||
default: 'nx run cool-app:serve',
|
default: 'npx nx run cool-app:serve',
|
||||||
production: 'nx run cool-app:preview',
|
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',
|
baseUrl: 'http://localhost:4200',
|
||||||
},
|
},
|
||||||
|
|||||||
@ -47,17 +47,13 @@ import { VitePluginOptions } from '@nx/vite/src/plugins/plugin';
|
|||||||
import { WebpackPluginOptions } from '@nx/webpack/src/plugins/plugin';
|
import { WebpackPluginOptions } from '@nx/webpack/src/plugins/plugin';
|
||||||
import staticServeConfiguration from '../static-serve/static-serve-configuration';
|
import staticServeConfiguration from '../static-serve/static-serve-configuration';
|
||||||
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
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 {
|
interface NormalizedSchema extends Schema {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
e2eWebServerAddress: string;
|
|
||||||
e2eWebServerTarget: string;
|
|
||||||
e2eCiWebServerTarget: string;
|
|
||||||
e2eCiBaseUrl: string;
|
|
||||||
e2ePort: number;
|
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,6 +387,43 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
spa: true,
|
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') {
|
if (options.e2eTestRunner === 'cypress') {
|
||||||
const { configurationGenerator } = ensurePackage<
|
const { configurationGenerator } = ensurePackage<
|
||||||
typeof import('@nx/cypress')
|
typeof import('@nx/cypress')
|
||||||
@ -406,20 +439,20 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
const cypressTask = await configurationGenerator(host, {
|
const cypressTask = await configurationGenerator(host, {
|
||||||
...options,
|
...options,
|
||||||
project: options.e2eProjectName,
|
project: options.e2eProjectName,
|
||||||
devServerTarget: `${options.projectName}:${options.e2eWebServerTarget}`,
|
devServerTarget: e2eWebServerInfo.e2eDevServerTarget,
|
||||||
baseUrl: options.e2eWebServerAddress,
|
baseUrl: e2eWebServerInfo.e2eWebServerAddress,
|
||||||
directory: 'src',
|
directory: 'src',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
webServerCommands: hasPlugin
|
webServerCommands: hasPlugin
|
||||||
? {
|
? {
|
||||||
default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`,
|
default: e2eWebServerInfo.e2eWebServerCommand,
|
||||||
production: `nx run ${options.projectName}:preview`,
|
production: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
ciWebServerCommand: hasPlugin
|
ciWebServerCommand: hasPlugin
|
||||||
? `nx run ${options.projectName}:${options.e2eCiWebServerTarget}`
|
? e2eWebServerInfo.e2eCiWebServerCommand
|
||||||
: undefined,
|
: undefined,
|
||||||
ciBaseUrl: options.bundler === 'vite' ? options.e2eCiBaseUrl : undefined,
|
ciBaseUrl: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -472,10 +505,8 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
|||||||
js: false,
|
js: false,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: options.setParserOptionsProject,
|
||||||
webServerCommand: `${getPackageManagerCommand().exec} nx run ${
|
webServerCommand: e2eWebServerInfo.e2eCiWebServerCommand,
|
||||||
options.projectName
|
webServerAddress: e2eWebServerInfo.e2eCiBaseUrl,
|
||||||
}:${options.e2eCiWebServerTarget}`,
|
|
||||||
webServerAddress: options.e2eCiBaseUrl,
|
|
||||||
addPlugin: options.addPlugin,
|
addPlugin: options.addPlugin,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -590,57 +621,8 @@ async function normalizeOptions(
|
|||||||
nxJson.useInferencePlugins !== false;
|
nxJson.useInferencePlugins !== false;
|
||||||
options.addPlugin ??= addPluginDefault;
|
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 e2eProjectName = `${appProjectName}-e2e`;
|
||||||
const e2eProjectRoot = `${appProjectRoot}-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);
|
const npmScope = getNpmScope(host);
|
||||||
|
|
||||||
@ -664,11 +646,6 @@ async function normalizeOptions(
|
|||||||
appProjectRoot,
|
appProjectRoot,
|
||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
e2eProjectName,
|
e2eProjectName,
|
||||||
e2eWebServerAddress,
|
|
||||||
e2eWebServerTarget,
|
|
||||||
e2eCiWebServerTarget,
|
|
||||||
e2eCiBaseUrl,
|
|
||||||
e2ePort,
|
|
||||||
parsedTags,
|
parsedTags,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,3 +37,4 @@ export * from './src/utils/get-css-module-local-ident';
|
|||||||
export * from './src/utils/with-nx';
|
export * from './src/utils/with-nx';
|
||||||
export * from './src/utils/with-web';
|
export * from './src/utils/with-web';
|
||||||
export * from './src/utils/module-federation/public-api';
|
export * from './src/utils/module-federation/public-api';
|
||||||
|
export * from './src/utils/e2e-web-server-info-utils';
|
||||||
|
|||||||
149
packages/webpack/src/utils/e2e-web-server-info-utils.spec.ts
Normal file
149
packages/webpack/src/utils/e2e-web-server-info-utils.spec.ts
Normal file
@ -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",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
39
packages/webpack/src/utils/e2e-web-server-info-utils.ts
Normal file
39
packages/webpack/src/utils/e2e-web-server-info-utils.ts
Normal file
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user