import type { Tree } from '@nx/devkit'; import { addDependenciesToPackageJson, addProjectConfiguration, ensurePackage, getPackageManagerCommand, joinPathFragments, readNxJson, readProjectConfiguration, updateProjectConfiguration, } from '@nx/devkit'; import { nxVersion } from '../../../utils/versions'; import { getInstalledAngularVersionInfo } from '../../utils/version-utils'; import type { NormalizedSchema } from './normalized-schema'; import { addE2eCiTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; export async function addE2e(tree: Tree, options: NormalizedSchema) { // since e2e are separate projects, default to adding plugins const nxJson = readNxJson(tree); const addPlugin = process.env.NX_ADD_PLUGINS !== 'false' && nxJson.useInferencePlugins !== false; if (options.e2eTestRunner === 'cypress') { const { configurationGenerator } = ensurePackage< typeof import('@nx/cypress') >('@nx/cypress', nxVersion); // TODO: This can call `@nx/web:static-config` generator when ready addFileServerTarget(tree, options, 'serve-static'); addProjectConfiguration(tree, options.e2eProjectName, { projectType: 'application', root: options.e2eProjectRoot, sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), targets: {}, tags: [], implicitDependencies: [options.name], }); await configurationGenerator(tree, { project: options.e2eProjectName, directory: 'src', linter: options.linter, skipPackageJson: options.skipPackageJson, skipFormat: true, devServerTarget: `${options.name}:${options.e2eWebServerTarget}:development`, baseUrl: options.e2eWebServerAddress, rootProject: options.rootProject, addPlugin, }); if (addPlugin) { await addE2eCiTargetDefaults( tree, '@nx/cypress/plugin', '^build', joinPathFragments(options.e2eProjectRoot, 'cypress.config.ts') ); } } else if (options.e2eTestRunner === 'playwright') { const { configurationGenerator } = ensurePackage< typeof import('@nx/playwright') >('@nx/playwright', nxVersion); addProjectConfiguration(tree, options.e2eProjectName, { projectType: 'application', root: options.e2eProjectRoot, sourceRoot: joinPathFragments(options.e2eProjectRoot, 'src'), targets: {}, implicitDependencies: [options.name], }); await configurationGenerator(tree, { project: options.e2eProjectName, skipFormat: true, skipPackageJson: options.skipPackageJson, directory: 'src', js: false, linter: options.linter, setParserOptionsProject: options.setParserOptionsProject, webServerCommand: `${getPackageManagerCommand().exec} nx ${ options.e2eWebServerTarget } ${options.name}`, webServerAddress: options.e2eWebServerAddress, rootProject: options.rootProject, addPlugin, }); if (addPlugin) { await addE2eCiTargetDefaults( tree, '@nx/playwright/plugin', '^build', joinPathFragments(options.e2eProjectRoot, 'playwright.config.ts') ); } } } function addFileServerTarget( tree: Tree, options: NormalizedSchema, targetName: string ) { if (!options.skipPackageJson) { addDependenciesToPackageJson(tree, {}, { '@nx/web': nxVersion }); } const { major: angularMajorVersion } = getInstalledAngularVersionInfo(tree); const isUsingApplicationBuilder = angularMajorVersion >= 17 && options.bundler === 'esbuild'; const projectConfig = readProjectConfiguration(tree, options.name); projectConfig.targets[targetName] = { executor: '@nx/web:file-server', options: { buildTarget: `${options.name}:build`, port: options.e2ePort, staticFilePath: isUsingApplicationBuilder ? joinPathFragments(options.outputPath, 'browser') : undefined, spa: true, }, }; updateProjectConfiguration(tree, options.name, projectConfig); }