From 7c787d4395008d6817bf9fdca6e6f48de3a07b41 Mon Sep 17 00:00:00 2001 From: Colum Ferry Date: Tue, 30 Jul 2024 11:23:35 +0100 Subject: [PATCH] fix(web): application generator should add e2e-ci target defaults --- .../application/application.spec.ts | 8 ++ .../src/generators/application/application.ts | 90 +++++++++++++++++-- 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/packages/web/src/generators/application/application.spec.ts b/packages/web/src/generators/application/application.spec.ts index 6aec78f324b939..cab0c67e7d4c22 100644 --- a/packages/web/src/generators/application/application.spec.ts +++ b/packages/web/src/generators/application/application.spec.ts @@ -43,6 +43,14 @@ describe('app', () => { expect(readProjectConfiguration(tree, 'my-app-e2e').root).toEqual( 'my-app-e2e' ); + expect(readNxJson(tree).targetDefaults['e2e-ci--**/*']) + .toMatchInlineSnapshot(` + { + "dependsOn": [ + "^build", + ], + } + `); }, 60_000); it('should update tags and implicit dependencies', async () => { diff --git a/packages/web/src/generators/application/application.ts b/packages/web/src/generators/application/application.ts index 823d771bbbd2d1..9dbed0511df911 100644 --- a/packages/web/src/generators/application/application.ts +++ b/packages/web/src/generators/application/application.ts @@ -9,6 +9,7 @@ import { joinPathFragments, names, offsetFromRoot, + type PluginConfiguration, readNxJson, readProjectConfiguration, runTasksInSerial, @@ -37,12 +38,15 @@ import { webInitGenerator } from '../init/init'; import { Schema } from './schema'; import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope'; import { hasWebpackPlugin } from '../../utils/has-webpack-plugin'; -import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; +import { + addBuildTargetDefaults, + addE2eCiTargetDefaults, +} from '@nx/devkit/src/generators/target-defaults-utils'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { VitePluginOptions } from '@nx/vite/src/plugins/plugin'; import { WebpackPluginOptions } from '@nx/webpack/src/plugins/plugin'; -import { hasVitePlugin } from '../../utils/has-vite-plugin'; import staticServeConfiguration from '../static-serve/static-serve-configuration'; +import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; interface NormalizedSchema extends Schema { projectName: string; @@ -368,10 +372,20 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { tasks.push(lintTask); } - const hasNxBuildPlugin = - (options.bundler === 'webpack' && hasWebpackPlugin(host)) || - (options.bundler === 'vite' && hasVitePlugin(host)); - if (!hasNxBuildPlugin) { + const nxJson = readNxJson(host); + let hasPlugin: PluginConfiguration | undefined; + let buildPlugin: string; + let buildConfigFile: string; + if (options.bundler === 'webpack' || options.bundler === 'vite') { + buildPlugin = `@nx/${options.bundler}/plugin`; + buildConfigFile = + options.bundler === 'webpack' ? 'webpack.config.js' : `vite.config.ts`; + hasPlugin = nxJson.plugins?.find((p) => + typeof p === 'string' ? p === buildPlugin : p.plugin === buildPlugin + ); + } + + if (!hasPlugin) { await staticServeConfiguration(host, { buildTarget: `${options.projectName}:build`, spa: true, @@ -396,17 +410,47 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { baseUrl: options.e2eWebServerAddress, directory: 'src', skipFormat: true, - webServerCommands: hasNxBuildPlugin + webServerCommands: hasPlugin ? { default: `nx run ${options.projectName}:${options.e2eWebServerTarget}`, production: `nx run ${options.projectName}:preview`, } : undefined, - ciWebServerCommand: hasNxBuildPlugin + ciWebServerCommand: hasPlugin ? `nx run ${options.projectName}:${options.e2eCiWebServerTarget}` : undefined, ciBaseUrl: options.bundler === 'vite' ? options.e2eCiBaseUrl : undefined, }); + + if ( + options.addPlugin || + readNxJson(host).plugins?.find((p) => + typeof p === 'string' + ? p === '@nx/cypress/plugin' + : p.plugin === '@nx/cypress/plugin' + ) + ) { + let buildTarget = '^build'; + if (hasPlugin) { + const matchingPlugin = await findPluginForConfigFile( + host, + buildPlugin, + joinPathFragments(options.appProjectRoot, buildConfigFile) + ); + if (matchingPlugin && typeof matchingPlugin !== 'string') { + buildTarget = `^${ + (matchingPlugin.options as any)?.buildTargetName ?? 'build' + }`; + } + } + await addE2eCiTargetDefaults( + host, + '@nx/cypress/plugin', + buildTarget, + joinPathFragments(options.e2eProjectRoot, `cypress.config.ts`) + ); + } + tasks.push(cypressTask); } else if (options.e2eTestRunner === 'playwright') { const { configurationGenerator: playwrightConfigGenerator } = ensurePackage< @@ -434,6 +478,36 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) { webServerAddress: options.e2eCiBaseUrl, addPlugin: options.addPlugin, }); + + if ( + options.addPlugin || + readNxJson(host).plugins?.find((p) => + typeof p === 'string' + ? p === '@nx/playwright/plugin' + : p.plugin === '@nx/playwright/plugin' + ) + ) { + let buildTarget = '^build'; + if (hasPlugin) { + const matchingPlugin = await findPluginForConfigFile( + host, + buildPlugin, + joinPathFragments(options.appProjectRoot, buildConfigFile) + ); + if (matchingPlugin && typeof matchingPlugin !== 'string') { + buildTarget = `^${ + (matchingPlugin.options as any)?.buildTargetName ?? 'build' + }`; + } + } + await addE2eCiTargetDefaults( + host, + '@nx/playwright/plugin', + buildTarget, + joinPathFragments(options.e2eProjectRoot, `playwright.config.ts`) + ); + } + tasks.push(playwrightTask); } if (options.unitTestRunner === 'jest') {