- 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 #
197 lines
5.9 KiB
TypeScript
197 lines
5.9 KiB
TypeScript
import {
|
|
type Tree,
|
|
addProjectConfiguration,
|
|
joinPathFragments,
|
|
readProjectConfiguration,
|
|
updateProjectConfiguration,
|
|
ensurePackage,
|
|
getPackageManagerCommand,
|
|
readNxJson,
|
|
} from '@nx/devkit';
|
|
import { type NormalizedSchema } from './normalize-options';
|
|
import { getPackageVersion } from '../../../utils/versions';
|
|
import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file';
|
|
import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
|
import { getE2EWebServerInfo } from '@nx/devkit/src/generators/e2e-web-server-info-utils';
|
|
|
|
export async function addE2E(tree: Tree, options: NormalizedSchema) {
|
|
const hasRemixPlugin = readNxJson(tree).plugins?.find((p) =>
|
|
typeof p === 'string'
|
|
? p === '@nx/remix/plugin'
|
|
: p.plugin === '@nx/remix/plugin'
|
|
);
|
|
|
|
let e2eWebsServerInfo = await getRemixE2EWebServerInfo(
|
|
tree,
|
|
options.projectName,
|
|
joinPathFragments(options.projectRoot, 'remix.config.js'),
|
|
options.addPlugin ?? Boolean(hasRemixPlugin)
|
|
);
|
|
|
|
if (options.e2eTestRunner === 'cypress') {
|
|
const { configurationGenerator } = ensurePackage<
|
|
typeof import('@nx/cypress')
|
|
>('@nx/cypress', getPackageVersion(tree, 'nx'));
|
|
|
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
|
projectType: 'application',
|
|
root: options.e2eProjectRoot,
|
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
|
targets: {},
|
|
tags: [],
|
|
implicitDependencies: [options.projectName],
|
|
});
|
|
|
|
const e2eTask = await configurationGenerator(tree, {
|
|
project: options.e2eProjectName,
|
|
directory: 'src',
|
|
skipFormat: true,
|
|
devServerTarget: e2eWebsServerInfo.e2eDevServerTarget,
|
|
baseUrl: e2eWebsServerInfo.e2eWebServerAddress,
|
|
webServerCommands: hasRemixPlugin
|
|
? {
|
|
default: e2eWebsServerInfo.e2eWebServerCommand,
|
|
production: e2eWebsServerInfo.e2eCiWebServerCommand,
|
|
}
|
|
: undefined,
|
|
ciWebServerCommand: hasRemixPlugin
|
|
? e2eWebsServerInfo.e2eCiWebServerCommand
|
|
: undefined,
|
|
ciBaseUrl: e2eWebsServerInfo.e2eCiBaseUrl,
|
|
addPlugin: options.addPlugin,
|
|
});
|
|
|
|
if (
|
|
options.addPlugin ||
|
|
readNxJson(tree).plugins?.find((p) =>
|
|
typeof p === 'string'
|
|
? p === '@nx/cypress/plugin'
|
|
: p.plugin === '@nx/cypress/plugin'
|
|
)
|
|
) {
|
|
let buildTarget = '^build';
|
|
if (hasRemixPlugin) {
|
|
const matchingPlugin = await findPluginForConfigFile(
|
|
tree,
|
|
`@nx/remix/plugin`,
|
|
joinPathFragments(options.projectRoot, 'remix.config.js')
|
|
);
|
|
if (matchingPlugin && typeof matchingPlugin !== 'string') {
|
|
buildTarget = `^${
|
|
(matchingPlugin.options as any)?.buildTargetName ?? 'build'
|
|
}`;
|
|
}
|
|
}
|
|
await addE2eCiTargetDefaults(
|
|
tree,
|
|
'@nx/cypress/plugin',
|
|
buildTarget,
|
|
joinPathFragments(
|
|
options.e2eProjectRoot,
|
|
`cypress.config.${options.js ? 'js' : 'ts'}`
|
|
)
|
|
);
|
|
}
|
|
|
|
return e2eTask;
|
|
} else if (options.e2eTestRunner === 'playwright') {
|
|
const { configurationGenerator } = ensurePackage<
|
|
typeof import('@nx/playwright')
|
|
>('@nx/playwright', getPackageVersion(tree, 'nx'));
|
|
|
|
addProjectConfiguration(tree, options.e2eProjectName, {
|
|
projectType: 'application',
|
|
root: options.e2eProjectRoot,
|
|
sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'),
|
|
targets: {},
|
|
tags: [],
|
|
implicitDependencies: [options.projectName],
|
|
});
|
|
|
|
const e2eTask = await configurationGenerator(tree, {
|
|
project: options.e2eProjectName,
|
|
skipFormat: true,
|
|
skipPackageJson: false,
|
|
directory: 'src',
|
|
js: false,
|
|
linter: options.linter,
|
|
setParserOptionsProject: false,
|
|
webServerCommand: e2eWebsServerInfo.e2eCiWebServerCommand,
|
|
webServerAddress: e2eWebsServerInfo.e2eCiBaseUrl,
|
|
rootProject: options.rootProject,
|
|
addPlugin: options.addPlugin,
|
|
});
|
|
|
|
if (
|
|
options.addPlugin ||
|
|
readNxJson(tree).plugins?.find((p) =>
|
|
typeof p === 'string'
|
|
? p === '@nx/playwright/plugin'
|
|
: p.plugin === '@nx/playwright/plugin'
|
|
)
|
|
) {
|
|
let buildTarget = '^build';
|
|
if (hasRemixPlugin) {
|
|
const matchingPlugin = await findPluginForConfigFile(
|
|
tree,
|
|
`@nx/remix/plugin`,
|
|
joinPathFragments(options.projectRoot, 'remix.config.js')
|
|
);
|
|
if (matchingPlugin && typeof matchingPlugin !== 'string') {
|
|
buildTarget = `^${
|
|
(matchingPlugin.options as any)?.buildTargetName ?? 'build'
|
|
}`;
|
|
}
|
|
}
|
|
await addE2eCiTargetDefaults(
|
|
tree,
|
|
'@nx/playwright/plugin',
|
|
buildTarget,
|
|
joinPathFragments(options.e2eProjectRoot, `playwright.config.ts`)
|
|
);
|
|
}
|
|
|
|
return e2eTask;
|
|
} else {
|
|
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
|
|
);
|
|
}
|