From 4ada9334ed861e2b458392e954cbc04d2ca04373 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Wed, 8 Oct 2025 12:36:25 +0100 Subject: [PATCH 01/12] chore(repo): split slow e2e tests - web, webpack, and workspace-create Split the following test suites into smaller, more focused tests: - web tests (decorator babel/swc, env variables, generate, html interpolation, new format, vite) - webpack tests (app plugin, assets, babel, compose plugins, config variations, env variables, executor options, node compilers) - workspace-create npm tests (angular, express, init, js, nest, next, node, react-native, react, web) --- e2e/web/src/web-decorator-babel.test.ts | 84 +++ e2e/web/src/web-decorator-swc.test.ts | 66 ++ e2e/web/src/web-env-variables.test.ts | 125 ++++ e2e/web/src/web-generate.test.ts | 117 ++++ e2e/web/src/web-html-interpolation.test.ts | 57 ++ e2e/web/src/web-new-format.test.ts | 27 + e2e/web/src/web-setup.ts | 6 + ...vite.test.ts => web-vite-generate.test.ts} | 35 +- e2e/web/src/web-vite-output.test.ts | 39 ++ e2e/web/src/web-vite-setup.ts | 6 + e2e/web/src/web.test.ts | 407 ------------ e2e/webpack/src/webpack-app-plugin.test.ts | 66 ++ e2e/webpack/src/webpack-assets.test.ts | 42 ++ e2e/webpack/src/webpack-babel-corejs.test.ts | 50 ++ e2e/webpack/src/webpack-babel-env.test.ts | 40 ++ .../src/webpack-compose-plugins.test.ts | 42 ++ e2e/webpack/src/webpack-config-array.test.ts | 71 ++ .../src/webpack-config-function-array.test.ts | 72 ++ .../src/webpack-config-function.test.ts | 44 ++ .../webpack-config-standard-object.test.ts | 43 ++ e2e/webpack/src/webpack-env-variables.test.ts | 40 ++ .../src/webpack-executor-options.test.ts | 62 ++ .../src/webpack-libs-from-source.test.ts | 60 ++ .../src/webpack-node-compilers.test.ts | 95 +++ e2e/webpack/src/webpack-setup.ts | 6 + e2e/webpack/src/webpack.test.ts | 618 ------------------ .../create-nx-workspace-npm-angular.test.ts | 41 ++ .../create-nx-workspace-npm-express.test.ts | 26 + .../src/create-nx-workspace-npm-init.test.ts | 24 + .../src/create-nx-workspace-npm-js.test.ts | 34 + .../src/create-nx-workspace-npm-nest.test.ts | 46 ++ .../src/create-nx-workspace-npm-next.test.ts | 46 ++ .../src/create-nx-workspace-npm-node.test.ts | 46 ++ ...eate-nx-workspace-npm-react-native.test.ts | 50 ++ .../src/create-nx-workspace-npm-react.test.ts | 46 ++ .../src/create-nx-workspace-npm-setup.ts | 39 ++ .../src/create-nx-workspace-npm-web.test.ts | 26 + .../src/create-nx-workspace-npm.test.ts | 263 -------- 38 files changed, 1686 insertions(+), 1321 deletions(-) create mode 100644 e2e/web/src/web-decorator-babel.test.ts create mode 100644 e2e/web/src/web-decorator-swc.test.ts create mode 100644 e2e/web/src/web-env-variables.test.ts create mode 100644 e2e/web/src/web-generate.test.ts create mode 100644 e2e/web/src/web-html-interpolation.test.ts create mode 100644 e2e/web/src/web-new-format.test.ts create mode 100644 e2e/web/src/web-setup.ts rename e2e/web/src/{web-vite.test.ts => web-vite-generate.test.ts} (50%) create mode 100644 e2e/web/src/web-vite-output.test.ts create mode 100644 e2e/web/src/web-vite-setup.ts delete mode 100644 e2e/web/src/web.test.ts create mode 100644 e2e/webpack/src/webpack-app-plugin.test.ts create mode 100644 e2e/webpack/src/webpack-assets.test.ts create mode 100644 e2e/webpack/src/webpack-babel-corejs.test.ts create mode 100644 e2e/webpack/src/webpack-babel-env.test.ts create mode 100644 e2e/webpack/src/webpack-compose-plugins.test.ts create mode 100644 e2e/webpack/src/webpack-config-array.test.ts create mode 100644 e2e/webpack/src/webpack-config-function-array.test.ts create mode 100644 e2e/webpack/src/webpack-config-function.test.ts create mode 100644 e2e/webpack/src/webpack-config-standard-object.test.ts create mode 100644 e2e/webpack/src/webpack-env-variables.test.ts create mode 100644 e2e/webpack/src/webpack-executor-options.test.ts create mode 100644 e2e/webpack/src/webpack-libs-from-source.test.ts create mode 100644 e2e/webpack/src/webpack-node-compilers.test.ts create mode 100644 e2e/webpack/src/webpack-setup.ts delete mode 100644 e2e/webpack/src/webpack.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-angular.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-init.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-js.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-nest.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-next.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-node.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-react-native.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-react.test.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-setup.ts create mode 100644 e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts delete mode 100644 e2e/workspace-create/src/create-nx-workspace-npm.test.ts diff --git a/e2e/web/src/web-decorator-babel.test.ts b/e2e/web/src/web-decorator-babel.test.ts new file mode 100644 index 0000000000000..61614565ec8f7 --- /dev/null +++ b/e2e/web/src/web-decorator-babel.test.ts @@ -0,0 +1,84 @@ +import { readFile, runCLI, uniq, updateFile } from '@nx/e2e-utils'; +import { setupWebTest } from './web-setup'; + +describe('Web Components Applications', () => { + setupWebTest(); + + it('should emit decorator metadata when --compiler=babel and it is enabled in tsconfig', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=babel --no-interactive --unitTestRunner=vitest --linter=eslint` + ); + + updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { + const newContent = `${content} + function enumerable(value: boolean) { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + descriptor.enumerable = value; + }; + } + function sealed(target: any) { + return target; + } + + @sealed + class Foo { + @enumerable(false) bar() {} + } + `; + return newContent; + }); + + updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { + const newContent = `${content} + // bust babel and nx cache + `; + return newContent; + }); + setPluginOption( + `apps/${appName}/webpack.config.js`, + 'outputHashing', + 'none' + ); + runCLI(`build ${appName}`); + + expect(readFile(`dist/apps/${appName}/main.js`)).toMatch( + /Reflect\.metadata/ + ); + + // Turn off decorator metadata + updateFile(`apps/${appName}/tsconfig.app.json`, (content) => { + const json = JSON.parse(content); + json.compilerOptions.emitDecoratorMetadata = false; + return JSON.stringify(json); + }); + + setPluginOption( + `apps/${appName}/webpack.config.js`, + 'outputHashing', + 'none' + ); + runCLI(`build ${appName}`); + + expect(readFile(`dist/apps/${appName}/main.js`)).not.toMatch( + /Reflect\.metadata/ + ); + }, 120000); +}); + +function setPluginOption( + webpackConfigPath: string, + option: string, + value: string | boolean +): void { + updateFile(webpackConfigPath, (content) => { + return content.replace( + new RegExp(`${option}: .+`), + `${option}: ${typeof value === 'string' ? `'${value}'` : value},` + ); + }); +} diff --git a/e2e/web/src/web-decorator-swc.test.ts b/e2e/web/src/web-decorator-swc.test.ts new file mode 100644 index 0000000000000..7411628cc3212 --- /dev/null +++ b/e2e/web/src/web-decorator-swc.test.ts @@ -0,0 +1,66 @@ +import { readFile, runCLI, uniq, updateFile } from '@nx/e2e-utils'; +import { setupWebTest } from './web-setup'; + +describe('Web Components Applications', () => { + setupWebTest(); + + it('should emit decorator metadata when using --compiler=swc', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=swc --no-interactive --unitTestRunner=vitest --linter=eslint` + ); + + updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { + const newContent = `${content} + function enumerable(value: boolean) { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + descriptor.enumerable = value; + }; + } + function sealed(target: any) { + return target; + } + + @sealed + class Foo { + @enumerable(false) bar() {} + } + `; + return newContent; + }); + + updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { + const newContent = `${content} + // bust babel and nx cache + `; + return newContent; + }); + setPluginOption( + `apps/${appName}/webpack.config.js`, + 'outputHashing', + 'none' + ); + runCLI(`build ${appName}`); + + expect(readFile(`dist/apps/${appName}/main.js`)).toMatch( + /Foo=.*?_decorate/ + ); + }, 120000); +}); + +function setPluginOption( + webpackConfigPath: string, + option: string, + value: string | boolean +): void { + updateFile(webpackConfigPath, (content) => { + return content.replace( + new RegExp(`${option}: .+`), + `${option}: ${typeof value === 'string' ? `'${value}'` : value},` + ); + }); +} diff --git a/e2e/web/src/web-env-variables.test.ts b/e2e/web/src/web-env-variables.test.ts new file mode 100644 index 0000000000000..272160c0227fd --- /dev/null +++ b/e2e/web/src/web-env-variables.test.ts @@ -0,0 +1,125 @@ +import { + cleanupProject, + newProject, + readFile, + runCLI, + uniq, + updateFile, +} from '@nx/e2e-utils'; + +describe('CLI - Environment Variables', () => { + it('should automatically load workspace and per-project environment variables', async () => { + newProject(); + + const appName = uniq('app'); + //test if the Nx CLI loads root .env vars + updateFile( + `.env`, + 'NX_PUBLIC_WS_BASE=ws-base\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-base' + ); + updateFile( + `.env.local`, + 'NX_PUBLIC_WS_ENV_LOCAL=ws-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-env-local' + ); + updateFile( + `.local.env`, + 'NX_PUBLIC_WS_LOCAL_ENV=ws-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-local-env' + ); + updateFile( + `apps/${appName}/.env`, + 'NX_PUBLIC_APP_BASE=app-base\nNX_PUBLIC_SHARED_ENV=shared-in-app-base' + ); + updateFile( + `apps/${appName}/.env.local`, + 'NX_PUBLIC_APP_ENV_LOCAL=app-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-app-env-local' + ); + updateFile( + `apps/${appName}/.local.env`, + 'NX_PUBLIC_APP_LOCAL_ENV=app-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-app-local-env' + ); + const main = `apps/${appName}/src/main.ts`; + const newCode = ` + const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV]; + const nodeEnv = process.env.NODE_ENV; + const nxWsBase = process.env.NX_PUBLIC_WS_BASE; + const nxWsEnvLocal = process.env.NX_PUBLIC_WS_ENV_LOCAL; + const nxWsLocalEnv = process.env.NX_PUBLIC_WS_LOCAL_ENV; + const nxAppBase = process.env.NX_PUBLIC_APP_BASE; + const nxAppEnvLocal = process.env.NX_PUBLIC_APP_ENV_LOCAL; + const nxAppLocalEnv = process.env.NX_PUBLIC_APP_LOCAL_ENV; + const nxSharedEnv = process.env.NX_PUBLIC_SHARED_ENV; + `; + + runCLI( + `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint` + ); + + const content = readFile(main); + + updateFile(main, `${newCode}\n${content}`); + + const appName2 = uniq('app'); + + updateFile( + `apps/${appName2}/.env`, + 'NX_PUBLIC_APP_BASE=app2-base\nNX_PUBLIC_SHARED_ENV=shared2-in-app-base' + ); + updateFile( + `apps/${appName2}/.env.local`, + 'NX_PUBLIC_APP_ENV_LOCAL=app2-env-local\nNX_PUBLIC_SHARED_ENV=shared2-in-app-env-local' + ); + updateFile( + `apps/${appName2}/.local.env`, + 'NX_PUBLIC_APP_LOCAL_ENV=app2-local-env\nNX_PUBLIC_SHARED_ENV=shared2-in-app-local-env' + ); + const main2 = `apps/${appName2}/src/main.ts`; + const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];`; + + runCLI( + `generate @nx/web:app apps/${appName2} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint` + ); + + const content2 = readFile(main2); + + updateFile(main2, `${newCode2}\n${content2}`); + + setPluginOption( + `apps/${appName}/webpack.config.js`, + 'outputHashing', + 'none' + ); + setPluginOption(`apps/${appName}/webpack.config.js`, 'optimization', false); + setPluginOption( + `apps/${appName2}/webpack.config.js`, + 'outputHashing', + 'none' + ); + setPluginOption( + `apps/${appName2}/webpack.config.js`, + 'optimization', + false + ); + runCLI(`run-many --target build --node-env=test`); + expect(readFile(`dist/apps/${appName}/main.js`)).toContain( + 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app-base", "app-env-local", "app-local-env", "shared-in-app-env-local"];' + ); + expect(readFile(`dist/apps/${appName2}/main.js`)).toContain( + 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app2-base", "app2-env-local", "app2-local-env", "shared2-in-app-env-local"];' + ); + + cleanupProject(); + }); +}); + +function setPluginOption( + webpackConfigPath: string, + option: string, + value: string | boolean +): void { + updateFile(webpackConfigPath, (content) => { + return content.replace( + new RegExp(`${option}: .+`), + `${option}: ${typeof value === 'string' ? `'${value}'` : value},` + ); + }); +} diff --git a/e2e/web/src/web-generate.test.ts b/e2e/web/src/web-generate.test.ts new file mode 100644 index 0000000000000..ac7a491d7208f --- /dev/null +++ b/e2e/web/src/web-generate.test.ts @@ -0,0 +1,117 @@ +import { + checkFilesExist, + isNotWindows, + killPorts, + listFiles, + readFile, + runCLI, + runCLIAsync, + runE2ETests, + tmpProjPath, + uniq, + updateFile, +} from '@nx/e2e-utils'; +import { join } from 'path'; +import { copyFileSync } from 'fs'; +import { setupWebTest } from './web-setup'; + +describe('Web Components Applications', () => { + setupWebTest(); + + it('should be able to generate a web app', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint` + ); + + const lintResults = runCLI(`lint ${appName}`); + expect(lintResults).toContain('Successfully ran target lint'); + + const testResults = await runCLIAsync(`test ${appName}`); + + expect(testResults.combinedOutput).toContain( + `Successfully ran target test for project ${appName}` + ); + const lintE2eResults = runCLI(`lint ${appName}-e2e`); + + expect(lintE2eResults).toContain('Successfully ran target lint'); + + if (isNotWindows() && runE2ETests()) { + const e2eResults = runCLI(`e2e ${appName}-e2e`); + expect(e2eResults).toContain('Successfully ran target e2e for project'); + await killPorts(); + } + + copyFileSync( + join(__dirname, 'test-fixtures/inlined.png'), + join(tmpProjPath(), `apps/${appName}/src/app/inlined.png`) + ); + copyFileSync( + join(__dirname, 'test-fixtures/emitted.png'), + join(tmpProjPath(), `apps/${appName}/src/app/emitted.png`) + ); + updateFile( + `apps/${appName}/src/app/app.element.ts`, + ` + // @ts-ignore + import inlined from './inlined.png'; + // @ts-ignore + import emitted from './emitted.png'; + export class AppElement extends HTMLElement { + public static observedAttributes = []; + connectedCallback() { + this.innerHTML = \` + + + \`; + } + } + customElements.define('app-root', AppElement); + ` + ); + setPluginOption( + `apps/${appName}/webpack.config.js`, + 'outputHashing', + 'none' + ); + runCLI(`build ${appName}`); + const images = listFiles(`dist/apps/${appName}`).filter((f) => + f.endsWith('.png') + ); + checkFilesExist( + `dist/apps/${appName}/index.html`, + `dist/apps/${appName}/runtime.js`, + `dist/apps/${appName}/main.js`, + `dist/apps/${appName}/styles.css` + ); + expect(images.some((f) => f.startsWith('emitted.'))).toBe(true); + expect(images.some((f) => f.startsWith('inlined.'))).toBe(false); + + expect(readFile(`dist/apps/${appName}/main.js`)).toContain( + 'data:image/png;base64' + ); + // Should not be a JS module but kept as a PNG + expect( + readFile( + `dist/apps/${appName}/${images.find((f) => f.startsWith('emitted.'))}` + ) + ).not.toContain('export default'); + + expect(readFile(`dist/apps/${appName}/index.html`)).toContain( + '' + ); + }, 500000); +}); + +function setPluginOption( + webpackConfigPath: string, + option: string, + value: string | boolean +): void { + updateFile(webpackConfigPath, (content) => { + return content.replace( + new RegExp(`${option}: .+`), + `${option}: ${typeof value === 'string' ? `'${value}'` : value},` + ); + }); +} diff --git a/e2e/web/src/web-html-interpolation.test.ts b/e2e/web/src/web-html-interpolation.test.ts new file mode 100644 index 0000000000000..69e7000db5d9d --- /dev/null +++ b/e2e/web/src/web-html-interpolation.test.ts @@ -0,0 +1,57 @@ +import { + createFile, + readFile, + runCLI, + uniq, + updateFile, +} from '@nx/e2e-utils'; +import { setupWebTest } from './web-setup'; + +describe('index.html interpolation', () => { + setupWebTest(); + + test('should interpolate environment variables', async () => { + const appName = uniq('app'); + + runCLI( + `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint` + ); + + const srcPath = `apps/${appName}/src`; + const indexPath = `${srcPath}/index.html`; + const indexContent = ` + + + + BestReactApp + + + + + +
+
Nx Variable: %NX_PUBLIC_VARIABLE%
+
Some other variable: %SOME_OTHER_VARIABLE%
+ + +`; + const envFilePath = `apps/${appName}/.env`; + const envFileContents = ` + NX_PUBLIC_VARIABLE=foo + SOME_OTHER_VARIABLE=bar + }`; + + createFile(envFilePath); + + // createFile could not create a file with content + updateFile(envFilePath, envFileContents); + updateFile(indexPath, indexContent); + + runCLI(`build ${appName}`); + + const distPath = `dist/apps/${appName}`; + const resultIndexContents = readFile(`${distPath}/index.html`); + + expect(resultIndexContents).toMatch(/
Nx Variable: foo<\/div>/); + }); +}); diff --git a/e2e/web/src/web-new-format.test.ts b/e2e/web/src/web-new-format.test.ts new file mode 100644 index 0000000000000..2e0e279e428c2 --- /dev/null +++ b/e2e/web/src/web-new-format.test.ts @@ -0,0 +1,27 @@ +import { checkFilesExist, runCLI, uniq } from '@nx/e2e-utils'; +import { setupWebTest } from './web-setup'; + +describe('Web Components Applications', () => { + setupWebTest(); + + it('should support generating applications with the new name and root format', () => { + const appName = uniq('app1'); + + runCLI( + `generate @nx/web:app ${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint` + ); + + // check files are generated without the layout directory ("apps/") and + // using the project name as the directory when no directory is provided + checkFilesExist(`${appName}/src/main.ts`); + // check build works + expect(runCLI(`build ${appName}`)).toContain( + `Successfully ran target build for project ${appName}` + ); + // check tests pass + const appTestResult = runCLI(`test ${appName}`); + expect(appTestResult).toContain( + `Successfully ran target test for project ${appName}` + ); + }, 500_000); +}); diff --git a/e2e/web/src/web-setup.ts b/e2e/web/src/web-setup.ts new file mode 100644 index 0000000000000..620893ec1dfa6 --- /dev/null +++ b/e2e/web/src/web-setup.ts @@ -0,0 +1,6 @@ +import { cleanupProject, newProject } from '@nx/e2e-utils'; + +export function setupWebTest() { + beforeAll(() => newProject()); + afterAll(() => cleanupProject()); +} diff --git a/e2e/web/src/web-vite.test.ts b/e2e/web/src/web-vite-generate.test.ts similarity index 50% rename from e2e/web/src/web-vite.test.ts rename to e2e/web/src/web-vite-generate.test.ts index db7e2916528ce..6c11100d9e1da 100644 --- a/e2e/web/src/web-vite.test.ts +++ b/e2e/web/src/web-vite-generate.test.ts @@ -1,20 +1,16 @@ import { - checkFilesDoNotExist, checkFilesExist, - cleanupProject, - createFile, isNotWindows, killPorts, - newProject, runCLI, runCLIAsync, runE2ETests, uniq, } from '@nx/e2e-utils'; +import { setupWebViteTest } from './web-vite-setup'; describe('Web Components Applications with bundler set as vite', () => { - beforeEach(() => newProject()); - afterEach(() => cleanupProject()); + setupWebViteTest(); it('should be able to generate a web app', async () => { const appName = uniq('app'); @@ -44,31 +40,4 @@ describe('Web Components Applications with bundler set as vite', () => { await killPorts(); } }, 500000); - - it('should remove previous output before building', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); - - runCLI( - `generate @nx/web:app apps/${appName} --bundler=vite --no-interactive --linter=eslint --unitTestRunner=vitest` - ); - runCLI( - `generate @nx/react:lib libs/${libName} --bundler=vite --no-interactive --unitTestRunner=vitest --linter=eslint` - ); - - createFile(`dist/apps/${appName}/_should_remove.txt`); - createFile(`dist/libs/${libName}/_should_remove.txt`); - createFile(`dist/apps/_should_not_remove.txt`); - checkFilesExist( - `dist/apps/${appName}/_should_remove.txt`, - `dist/apps/_should_not_remove.txt` - ); - runCLI(`build ${appName} --emptyOutDir`); - runCLI(`build ${libName} --emptyOutDir`); - checkFilesDoNotExist( - `dist/apps/${appName}/_should_remove.txt`, - `dist/libs/${libName}/_should_remove.txt` - ); - checkFilesExist(`dist/apps/_should_not_remove.txt`); - }, 120000); }); diff --git a/e2e/web/src/web-vite-output.test.ts b/e2e/web/src/web-vite-output.test.ts new file mode 100644 index 0000000000000..558774976e592 --- /dev/null +++ b/e2e/web/src/web-vite-output.test.ts @@ -0,0 +1,39 @@ +import { + checkFilesDoNotExist, + checkFilesExist, + createFile, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { setupWebViteTest } from './web-vite-setup'; + +describe('Web Components Applications with bundler set as vite', () => { + setupWebViteTest(); + + it('should remove previous output before building', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI( + `generate @nx/web:app apps/${appName} --bundler=vite --no-interactive --linter=eslint --unitTestRunner=vitest` + ); + runCLI( + `generate @nx/react:lib libs/${libName} --bundler=vite --no-interactive --unitTestRunner=vitest --linter=eslint` + ); + + createFile(`dist/apps/${appName}/_should_remove.txt`); + createFile(`dist/libs/${libName}/_should_remove.txt`); + createFile(`dist/apps/_should_not_remove.txt`); + checkFilesExist( + `dist/apps/${appName}/_should_remove.txt`, + `dist/apps/_should_not_remove.txt` + ); + runCLI(`build ${appName} --emptyOutDir`); + runCLI(`build ${libName} --emptyOutDir`); + checkFilesDoNotExist( + `dist/apps/${appName}/_should_remove.txt`, + `dist/libs/${libName}/_should_remove.txt` + ); + checkFilesExist(`dist/apps/_should_not_remove.txt`); + }, 120000); +}); diff --git a/e2e/web/src/web-vite-setup.ts b/e2e/web/src/web-vite-setup.ts new file mode 100644 index 0000000000000..ae2ca1145d705 --- /dev/null +++ b/e2e/web/src/web-vite-setup.ts @@ -0,0 +1,6 @@ +import { cleanupProject, newProject } from '@nx/e2e-utils'; + +export function setupWebViteTest() { + beforeEach(() => newProject()); + afterEach(() => cleanupProject()); +} diff --git a/e2e/web/src/web.test.ts b/e2e/web/src/web.test.ts deleted file mode 100644 index 7c2a8e671b779..0000000000000 --- a/e2e/web/src/web.test.ts +++ /dev/null @@ -1,407 +0,0 @@ -import { - checkFilesDoNotExist, - checkFilesExist, - cleanupProject, - createFile, - isNotWindows, - killPorts, - listFiles, - newProject, - readFile, - runCLI, - runCLIAsync, - runE2ETests, - tmpProjPath, - uniq, - updateFile, - updateJson, -} from '@nx/e2e-utils'; -import { join } from 'path'; -import { copyFileSync } from 'fs'; - -describe('Web Components Applications', () => { - beforeAll(() => newProject()); - afterAll(() => cleanupProject()); - - it('should be able to generate a web app', async () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint` - ); - - const lintResults = runCLI(`lint ${appName}`); - expect(lintResults).toContain('Successfully ran target lint'); - - const testResults = await runCLIAsync(`test ${appName}`); - - expect(testResults.combinedOutput).toContain( - `Successfully ran target test for project ${appName}` - ); - const lintE2eResults = runCLI(`lint ${appName}-e2e`); - - expect(lintE2eResults).toContain('Successfully ran target lint'); - - if (isNotWindows() && runE2ETests()) { - const e2eResults = runCLI(`e2e ${appName}-e2e`); - expect(e2eResults).toContain('Successfully ran target e2e for project'); - await killPorts(); - } - - copyFileSync( - join(__dirname, 'test-fixtures/inlined.png'), - join(tmpProjPath(), `apps/${appName}/src/app/inlined.png`) - ); - copyFileSync( - join(__dirname, 'test-fixtures/emitted.png'), - join(tmpProjPath(), `apps/${appName}/src/app/emitted.png`) - ); - updateFile( - `apps/${appName}/src/app/app.element.ts`, - ` - // @ts-ignore - import inlined from './inlined.png'; - // @ts-ignore - import emitted from './emitted.png'; - export class AppElement extends HTMLElement { - public static observedAttributes = []; - connectedCallback() { - this.innerHTML = \` - - - \`; - } - } - customElements.define('app-root', AppElement); - ` - ); - setPluginOption( - `apps/${appName}/webpack.config.js`, - 'outputHashing', - 'none' - ); - runCLI(`build ${appName}`); - const images = listFiles(`dist/apps/${appName}`).filter((f) => - f.endsWith('.png') - ); - checkFilesExist( - `dist/apps/${appName}/index.html`, - `dist/apps/${appName}/runtime.js`, - `dist/apps/${appName}/main.js`, - `dist/apps/${appName}/styles.css` - ); - expect(images.some((f) => f.startsWith('emitted.'))).toBe(true); - expect(images.some((f) => f.startsWith('inlined.'))).toBe(false); - - expect(readFile(`dist/apps/${appName}/main.js`)).toContain( - 'data:image/png;base64' - ); - // Should not be a JS module but kept as a PNG - expect( - readFile( - `dist/apps/${appName}/${images.find((f) => f.startsWith('emitted.'))}` - ) - ).not.toContain('export default'); - - expect(readFile(`dist/apps/${appName}/index.html`)).toContain( - '' - ); - }, 500000); - - it('should emit decorator metadata when --compiler=babel and it is enabled in tsconfig', async () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=babel --no-interactive --unitTestRunner=vitest --linter=eslint` - ); - - updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { - const newContent = `${content} - function enumerable(value: boolean) { - return function ( - target: any, - propertyKey: string, - descriptor: PropertyDescriptor - ) { - descriptor.enumerable = value; - }; - } - function sealed(target: any) { - return target; - } - - @sealed - class Foo { - @enumerable(false) bar() {} - } - `; - return newContent; - }); - - updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { - const newContent = `${content} - // bust babel and nx cache - `; - return newContent; - }); - setPluginOption( - `apps/${appName}/webpack.config.js`, - 'outputHashing', - 'none' - ); - runCLI(`build ${appName}`); - - expect(readFile(`dist/apps/${appName}/main.js`)).toMatch( - /Reflect\.metadata/ - ); - - // Turn off decorator metadata - updateFile(`apps/${appName}/tsconfig.app.json`, (content) => { - const json = JSON.parse(content); - json.compilerOptions.emitDecoratorMetadata = false; - return JSON.stringify(json); - }); - - setPluginOption( - `apps/${appName}/webpack.config.js`, - 'outputHashing', - 'none' - ); - runCLI(`build ${appName}`); - - expect(readFile(`dist/apps/${appName}/main.js`)).not.toMatch( - /Reflect\.metadata/ - ); - }, 120000); - - it('should emit decorator metadata when using --compiler=swc', async () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app apps/${appName} --bundler=webpack --compiler=swc --no-interactive --unitTestRunner=vitest --linter=eslint` - ); - - updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { - const newContent = `${content} - function enumerable(value: boolean) { - return function ( - target: any, - propertyKey: string, - descriptor: PropertyDescriptor - ) { - descriptor.enumerable = value; - }; - } - function sealed(target: any) { - return target; - } - - @sealed - class Foo { - @enumerable(false) bar() {} - } - `; - return newContent; - }); - - updateFile(`apps/${appName}/src/app/app.element.ts`, (content) => { - const newContent = `${content} - // bust babel and nx cache - `; - return newContent; - }); - setPluginOption( - `apps/${appName}/webpack.config.js`, - 'outputHashing', - 'none' - ); - runCLI(`build ${appName}`); - - expect(readFile(`dist/apps/${appName}/main.js`)).toMatch( - /Foo=.*?_decorate/ - ); - }, 120000); - - it('should support generating applications with the new name and root format', () => { - const appName = uniq('app1'); - - runCLI( - `generate @nx/web:app ${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint` - ); - - // check files are generated without the layout directory ("apps/") and - // using the project name as the directory when no directory is provided - checkFilesExist(`${appName}/src/main.ts`); - // check build works - expect(runCLI(`build ${appName}`)).toContain( - `Successfully ran target build for project ${appName}` - ); - // check tests pass - const appTestResult = runCLI(`test ${appName}`); - expect(appTestResult).toContain( - `Successfully ran target test for project ${appName}` - ); - }, 500_000); -}); - -describe('CLI - Environment Variables', () => { - it('should automatically load workspace and per-project environment variables', async () => { - newProject(); - - const appName = uniq('app'); - //test if the Nx CLI loads root .env vars - updateFile( - `.env`, - 'NX_PUBLIC_WS_BASE=ws-base\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-base' - ); - updateFile( - `.env.local`, - 'NX_PUBLIC_WS_ENV_LOCAL=ws-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-env-local' - ); - updateFile( - `.local.env`, - 'NX_PUBLIC_WS_LOCAL_ENV=ws-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-workspace-local-env' - ); - updateFile( - `apps/${appName}/.env`, - 'NX_PUBLIC_APP_BASE=app-base\nNX_PUBLIC_SHARED_ENV=shared-in-app-base' - ); - updateFile( - `apps/${appName}/.env.local`, - 'NX_PUBLIC_APP_ENV_LOCAL=app-env-local\nNX_PUBLIC_SHARED_ENV=shared-in-app-env-local' - ); - updateFile( - `apps/${appName}/.local.env`, - 'NX_PUBLIC_APP_LOCAL_ENV=app-local-env\nNX_PUBLIC_SHARED_ENV=shared-in-app-local-env' - ); - const main = `apps/${appName}/src/main.ts`; - const newCode = ` - const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV]; - const nodeEnv = process.env.NODE_ENV; - const nxWsBase = process.env.NX_PUBLIC_WS_BASE; - const nxWsEnvLocal = process.env.NX_PUBLIC_WS_ENV_LOCAL; - const nxWsLocalEnv = process.env.NX_PUBLIC_WS_LOCAL_ENV; - const nxAppBase = process.env.NX_PUBLIC_APP_BASE; - const nxAppEnvLocal = process.env.NX_PUBLIC_APP_ENV_LOCAL; - const nxAppLocalEnv = process.env.NX_PUBLIC_APP_LOCAL_ENV; - const nxSharedEnv = process.env.NX_PUBLIC_SHARED_ENV; - `; - - runCLI( - `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint` - ); - - const content = readFile(main); - - updateFile(main, `${newCode}\n${content}`); - - const appName2 = uniq('app'); - - updateFile( - `apps/${appName2}/.env`, - 'NX_PUBLIC_APP_BASE=app2-base\nNX_PUBLIC_SHARED_ENV=shared2-in-app-base' - ); - updateFile( - `apps/${appName2}/.env.local`, - 'NX_PUBLIC_APP_ENV_LOCAL=app2-env-local\nNX_PUBLIC_SHARED_ENV=shared2-in-app-env-local' - ); - updateFile( - `apps/${appName2}/.local.env`, - 'NX_PUBLIC_APP_LOCAL_ENV=app2-local-env\nNX_PUBLIC_SHARED_ENV=shared2-in-app-local-env' - ); - const main2 = `apps/${appName2}/src/main.ts`; - const newCode2 = `const envVars = [process.env.NODE_ENV, process.env.NX_PUBLIC_WS_BASE, process.env.NX_PUBLIC_WS_ENV_LOCAL, process.env.NX_PUBLIC_WS_LOCAL_ENV, process.env.NX_PUBLIC_APP_BASE, process.env.NX_PUBLIC_APP_ENV_LOCAL, process.env.NX_PUBLIC_APP_LOCAL_ENV, process.env.NX_PUBLIC_SHARED_ENV];`; - - runCLI( - `generate @nx/web:app apps/${appName2} --bundler=webpack --no-interactive --compiler=babel --unitTestRunner=vitest --linter=eslint` - ); - - const content2 = readFile(main2); - - updateFile(main2, `${newCode2}\n${content2}`); - - setPluginOption( - `apps/${appName}/webpack.config.js`, - 'outputHashing', - 'none' - ); - setPluginOption(`apps/${appName}/webpack.config.js`, 'optimization', false); - setPluginOption( - `apps/${appName2}/webpack.config.js`, - 'outputHashing', - 'none' - ); - setPluginOption( - `apps/${appName2}/webpack.config.js`, - 'optimization', - false - ); - runCLI(`run-many --target build --node-env=test`); - expect(readFile(`dist/apps/${appName}/main.js`)).toContain( - 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app-base", "app-env-local", "app-local-env", "shared-in-app-env-local"];' - ); - expect(readFile(`dist/apps/${appName2}/main.js`)).toContain( - 'const envVars = ["test", "ws-base", "ws-env-local", "ws-local-env", "app2-base", "app2-env-local", "app2-local-env", "shared2-in-app-env-local"];' - ); - }); -}); - -describe('index.html interpolation', () => { - beforeAll(() => newProject()); - afterAll(() => cleanupProject()); - - test('should interpolate environment variables', async () => { - const appName = uniq('app'); - - runCLI( - `generate @nx/web:app apps/${appName} --bundler=webpack --no-interactive --unitTestRunner=vitest --linter=eslint` - ); - - const srcPath = `apps/${appName}/src`; - const indexPath = `${srcPath}/index.html`; - const indexContent = ` - - - - BestReactApp - - - - - -
-
Nx Variable: %NX_PUBLIC_VARIABLE%
-
Some other variable: %SOME_OTHER_VARIABLE%
- - -`; - const envFilePath = `apps/${appName}/.env`; - const envFileContents = ` - NX_PUBLIC_VARIABLE=foo - SOME_OTHER_VARIABLE=bar - }`; - - createFile(envFilePath); - - // createFile could not create a file with content - updateFile(envFilePath, envFileContents); - updateFile(indexPath, indexContent); - - runCLI(`build ${appName}`); - - const distPath = `dist/apps/${appName}`; - const resultIndexContents = readFile(`${distPath}/index.html`); - - expect(resultIndexContents).toMatch(/
Nx Variable: foo<\/div>/); - }); -}); - -function setPluginOption( - webpackConfigPath: string, - option: string, - value: string | boolean -): void { - updateFile(webpackConfigPath, (content) => { - return content.replace( - new RegExp(`${option}: .+`), - `${option}: ${typeof value === 'string' ? `'${value}'` : value},` - ); - }); -} diff --git a/e2e/webpack/src/webpack-app-plugin.test.ts b/e2e/webpack/src/webpack-app-plugin.test.ts new file mode 100644 index 0000000000000..6569b23b7df1e --- /dev/null +++ b/e2e/webpack/src/webpack-app-plugin.test.ts @@ -0,0 +1,66 @@ +import { + checkFilesExist, + createFile, + runCLI, + runCommand, + uniq, + updateFile, +} from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should be able to build with NxWebpackPlugin and a standard webpack config file', () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app ${appName} --bundler webpack --directory=apps/${appName}` + ); + updateFile(`apps/${appName}/src/main.ts`, `console.log('Hello');\n`); + updateFile(`apps/${appName}/src/foo.ts`, `console.log('Foo');\n`); + updateFile(`apps/${appName}/src/bar.ts`, `console.log('Bar');\n`); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const path = require('path'); + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + + module.exports = { + target: 'node', + output: { + path: path.join(__dirname, '../../dist/apps/${appName}'), + // do not remove dist, so files between builds will remain + clean: false, + }, + plugins: [ + new NxAppWebpackPlugin({ + compiler: 'tsc', + main: './src/main.ts', + additionalEntryPoints: [ + './src/foo.ts', + { + entryName: 'bar', + entryPath: './src/bar.ts', + } + ], + tsConfig: './tsconfig.app.json', + outputHashing: 'none', + optimization: false, + }) + ] + };` + ); + + runCLI(`build ${appName}`); + + expect(runCommand(`node dist/apps/${appName}/main.js`)).toMatch(/Hello/); + expect(runCommand(`node dist/apps/${appName}/foo.js`)).toMatch(/Foo/); + expect(runCommand(`node dist/apps/${appName}/bar.js`)).toMatch(/Bar/); + + // Ensure dist is not removed between builds since output.clean === false + createFile(`dist/apps/${appName}/extra.js`); + runCLI(`build ${appName} --skip-nx-cache`); + checkFilesExist(`dist/apps/${appName}/extra.js`); + }, 500_000); +}); diff --git a/e2e/webpack/src/webpack-assets.test.ts b/e2e/webpack/src/webpack-assets.test.ts new file mode 100644 index 0000000000000..6a346778f538c --- /dev/null +++ b/e2e/webpack/src/webpack-assets.test.ts @@ -0,0 +1,42 @@ +import { + checkFilesExist, + runCLI, + uniq, + updateFile, + updateJson, +} from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should resolve assets from executors as relative to workspace root', () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack` + ); + updateFile('shared/docs/TEST.md', 'TEST'); + updateJson(`apps/${appName}/project.json`, (json) => { + json.targets.build = { + executor: '@nx/webpack:webpack', + outputs: ['{options.outputPath}'], + options: { + assets: [ + { + input: 'shared/docs', + glob: 'TEST.md', + output: '.', + }, + ], + outputPath: `dist/apps/${appName}`, + webpackConfig: `apps/${appName}/webpack.config.js`, + }, + }; + return json; + }); + + runCLI(`build ${appName}`); + + checkFilesExist(`dist/apps/${appName}/TEST.md`); + }); +}); diff --git a/e2e/webpack/src/webpack-babel-corejs.test.ts b/e2e/webpack/src/webpack-babel-corejs.test.ts new file mode 100644 index 0000000000000..861b0374c5900 --- /dev/null +++ b/e2e/webpack/src/webpack-babel-corejs.test.ts @@ -0,0 +1,50 @@ +import { + checkFilesExist, + listFiles, + packageInstall, + readFile, + runCLI, + uniq, + updateFile, +} from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should support babel + core-js to polyfill JS features', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack --compiler=babel` + ); + packageInstall('core-js', undefined, '3.26.1', 'prod'); + + checkFilesExist(`apps/${appName}/src/main.ts`); + updateFile( + `apps/${appName}/src/main.ts`, + ` + import 'core-js/stable'; + async function main() { + const result = await Promise.resolve('foobar') + console.log(result); + } + main(); + ` + ); + + // Modern browser + updateFile(`apps/${appName}/.browserslistrc`, `last 1 Chrome version\n`); + runCLI(`build ${appName}`); + expect(readMainFile(`dist/apps/${appName}`)).toMatch(`await Promise`); + + // Legacy browser + updateFile(`apps/${appName}/.browserslistrc`, `IE 11\n`); + runCLI(`build ${appName}`); + expect(readMainFile(`dist/apps/${appName}`)).not.toMatch(`await Promise`); + }); +}); + +function readMainFile(dir: string): string { + const main = listFiles(dir).find((f) => f.startsWith('main.')); + return readFile(`${dir}/${main}`); +} diff --git a/e2e/webpack/src/webpack-babel-env.test.ts b/e2e/webpack/src/webpack-babel-env.test.ts new file mode 100644 index 0000000000000..7d94b363f9358 --- /dev/null +++ b/e2e/webpack/src/webpack-babel-env.test.ts @@ -0,0 +1,40 @@ +import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should use either BABEL_ENV or NODE_ENV value for Babel environment configuration', async () => { + const myPkg = uniq('my-pkg'); + runCLI( + `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none` + ); + updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`); + + runCLI( + `generate @nx/webpack:configuration ${myPkg} --target=node --compiler=babel --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts` + ); + + updateFile( + `libs/${myPkg}/.babelrc`, + `{ 'presets': ['@nx/js/babel', './custom-preset'] } ` + ); + updateFile( + `libs/${myPkg}/custom-preset.js`, + ` + module.exports = function(api, opts) { + console.log('Babel env is ' + api.env()); + return opts; + } + ` + ); + + let output = runCLI(`build ${myPkg}`, { + env: { + NODE_ENV: 'nodeEnv', + BABEL_ENV: 'babelEnv', + }, + }); + expect(output).toContain('Babel env is babelEnv'); + }, 500_000); +}); diff --git a/e2e/webpack/src/webpack-compose-plugins.test.ts b/e2e/webpack/src/webpack-compose-plugins.test.ts new file mode 100644 index 0000000000000..f892fd1944b14 --- /dev/null +++ b/e2e/webpack/src/webpack-compose-plugins.test.ts @@ -0,0 +1,42 @@ +import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should be able to support webpack config with nx enhanced and babel', () => { + const appName = uniq('app'); + + runCLI( + `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler=webpack --compiler=babel` + ); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const { composePlugins, withNx } = require('@nx/webpack'); + const { withReact } = require('@nx/react'); + const { join } = require('path'); + + const pluginOption = { + index: 'apps/${appName}/src/index.html', + main: 'apps/${appName}/src/main.ts', + tsConfig: 'apps/${appName}/tsconfig.app.json', + outputPath: 'dist/apps/${appName}', + } + + // Nx composable plugins for webpack. + module.exports = composePlugins( + withNx(pluginOption), + withReact(pluginOption), + );` + ); + + const result = runCLI(`build ${appName}`); + + expect(result).toContain(`nx run ${appName}:build`); + expect(result).toContain( + `Successfully ran target build for project ${appName}` + ); + }); +}); diff --git a/e2e/webpack/src/webpack-config-array.test.ts b/e2e/webpack/src/webpack-config-array.test.ts new file mode 100644 index 0000000000000..05caa69e8d470 --- /dev/null +++ b/e2e/webpack/src/webpack-config-array.test.ts @@ -0,0 +1,71 @@ +import { + checkFilesExist, + createFile, + runCLI, + uniq, + updateFile, +} from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('config types', () => { + setupWebpackTest(); + + it('should support an array of standard config objects', () => { + const appName = uniq('app'); + const serverName = uniq('server'); + + runCLI( + `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` + ); + + // Create server index file + createFile( + `apps/${serverName}/index.js`, + `console.log('Hello from ${serverName}');\n` + ); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const path = require('path'); + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + + module.exports = [ + { + name: 'client', + target: 'node', + output: { + path: path.join(__dirname, '../../dist/${appName}') + }, + plugins: [ + new NxAppWebpackPlugin({ + compiler: 'tsc', + main: './src/main.tsx', + tsConfig: './tsconfig.app.json', + outputHashing: 'none', + optimization: false, + }) + ] + }, { + name: 'server', + target: 'node', + entry: '../${serverName}/index.js', + output: { + path: path.join(__dirname, '../../dist/${serverName}'), + filename: 'index.js', + }, + } + ]; + ` + ); + + const result = runCLI(`build ${appName}`); + + checkFilesExist(`dist/${appName}/main.js`); + checkFilesExist(`dist/${serverName}/index.js`); + + expect(result).toContain( + `Successfully ran target build for project ${appName}` + ); + }); +}); diff --git a/e2e/webpack/src/webpack-config-function-array.test.ts b/e2e/webpack/src/webpack-config-function-array.test.ts new file mode 100644 index 0000000000000..82ff3f6fd66ca --- /dev/null +++ b/e2e/webpack/src/webpack-config-function-array.test.ts @@ -0,0 +1,72 @@ +import { + checkFilesExist, + createFile, + runCLI, + uniq, + updateFile, +} from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('config types', () => { + setupWebpackTest(); + + it('should support a function that returns an array of standard config objects', () => { + const appName = uniq('app'); + const serverName = uniq('server'); + + runCLI( + `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` + ); + + // Create server index file + createFile( + `apps/${serverName}/index.js`, + `console.log('Hello from ${serverName}');\n` + ); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const path = require('path'); + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + + module.exports = () => { + return [ + { + name: 'client', + target: 'node', + output: { + path: path.join(__dirname, '../../dist/${appName}') + }, + plugins: [ + new NxAppWebpackPlugin({ + compiler: 'tsc', + main: './src/main.tsx', + tsConfig: './tsconfig.app.json', + outputHashing: 'none', + optimization: false, + }) + ] + }, + { + name: 'server', + target: 'node', + entry: '../${serverName}/index.js', + output: { + path: path.join(__dirname, '../../dist/${serverName}'), + filename: 'index.js', + } + } + ]; + };` + ); + const result = runCLI(`build ${appName}`); + + checkFilesExist(`dist/${serverName}/index.js`); + checkFilesExist(`dist/${appName}/main.js`); + + expect(result).toContain( + `Successfully ran target build for project ${appName}` + ); + }); +}); diff --git a/e2e/webpack/src/webpack-config-function.test.ts b/e2e/webpack/src/webpack-config-function.test.ts new file mode 100644 index 0000000000000..d86039b6bcd47 --- /dev/null +++ b/e2e/webpack/src/webpack-config-function.test.ts @@ -0,0 +1,44 @@ +import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('config types', () => { + setupWebpackTest(); + + it('should support a standard function that returns a config object', () => { + const appName = uniq('app'); + + runCLI( + `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` + ); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const path = require('path'); + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + + module.exports = () => { + return { + target: 'node', + output: { + path: path.join(__dirname, '../../dist/${appName}') + }, + plugins: [ + new NxAppWebpackPlugin({ + compiler: 'tsc', + main: './src/main.tsx', + tsConfig: './tsconfig.app.json', + outputHashing: 'none', + optimization: false, + }) + ] + }; + };` + ); + + const result = runCLI(`build ${appName}`); + expect(result).toContain( + `Successfully ran target build for project ${appName}` + ); + }); +}); diff --git a/e2e/webpack/src/webpack-config-standard-object.test.ts b/e2e/webpack/src/webpack-config-standard-object.test.ts new file mode 100644 index 0000000000000..432c9d3482261 --- /dev/null +++ b/e2e/webpack/src/webpack-config-standard-object.test.ts @@ -0,0 +1,43 @@ +import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('config types', () => { + setupWebpackTest(); + + it('should support a standard config object', () => { + const appName = uniq('app'); + + runCLI( + `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` + ); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const path = require('path'); + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + + module.exports = { + target: 'node', + output: { + path: path.join(__dirname, '../../dist/${appName}') + }, + plugins: [ + new NxAppWebpackPlugin({ + compiler: 'babel', + main: './src/main.tsx', + tsConfig: './tsconfig.app.json', + outputHashing: 'none', + optimization: false, + }) + ] + };` + ); + + const result = runCLI(`build ${appName}`); + + expect(result).toContain( + `Successfully ran target build for project ${appName}` + ); + }); +}); diff --git a/e2e/webpack/src/webpack-env-variables.test.ts b/e2e/webpack/src/webpack-env-variables.test.ts new file mode 100644 index 0000000000000..551181f63e02e --- /dev/null +++ b/e2e/webpack/src/webpack-env-variables.test.ts @@ -0,0 +1,40 @@ +import { + checkFilesExist, + listFiles, + readFile, + runCLI, + uniq, + updateFile, +} from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should bundle in NX_PUBLIC_ environment variables', () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack` + ); + + checkFilesExist(`apps/${appName}/src/main.ts`); + updateFile( + `apps/${appName}/src/main.ts`, + ` + console.log(process.env['NX_PUBLIC_TEST']); + ` + ); + + runCLI(`build ${appName}`, { + env: { + NX_PUBLIC_TEST: 'foobar', + }, + }); + + const mainFile = listFiles(`dist/apps/${appName}`).filter((f) => + f.startsWith('main.') + ); + const content = readFile(`dist/apps/${appName}/${mainFile}`); + expect(content).toMatch(/foobar/); + }); +}); diff --git a/e2e/webpack/src/webpack-executor-options.test.ts b/e2e/webpack/src/webpack-executor-options.test.ts new file mode 100644 index 0000000000000..4c10fdbd85b2f --- /dev/null +++ b/e2e/webpack/src/webpack-executor-options.test.ts @@ -0,0 +1,62 @@ +import { + checkFilesExist, + fileExists, + runCLI, + uniq, + updateFile, + updateJson, +} from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should allow options to be passed from the executor', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack` + ); + + checkFilesExist(`apps/${appName}/project.json`); + updateJson(`apps/${appName}/project.json`, (json) => { + json.targets.build = { + executor: '@nx/webpack:webpack', + outputs: ['{options.outputPath}'], + options: { + generatePackageJson: true, // This should be passed to the plugin. + outputPath: `dist/apps/${appName}`, + webpackConfig: `apps/${appName}/webpack.config.js`, + }, + }; + return json; + }); + + checkFilesExist(`apps/${appName}/webpack.config.js`); + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + const { join } = require('path'); + module.exports = { + output: { + path: join(__dirname, '../../dist/apps/demo'), + }, + plugins: [ + new NxAppWebpackPlugin({ + // NOTE: generatePackageJson is missing here, but executor passes it. + target: 'web', + compiler: 'swc', + main: './src/main.ts', + tsConfig: './tsconfig.app.json', + optimization: false, + outputHashing: 'none', + }), + ], + };` + ); + + runCLI(`build ${appName}`); + + fileExists(`dist/apps/${appName}/package.json`); + }); +}); diff --git a/e2e/webpack/src/webpack-libs-from-source.test.ts b/e2e/webpack/src/webpack-libs-from-source.test.ts new file mode 100644 index 0000000000000..ce757f653034f --- /dev/null +++ b/e2e/webpack/src/webpack-libs-from-source.test.ts @@ -0,0 +1,60 @@ +import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('it should support building libraries and apps when buildLibsFromSource is false', () => { + const appName = uniq('app'); + const myPkg = uniq('my-pkg'); + + runCLI( + `generate @nx/web:application ${appName} --directory=apps/${appName}` + ); + + runCLI( + `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --importPath=@${appName}/${myPkg}` + ); + + updateFile(`libs/${myPkg}/src/index.ts`, `export const foo = 'bar';\n`); + + updateFile( + `apps/${appName}/src/main.ts`, + `import { foo } from '@${appName}/${myPkg}';\nconsole.log(foo);\n` + ); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const path = require('path'); + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + + module.exports = { + target: 'node', + output: { + path: path.join(__dirname, '../../dist/${appName}') + }, + plugins: [ + new NxAppWebpackPlugin({ + compiler: 'tsc', + main: 'apps/${appName}/src/main.ts', + tsConfig: 'apps/${appName}/tsconfig.app.json', + outputHashing: 'none', + optimization: false, + buildLibsFromSource: false, + }) + ] + };` + ); + + const result = runCLI(`build ${appName}`); + + expect(result).toContain( + `Running target build for project ${appName} and 1 task it depends on` + ); + expect(result).toContain(`nx run ${myPkg}:build`); + expect(result).toContain( + `Successfully ran target build for project ${appName} and 1 task it depends on` + ); + }); +}); diff --git a/e2e/webpack/src/webpack-node-compilers.test.ts b/e2e/webpack/src/webpack-node-compilers.test.ts new file mode 100644 index 0000000000000..d256168310ed6 --- /dev/null +++ b/e2e/webpack/src/webpack-node-compilers.test.ts @@ -0,0 +1,95 @@ +import { + rmDist, + runCLI, + runCommand, + uniq, + updateFile, + updateJson, +} from '@nx/e2e-utils'; +import { join } from 'path'; +import { setupWebpackTest } from './webpack-setup'; + +describe('Webpack Plugin', () => { + setupWebpackTest(); + + it('should be able to setup project to build node programs with webpack and different compilers', async () => { + const myPkg = uniq('my-pkg'); + runCLI( + `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none` + ); + updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`); + + runCLI( + `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts` + ); + + // Test `scriptType` later during during. + updateFile( + `libs/${myPkg}/webpack.config.js`, + ` + const path = require('path'); + const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); + + class DebugPlugin { + apply(compiler) { + console.log('scriptType is ' + compiler.options.output.scriptType); + } + } + + module.exports = { + target: 'node', + output: { + path: path.join(__dirname, '../../dist/libs/${myPkg}') + }, + plugins: [ + new NxAppWebpackPlugin({ + compiler: 'tsc', + main: './src/index.ts', + tsConfig: './tsconfig.lib.json', + outputHashing: 'none', + optimization: false, + }), + new DebugPlugin() + ] + };` + ); + + rmDist(); + + const buildOutput = runCLI(`build ${myPkg}`); + // Ensure scriptType is not set if we're in Node (it only applies to Web). + expect(buildOutput).toContain('scriptType is undefined'); + let output = runCommand(`node dist/libs/${myPkg}/main.js`); + expect(output).toMatch(/Hello/); + expect(output).not.toMatch(/Conflicting/); + expect(output).not.toMatch(/process.env.NODE_ENV/); + + updateJson(join('libs', myPkg, 'project.json'), (config) => { + delete config.targets.build; + return config; + }); + + // swc + runCLI( + `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=swc` + ); + rmDist(); + runCLI(`build ${myPkg}`); + output = runCommand(`node dist/libs/${myPkg}/main.js`); + expect(output).toMatch(/Hello/); + + updateJson(join('libs', myPkg, 'project.json'), (config) => { + delete config.targets.build; + return config; + }); + + // tsc + runCLI( + `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc` + ); + rmDist(); + runCLI(`build ${myPkg}`); + output = runCommand(`node dist/libs/${myPkg}/main.js`); + expect(output).toMatch(/Hello/); + }, 500000); +}); diff --git a/e2e/webpack/src/webpack-setup.ts b/e2e/webpack/src/webpack-setup.ts new file mode 100644 index 0000000000000..1ac7ebef980a2 --- /dev/null +++ b/e2e/webpack/src/webpack-setup.ts @@ -0,0 +1,6 @@ +import { cleanupProject, newProject } from '@nx/e2e-utils'; + +export function setupWebpackTest() { + beforeAll(() => newProject()); + afterAll(() => cleanupProject()); +} diff --git a/e2e/webpack/src/webpack.test.ts b/e2e/webpack/src/webpack.test.ts deleted file mode 100644 index 63911310584a9..0000000000000 --- a/e2e/webpack/src/webpack.test.ts +++ /dev/null @@ -1,618 +0,0 @@ -import { - checkFilesExist, - cleanupProject, - createFile, - fileExists, - listFiles, - newProject, - packageInstall, - readFile, - rmDist, - runCLI, - runCommand, - uniq, - updateFile, - updateJson, -} from '@nx/e2e-utils'; -import { join } from 'path'; - -describe('Webpack Plugin', () => { - beforeAll(() => newProject()); - afterAll(() => cleanupProject()); - - it('should be able to setup project to build node programs with webpack and different compilers', async () => { - const myPkg = uniq('my-pkg'); - runCLI( - `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none` - ); - updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`); - - runCLI( - `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts` - ); - - // Test `scriptType` later during during. - updateFile( - `libs/${myPkg}/webpack.config.js`, - ` - const path = require('path'); - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - - class DebugPlugin { - apply(compiler) { - console.log('scriptType is ' + compiler.options.output.scriptType); - } - } - - module.exports = { - target: 'node', - output: { - path: path.join(__dirname, '../../dist/libs/${myPkg}') - }, - plugins: [ - new NxAppWebpackPlugin({ - compiler: 'tsc', - main: './src/index.ts', - tsConfig: './tsconfig.lib.json', - outputHashing: 'none', - optimization: false, - }), - new DebugPlugin() - ] - };` - ); - - rmDist(); - - const buildOutput = runCLI(`build ${myPkg}`); - // Ensure scriptType is not set if we're in Node (it only applies to Web). - expect(buildOutput).toContain('scriptType is undefined'); - let output = runCommand(`node dist/libs/${myPkg}/main.js`); - expect(output).toMatch(/Hello/); - expect(output).not.toMatch(/Conflicting/); - expect(output).not.toMatch(/process.env.NODE_ENV/); - - updateJson(join('libs', myPkg, 'project.json'), (config) => { - delete config.targets.build; - return config; - }); - - // swc - runCLI( - `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=swc` - ); - rmDist(); - runCLI(`build ${myPkg}`); - output = runCommand(`node dist/libs/${myPkg}/main.js`); - expect(output).toMatch(/Hello/); - - updateJson(join('libs', myPkg, 'project.json'), (config) => { - delete config.targets.build; - return config; - }); - - // tsc - runCLI( - `generate @nx/webpack:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc` - ); - rmDist(); - runCLI(`build ${myPkg}`); - output = runCommand(`node dist/libs/${myPkg}/main.js`); - expect(output).toMatch(/Hello/); - }, 500000); - - it('should use either BABEL_ENV or NODE_ENV value for Babel environment configuration', async () => { - const myPkg = uniq('my-pkg'); - runCLI( - `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --bundler=none` - ); - updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`); - - runCLI( - `generate @nx/webpack:configuration ${myPkg} --target=node --compiler=babel --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts` - ); - - updateFile( - `libs/${myPkg}/.babelrc`, - `{ 'presets': ['@nx/js/babel', './custom-preset'] } ` - ); - updateFile( - `libs/${myPkg}/custom-preset.js`, - ` - module.exports = function(api, opts) { - console.log('Babel env is ' + api.env()); - return opts; - } - ` - ); - - let output = runCLI(`build ${myPkg}`, { - env: { - NODE_ENV: 'nodeEnv', - BABEL_ENV: 'babelEnv', - }, - }); - expect(output).toContain('Babel env is babelEnv'); - }, 500_000); - - it('should be able to build with NxWebpackPlugin and a standard webpack config file', () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app ${appName} --bundler webpack --directory=apps/${appName}` - ); - updateFile(`apps/${appName}/src/main.ts`, `console.log('Hello');\n`); - updateFile(`apps/${appName}/src/foo.ts`, `console.log('Foo');\n`); - updateFile(`apps/${appName}/src/bar.ts`, `console.log('Bar');\n`); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const path = require('path'); - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - - module.exports = { - target: 'node', - output: { - path: path.join(__dirname, '../../dist/apps/${appName}'), - // do not remove dist, so files between builds will remain - clean: false, - }, - plugins: [ - new NxAppWebpackPlugin({ - compiler: 'tsc', - main: './src/main.ts', - additionalEntryPoints: [ - './src/foo.ts', - { - entryName: 'bar', - entryPath: './src/bar.ts', - } - ], - tsConfig: './tsconfig.app.json', - outputHashing: 'none', - optimization: false, - }) - ] - };` - ); - - runCLI(`build ${appName}`); - - expect(runCommand(`node dist/apps/${appName}/main.js`)).toMatch(/Hello/); - expect(runCommand(`node dist/apps/${appName}/foo.js`)).toMatch(/Foo/); - expect(runCommand(`node dist/apps/${appName}/bar.js`)).toMatch(/Bar/); - - // Ensure dist is not removed between builds since output.clean === false - createFile(`dist/apps/${appName}/extra.js`); - runCLI(`build ${appName} --skip-nx-cache`); - checkFilesExist(`dist/apps/${appName}/extra.js`); - }, 500_000); - - it('should bundle in NX_PUBLIC_ environment variables', () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack` - ); - - checkFilesExist(`apps/${appName}/src/main.ts`); - updateFile( - `apps/${appName}/src/main.ts`, - ` - console.log(process.env['NX_PUBLIC_TEST']); - ` - ); - - runCLI(`build ${appName}`, { - env: { - NX_PUBLIC_TEST: 'foobar', - }, - }); - - const mainFile = listFiles(`dist/apps/${appName}`).filter((f) => - f.startsWith('main.') - ); - const content = readFile(`dist/apps/${appName}/${mainFile}`); - expect(content).toMatch(/foobar/); - }); - - it('should support babel + core-js to polyfill JS features', async () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack --compiler=babel` - ); - packageInstall('core-js', undefined, '3.26.1', 'prod'); - - checkFilesExist(`apps/${appName}/src/main.ts`); - updateFile( - `apps/${appName}/src/main.ts`, - ` - import 'core-js/stable'; - async function main() { - const result = await Promise.resolve('foobar') - console.log(result); - } - main(); - ` - ); - - // Modern browser - updateFile(`apps/${appName}/.browserslistrc`, `last 1 Chrome version\n`); - runCLI(`build ${appName}`); - expect(readMainFile(`dist/apps/${appName}`)).toMatch(`await Promise`); - - // Legacy browser - updateFile(`apps/${appName}/.browserslistrc`, `IE 11\n`); - runCLI(`build ${appName}`); - expect(readMainFile(`dist/apps/${appName}`)).not.toMatch(`await Promise`); - }); - - it('should allow options to be passed from the executor', async () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack` - ); - - checkFilesExist(`apps/${appName}/project.json`); - updateJson(`apps/${appName}/project.json`, (json) => { - json.targets.build = { - executor: '@nx/webpack:webpack', - outputs: ['{options.outputPath}'], - options: { - generatePackageJson: true, // This should be passed to the plugin. - outputPath: `dist/apps/${appName}`, - webpackConfig: `apps/${appName}/webpack.config.js`, - }, - }; - return json; - }); - - checkFilesExist(`apps/${appName}/webpack.config.js`); - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - const { join } = require('path'); - module.exports = { - output: { - path: join(__dirname, '../../dist/apps/demo'), - }, - plugins: [ - new NxAppWebpackPlugin({ - // NOTE: generatePackageJson is missing here, but executor passes it. - target: 'web', - compiler: 'swc', - main: './src/main.ts', - tsConfig: './tsconfig.app.json', - optimization: false, - outputHashing: 'none', - }), - ], - };` - ); - - runCLI(`build ${appName}`); - - fileExists(`dist/apps/${appName}/package.json`); - }); - - it('should resolve assets from executors as relative to workspace root', () => { - const appName = uniq('app'); - runCLI( - `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler webpack` - ); - updateFile('shared/docs/TEST.md', 'TEST'); - updateJson(`apps/${appName}/project.json`, (json) => { - json.targets.build = { - executor: '@nx/webpack:webpack', - outputs: ['{options.outputPath}'], - options: { - assets: [ - { - input: 'shared/docs', - glob: 'TEST.md', - output: '.', - }, - ], - outputPath: `dist/apps/${appName}`, - webpackConfig: `apps/${appName}/webpack.config.js`, - }, - }; - return json; - }); - - runCLI(`build ${appName}`); - - checkFilesExist(`dist/apps/${appName}/TEST.md`); - }); - - it('it should support building libraries and apps when buildLibsFromSource is false', () => { - const appName = uniq('app'); - const myPkg = uniq('my-pkg'); - - runCLI( - `generate @nx/web:application ${appName} --directory=apps/${appName}` - ); - - runCLI( - `generate @nx/js:lib ${myPkg} --directory=libs/${myPkg} --importPath=@${appName}/${myPkg}` - ); - - updateFile(`libs/${myPkg}/src/index.ts`, `export const foo = 'bar';\n`); - - updateFile( - `apps/${appName}/src/main.ts`, - `import { foo } from '@${appName}/${myPkg}';\nconsole.log(foo);\n` - ); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const path = require('path'); - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - - module.exports = { - target: 'node', - output: { - path: path.join(__dirname, '../../dist/${appName}') - }, - plugins: [ - new NxAppWebpackPlugin({ - compiler: 'tsc', - main: 'apps/${appName}/src/main.ts', - tsConfig: 'apps/${appName}/tsconfig.app.json', - outputHashing: 'none', - optimization: false, - buildLibsFromSource: false, - }) - ] - };` - ); - - const result = runCLI(`build ${appName}`); - - expect(result).toContain( - `Running target build for project ${appName} and 1 task it depends on` - ); - expect(result).toContain(`nx run ${myPkg}:build`); - expect(result).toContain( - `Successfully ran target build for project ${appName} and 1 task it depends on` - ); - }); - - it('should be able to support webpack config with nx enhanced and babel', () => { - const appName = uniq('app'); - - runCLI( - `generate @nx/web:app ${appName} --directory=apps/${appName} --bundler=webpack --compiler=babel` - ); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const { composePlugins, withNx } = require('@nx/webpack'); - const { withReact } = require('@nx/react'); - const { join } = require('path'); - - const pluginOption = { - index: 'apps/${appName}/src/index.html', - main: 'apps/${appName}/src/main.ts', - tsConfig: 'apps/${appName}/tsconfig.app.json', - outputPath: 'dist/apps/${appName}', - } - - // Nx composable plugins for webpack. - module.exports = composePlugins( - withNx(pluginOption), - withReact(pluginOption), - );` - ); - - const result = runCLI(`build ${appName}`); - - expect(result).toContain(`nx run ${appName}:build`); - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }); - - describe('config types', () => { - it('should support a standard config object', () => { - const appName = uniq('app'); - - runCLI( - `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` - ); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const path = require('path'); - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - - module.exports = { - target: 'node', - output: { - path: path.join(__dirname, '../../dist/${appName}') - }, - plugins: [ - new NxAppWebpackPlugin({ - compiler: 'babel', - main: './src/main.tsx', - tsConfig: './tsconfig.app.json', - outputHashing: 'none', - optimization: false, - }) - ] - };` - ); - - const result = runCLI(`build ${appName}`); - - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }); - - it('should support a standard function that returns a config object', () => { - const appName = uniq('app'); - - runCLI( - `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` - ); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const path = require('path'); - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - - module.exports = () => { - return { - target: 'node', - output: { - path: path.join(__dirname, '../../dist/${appName}') - }, - plugins: [ - new NxAppWebpackPlugin({ - compiler: 'tsc', - main: './src/main.tsx', - tsConfig: './tsconfig.app.json', - outputHashing: 'none', - optimization: false, - }) - ] - }; - };` - ); - - const result = runCLI(`build ${appName}`); - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }); - - it('should support an array of standard config objects', () => { - const appName = uniq('app'); - const serverName = uniq('server'); - - runCLI( - `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` - ); - - // Create server index file - createFile( - `apps/${serverName}/index.js`, - `console.log('Hello from ${serverName}');\n` - ); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const path = require('path'); - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - - module.exports = [ - { - name: 'client', - target: 'node', - output: { - path: path.join(__dirname, '../../dist/${appName}') - }, - plugins: [ - new NxAppWebpackPlugin({ - compiler: 'tsc', - main: './src/main.tsx', - tsConfig: './tsconfig.app.json', - outputHashing: 'none', - optimization: false, - }) - ] - }, { - name: 'server', - target: 'node', - entry: '../${serverName}/index.js', - output: { - path: path.join(__dirname, '../../dist/${serverName}'), - filename: 'index.js', - }, - } - ]; - ` - ); - - const result = runCLI(`build ${appName}`); - - checkFilesExist(`dist/${appName}/main.js`); - checkFilesExist(`dist/${serverName}/index.js`); - - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }); - - it('should support a function that returns an array of standard config objects', () => { - const appName = uniq('app'); - const serverName = uniq('server'); - - runCLI( - `generate @nx/react:application --directory=apps/${appName} --bundler=webpack --e2eTestRunner=none` - ); - - // Create server index file - createFile( - `apps/${serverName}/index.js`, - `console.log('Hello from ${serverName}');\n` - ); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const path = require('path'); - const { NxAppWebpackPlugin } = require('@nx/webpack/app-plugin'); - - module.exports = () => { - return [ - { - name: 'client', - target: 'node', - output: { - path: path.join(__dirname, '../../dist/${appName}') - }, - plugins: [ - new NxAppWebpackPlugin({ - compiler: 'tsc', - main: './src/main.tsx', - tsConfig: './tsconfig.app.json', - outputHashing: 'none', - optimization: false, - }) - ] - }, - { - name: 'server', - target: 'node', - entry: '../${serverName}/index.js', - output: { - path: path.join(__dirname, '../../dist/${serverName}'), - filename: 'index.js', - } - } - ]; - };` - ); - const result = runCLI(`build ${appName}`); - - checkFilesExist(`dist/${serverName}/index.js`); - checkFilesExist(`dist/${appName}/main.js`); - - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }); - }); -}); - -function readMainFile(dir: string): string { - const main = listFiles(dir).find((f) => f.startsWith('main.')); - return readFile(`${dir}/${main}`); -} diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-angular.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-angular.test.ts new file mode 100644 index 0000000000000..d72e9794ee365 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-angular.test.ts @@ -0,0 +1,41 @@ +import { + checkFilesExist, + packageInstall, + readJson, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add angular application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/angular', wsName); + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nx/angular:app packages/${appName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }, 1_000_000); + + it('should add angular library', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/angular', wsName); + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nx/angular:lib packages/${libName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + const tsconfig = readJson(`tsconfig.base.json`); + expect(tsconfig.compilerOptions.paths).toEqual({ + [`@${wsName}/${libName}`]: [`packages/${libName}/src/index.ts`], + }); + }, 1_000_000); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts new file mode 100644 index 0000000000000..67243891d21ac --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts @@ -0,0 +1,26 @@ +import { + checkFilesExist, + packageInstall, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add express application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/express', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nx/express:app packages/${appName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-init.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-init.test.ts new file mode 100644 index 0000000000000..e419bde76da5d --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-init.test.ts @@ -0,0 +1,24 @@ +import { + checkFilesExist, + getSelectedPackageManager, + readJson, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should setup package-based workspace', () => { + const packageJson = readJson('package.json'); + expect(packageJson.dependencies).toEqual({}); + + if (getSelectedPackageManager() === 'pnpm') { + checkFilesExist('pnpm-workspace.yaml'); + } else { + expect(packageJson.workspaces).toEqual(['packages/*']); + } + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-js.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-js.test.ts new file mode 100644 index 0000000000000..ad15853db8e32 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-js.test.ts @@ -0,0 +1,34 @@ +import { + checkFilesExist, + packageInstall, + readJson, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add js library', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/js', wsName); + + const libName = uniq('lib'); + + expect(() => + runCLI(`generate @nx/js:library packages/${libName} --no-interactive`) + ).not.toThrow(); + checkFilesExist('tsconfig.base.json', 'tsconfig.json'); + const tsconfigBase = readJson(`tsconfig.base.json`); + expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); + const tsconfig = readJson(`tsconfig.json`); + expect(tsconfig.extends).toBe('./tsconfig.base.json'); + expect(tsconfig.references).toStrictEqual([ + { path: `./packages/${libName}` }, + ]); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-nest.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-nest.test.ts new file mode 100644 index 0000000000000..7dd0d2611d3f5 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-nest.test.ts @@ -0,0 +1,46 @@ +import { + checkFilesExist, + packageInstall, + readJson, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add nest application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/nest', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nx/nest:app packages/${appName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add nest library', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/nest', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nx/nest:lib packages/${libName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json', 'tsconfig.json'); + const tsconfigBase = readJson(`tsconfig.base.json`); + expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); + const tsconfig = readJson(`tsconfig.json`); + expect(tsconfig.extends).toBe('./tsconfig.base.json'); + expect(tsconfig.references).toStrictEqual([ + { path: `./packages/${libName}` }, + ]); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-next.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-next.test.ts new file mode 100644 index 0000000000000..6ae05ed9c73e0 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-next.test.ts @@ -0,0 +1,46 @@ +import { + checkFilesExist, + packageInstall, + readJson, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add next application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/next', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nx/next:app packages/${appName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add next library', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/next', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nx/next:lib packages/${libName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json', 'tsconfig.json'); + const tsconfigBase = readJson(`tsconfig.base.json`); + expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); + const tsconfig = readJson(`tsconfig.json`); + expect(tsconfig.extends).toBe('./tsconfig.base.json'); + expect(tsconfig.references).toStrictEqual([ + { path: `./packages/${libName}` }, + ]); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-node.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-node.test.ts new file mode 100644 index 0000000000000..e8a2c3682ed24 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-node.test.ts @@ -0,0 +1,46 @@ +import { + checkFilesExist, + packageInstall, + readJson, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add node application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/node', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nx/node:app packages/${appName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add node library', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/node', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nx/node:lib packages/${libName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json', 'tsconfig.json'); + const tsconfigBase = readJson(`tsconfig.base.json`); + expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); + const tsconfig = readJson(`tsconfig.json`); + expect(tsconfig.extends).toBe('./tsconfig.base.json'); + expect(tsconfig.references).toStrictEqual([ + { path: `./packages/${libName}` }, + ]); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-react-native.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-react-native.test.ts new file mode 100644 index 0000000000000..6f28dc361f99d --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-react-native.test.ts @@ -0,0 +1,50 @@ +import { + checkFilesExist, + packageInstall, + readJson, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add react-native application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/react-native', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI( + `generate @nx/react-native:app packages/${appName} --install=false --no-interactive` + ); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add react-native library', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/react-native', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI( + `generate @nx/react-native:lib packages/${libName} --no-interactive` + ); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json', 'tsconfig.json'); + const tsconfigBase = readJson(`tsconfig.base.json`); + expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); + const tsconfig = readJson(`tsconfig.json`); + expect(tsconfig.extends).toBe('./tsconfig.base.json'); + expect(tsconfig.references).toStrictEqual([ + { path: `./packages/${libName}` }, + ]); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-react.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-react.test.ts new file mode 100644 index 0000000000000..defe48e5179d5 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-react.test.ts @@ -0,0 +1,46 @@ +import { + checkFilesExist, + packageInstall, + readJson, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add react application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/react', wsName); + + const appName = uniq('my-app'); + + expect(() => { + runCLI(`generate @nx/react:app packages/${appName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }); + + it('should add react library', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/react', wsName); + + const libName = uniq('lib'); + + expect(() => { + runCLI(`generate @nx/react:lib packages/${libName} --no-interactive`); + }).not.toThrow(); + checkFilesExist('tsconfig.base.json', 'tsconfig.json'); + const tsconfigBase = readJson(`tsconfig.base.json`); + expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); + const tsconfig = readJson(`tsconfig.json`); + expect(tsconfig.extends).toBe('./tsconfig.base.json'); + expect(tsconfig.references).toStrictEqual([ + { path: `./packages/${libName}` }, + ]); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-setup.ts b/e2e/workspace-create/src/create-nx-workspace-npm-setup.ts new file mode 100644 index 0000000000000..28e8893a24849 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-setup.ts @@ -0,0 +1,39 @@ +import { + cleanupProject, + getSelectedPackageManager, + runCommand, + runCreateWorkspace, + uniq, +} from '@nx/e2e-utils'; + +const wsName = uniq('npm'); + +let orginalGlobCache; + +export function setupNpmWorkspaceTest() { + beforeAll(() => { + orginalGlobCache = process.env.NX_PROJECT_GLOB_CACHE; + // glob cache is causing previous projects to show in Workspace for maxWorkers overrides + // which fails due to files no longer being available + process.env.NX_PROJECT_GLOB_CACHE = 'false'; + + runCreateWorkspace(wsName, { + preset: 'npm', + packageManager: getSelectedPackageManager(), + }); + }); + + afterEach(() => { + // cleanup previous projects + runCommand(`rm -rf packages/** tsconfig.base.json tsconfig.json`); + }); + + afterAll(() => { + process.env.NX_PROJECT_GLOB_CACHE = orginalGlobCache; + cleanupProject({ skipReset: true }); + }); +} + +export function getWorkspaceName() { + return wsName; +} diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts new file mode 100644 index 0000000000000..82cdcc4163659 --- /dev/null +++ b/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts @@ -0,0 +1,26 @@ +import { + checkFilesExist, + packageInstall, + runCLI, + uniq, +} from '@nx/e2e-utils'; +import { + setupNpmWorkspaceTest, + getWorkspaceName, +} from './create-nx-workspace-npm-setup'; + +describe('create-nx-workspace --preset=npm', () => { + setupNpmWorkspaceTest(); + + it('should add web application', () => { + const wsName = getWorkspaceName(); + packageInstall('@nx/web', wsName); + + const appName = uniq('my-app'); + + expect(() => + runCLI(`generate @nx/web:app packages/${appName} --no-interactive`) + ).not.toThrow(); + checkFilesExist('tsconfig.base.json'); + }); +}); diff --git a/e2e/workspace-create/src/create-nx-workspace-npm.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm.test.ts deleted file mode 100644 index 837902373f585..0000000000000 --- a/e2e/workspace-create/src/create-nx-workspace-npm.test.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { - checkFilesExist, - cleanupProject, - getSelectedPackageManager, - packageInstall, - readJson, - runCLI, - runCommand, - runCreateWorkspace, - uniq, -} from '@nx/e2e-utils'; - -describe('create-nx-workspace --preset=npm', () => { - const wsName = uniq('npm'); - - let orginalGlobCache; - - beforeAll(() => { - orginalGlobCache = process.env.NX_PROJECT_GLOB_CACHE; - // glob cache is causing previous projects to show in Workspace for maxWorkers overrides - // which fails due to files no longer being available - process.env.NX_PROJECT_GLOB_CACHE = 'false'; - - runCreateWorkspace(wsName, { - preset: 'npm', - packageManager: getSelectedPackageManager(), - }); - }); - - afterEach(() => { - // cleanup previous projects - runCommand(`rm -rf packages/** tsconfig.base.json tsconfig.json`); - }); - - afterAll(() => { - process.env.NX_PROJECT_GLOB_CACHE = orginalGlobCache; - cleanupProject({ skipReset: true }); - }); - - it('should setup package-based workspace', () => { - const packageJson = readJson('package.json'); - expect(packageJson.dependencies).toEqual({}); - - if (getSelectedPackageManager() === 'pnpm') { - checkFilesExist('pnpm-workspace.yaml'); - } else { - expect(packageJson.workspaces).toEqual(['packages/*']); - } - }); - - it('should add angular application', () => { - packageInstall('@nx/angular', wsName); - const appName = uniq('my-app'); - - expect(() => { - runCLI(`generate @nx/angular:app packages/${appName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }, 1_000_000); - - it('should add angular library', () => { - packageInstall('@nx/angular', wsName); - const libName = uniq('lib'); - - expect(() => { - runCLI(`generate @nx/angular:lib packages/${libName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - const tsconfig = readJson(`tsconfig.base.json`); - expect(tsconfig.compilerOptions.paths).toEqual({ - [`@${wsName}/${libName}`]: [`packages/${libName}/src/index.ts`], - }); - }, 1_000_000); - - it('should add js library', () => { - packageInstall('@nx/js', wsName); - - const libName = uniq('lib'); - - expect(() => - runCLI(`generate @nx/js:library packages/${libName} --no-interactive`) - ).not.toThrow(); - checkFilesExist('tsconfig.base.json', 'tsconfig.json'); - const tsconfigBase = readJson(`tsconfig.base.json`); - expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); - const tsconfig = readJson(`tsconfig.json`); - expect(tsconfig.extends).toBe('./tsconfig.base.json'); - expect(tsconfig.references).toStrictEqual([ - { path: `./packages/${libName}` }, - ]); - }); - - it('should add web application', () => { - packageInstall('@nx/web', wsName); - - const appName = uniq('my-app'); - - expect(() => - runCLI(`generate @nx/web:app packages/${appName} --no-interactive`) - ).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }); - - it('should add react application', () => { - packageInstall('@nx/react', wsName); - - const appName = uniq('my-app'); - - expect(() => { - runCLI(`generate @nx/react:app packages/${appName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }); - - it('should add react library', () => { - packageInstall('@nx/react', wsName); - - const libName = uniq('lib'); - - expect(() => { - runCLI(`generate @nx/react:lib packages/${libName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json', 'tsconfig.json'); - const tsconfigBase = readJson(`tsconfig.base.json`); - expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); - const tsconfig = readJson(`tsconfig.json`); - expect(tsconfig.extends).toBe('./tsconfig.base.json'); - expect(tsconfig.references).toStrictEqual([ - { path: `./packages/${libName}` }, - ]); - }); - - it('should add next application', () => { - packageInstall('@nx/next', wsName); - - const appName = uniq('my-app'); - - expect(() => { - runCLI(`generate @nx/next:app packages/${appName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }); - - it('should add next library', () => { - packageInstall('@nx/next', wsName); - - const libName = uniq('lib'); - - expect(() => { - runCLI(`generate @nx/next:lib packages/${libName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json', 'tsconfig.json'); - const tsconfigBase = readJson(`tsconfig.base.json`); - expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); - const tsconfig = readJson(`tsconfig.json`); - expect(tsconfig.extends).toBe('./tsconfig.base.json'); - expect(tsconfig.references).toStrictEqual([ - { path: `./packages/${libName}` }, - ]); - }); - - it('should add react-native application', () => { - packageInstall('@nx/react-native', wsName); - - const appName = uniq('my-app'); - - expect(() => { - runCLI( - `generate @nx/react-native:app packages/${appName} --install=false --no-interactive` - ); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }); - - it('should add react-native library', () => { - packageInstall('@nx/react-native', wsName); - - const libName = uniq('lib'); - - expect(() => { - runCLI( - `generate @nx/react-native:lib packages/${libName} --no-interactive` - ); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json', 'tsconfig.json'); - const tsconfigBase = readJson(`tsconfig.base.json`); - expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); - const tsconfig = readJson(`tsconfig.json`); - expect(tsconfig.extends).toBe('./tsconfig.base.json'); - expect(tsconfig.references).toStrictEqual([ - { path: `./packages/${libName}` }, - ]); - }); - - it('should add node application', () => { - packageInstall('@nx/node', wsName); - - const appName = uniq('my-app'); - - expect(() => { - runCLI(`generate @nx/node:app packages/${appName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }); - - it('should add node library', () => { - packageInstall('@nx/node', wsName); - - const libName = uniq('lib'); - - expect(() => { - runCLI(`generate @nx/node:lib packages/${libName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json', 'tsconfig.json'); - const tsconfigBase = readJson(`tsconfig.base.json`); - expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); - const tsconfig = readJson(`tsconfig.json`); - expect(tsconfig.extends).toBe('./tsconfig.base.json'); - expect(tsconfig.references).toStrictEqual([ - { path: `./packages/${libName}` }, - ]); - }); - - it('should add nest application', () => { - packageInstall('@nx/nest', wsName); - - const appName = uniq('my-app'); - - expect(() => { - runCLI(`generate @nx/nest:app packages/${appName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }); - - it('should add nest library', () => { - packageInstall('@nx/nest', wsName); - - const libName = uniq('lib'); - - expect(() => { - runCLI(`generate @nx/nest:lib packages/${libName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json', 'tsconfig.json'); - const tsconfigBase = readJson(`tsconfig.base.json`); - expect(tsconfigBase.compilerOptions.paths).toBeUndefined(); - const tsconfig = readJson(`tsconfig.json`); - expect(tsconfig.extends).toBe('./tsconfig.base.json'); - expect(tsconfig.references).toStrictEqual([ - { path: `./packages/${libName}` }, - ]); - }); - - it('should add express application', () => { - packageInstall('@nx/express', wsName); - - const appName = uniq('my-app'); - - expect(() => { - runCLI(`generate @nx/express:app packages/${appName} --no-interactive`); - }).not.toThrow(); - checkFilesExist('tsconfig.base.json'); - }); -}); From e53e9e8c6e6be459885ca03394db26e4175a432d Mon Sep 17 00:00:00 2001 From: "nx-cloud[bot]" <71083854+nx-cloud[bot]@users.noreply.github.com> Date: Wed, 8 Oct 2025 14:06:06 +0000 Subject: [PATCH 02/12] fix: format import statements in new e2e test files --- e2e/web/src/web-html-interpolation.test.ts | 8 +------- .../src/create-nx-workspace-npm-express.test.ts | 7 +------ .../src/create-nx-workspace-npm-web.test.ts | 7 +------ 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/e2e/web/src/web-html-interpolation.test.ts b/e2e/web/src/web-html-interpolation.test.ts index 69e7000db5d9d..c4dc054cf4b1d 100644 --- a/e2e/web/src/web-html-interpolation.test.ts +++ b/e2e/web/src/web-html-interpolation.test.ts @@ -1,10 +1,4 @@ -import { - createFile, - readFile, - runCLI, - uniq, - updateFile, -} from '@nx/e2e-utils'; +import { createFile, readFile, runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebTest } from './web-setup'; describe('index.html interpolation', () => { diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts index 67243891d21ac..07a3a86d3cd1e 100644 --- a/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts +++ b/e2e/workspace-create/src/create-nx-workspace-npm-express.test.ts @@ -1,9 +1,4 @@ -import { - checkFilesExist, - packageInstall, - runCLI, - uniq, -} from '@nx/e2e-utils'; +import { checkFilesExist, packageInstall, runCLI, uniq } from '@nx/e2e-utils'; import { setupNpmWorkspaceTest, getWorkspaceName, diff --git a/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts b/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts index 82cdcc4163659..9c73153737da5 100644 --- a/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts +++ b/e2e/workspace-create/src/create-nx-workspace-npm-web.test.ts @@ -1,9 +1,4 @@ -import { - checkFilesExist, - packageInstall, - runCLI, - uniq, -} from '@nx/e2e-utils'; +import { checkFilesExist, packageInstall, runCLI, uniq } from '@nx/e2e-utils'; import { setupNpmWorkspaceTest, getWorkspaceName, From f7059748928b2755c140db3d3f132f821d40c326 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Thu, 16 Oct 2025 13:26:03 +0100 Subject: [PATCH 03/12] chore(repo): fix failing tests --- e2e/webpack/src/webpack-app-plugin.test.ts | 2 +- e2e/webpack/src/webpack-assets.test.ts | 2 +- e2e/webpack/src/webpack-babel-corejs.test.ts | 2 +- e2e/webpack/src/webpack-babel-env.test.ts | 2 +- .../src/webpack-compose-plugins.test.ts | 2 +- e2e/webpack/src/webpack-config-array.test.ts | 2 +- .../src/webpack-config-function-array.test.ts | 2 +- .../src/webpack-config-function.test.ts | 2 +- .../webpack-config-standard-object.test.ts | 2 +- e2e/webpack/src/webpack-env-variables.test.ts | 2 +- .../src/webpack-executor-options.test.ts | 2 +- .../src/webpack-libs-from-source.test.ts | 2 +- .../src/webpack-node-compilers.test.ts | 2 +- e2e/webpack/src/webpack-setup.ts | 36 +++++++++++++++++-- 14 files changed, 47 insertions(+), 15 deletions(-) diff --git a/e2e/webpack/src/webpack-app-plugin.test.ts b/e2e/webpack/src/webpack-app-plugin.test.ts index 6569b23b7df1e..b0045adf59522 100644 --- a/e2e/webpack/src/webpack-app-plugin.test.ts +++ b/e2e/webpack/src/webpack-app-plugin.test.ts @@ -9,7 +9,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/web', '@nx/webpack']); it('should be able to build with NxWebpackPlugin and a standard webpack config file', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-assets.test.ts b/e2e/webpack/src/webpack-assets.test.ts index 6a346778f538c..9c2ad782610ee 100644 --- a/e2e/webpack/src/webpack-assets.test.ts +++ b/e2e/webpack/src/webpack-assets.test.ts @@ -8,7 +8,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/web', '@nx/webpack']); it('should resolve assets from executors as relative to workspace root', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-babel-corejs.test.ts b/e2e/webpack/src/webpack-babel-corejs.test.ts index 861b0374c5900..f606ff90a8925 100644 --- a/e2e/webpack/src/webpack-babel-corejs.test.ts +++ b/e2e/webpack/src/webpack-babel-corejs.test.ts @@ -10,7 +10,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/web', '@nx/webpack']); it('should support babel + core-js to polyfill JS features', async () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-babel-env.test.ts b/e2e/webpack/src/webpack-babel-env.test.ts index 7d94b363f9358..9c7cf7e3373dd 100644 --- a/e2e/webpack/src/webpack-babel-env.test.ts +++ b/e2e/webpack/src/webpack-babel-env.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/js', '@nx/webpack']); it('should use either BABEL_ENV or NODE_ENV value for Babel environment configuration', async () => { const myPkg = uniq('my-pkg'); diff --git a/e2e/webpack/src/webpack-compose-plugins.test.ts b/e2e/webpack/src/webpack-compose-plugins.test.ts index f892fd1944b14..017bf390ab395 100644 --- a/e2e/webpack/src/webpack-compose-plugins.test.ts +++ b/e2e/webpack/src/webpack-compose-plugins.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/web', '@nx/webpack']); it('should be able to support webpack config with nx enhanced and babel', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-array.test.ts b/e2e/webpack/src/webpack-config-array.test.ts index 05caa69e8d470..622916bff35a5 100644 --- a/e2e/webpack/src/webpack-config-array.test.ts +++ b/e2e/webpack/src/webpack-config-array.test.ts @@ -8,7 +8,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/react', '@nx/webpack']); it('should support an array of standard config objects', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-function-array.test.ts b/e2e/webpack/src/webpack-config-function-array.test.ts index 82ff3f6fd66ca..19823844a8093 100644 --- a/e2e/webpack/src/webpack-config-function-array.test.ts +++ b/e2e/webpack/src/webpack-config-function-array.test.ts @@ -8,7 +8,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/react', '@nx/webpack']); it('should support a function that returns an array of standard config objects', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-function.test.ts b/e2e/webpack/src/webpack-config-function.test.ts index d86039b6bcd47..0b5100f574f38 100644 --- a/e2e/webpack/src/webpack-config-function.test.ts +++ b/e2e/webpack/src/webpack-config-function.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/react', '@nx/webpack']); it('should support a standard function that returns a config object', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-standard-object.test.ts b/e2e/webpack/src/webpack-config-standard-object.test.ts index 432c9d3482261..d6afc40e371cc 100644 --- a/e2e/webpack/src/webpack-config-standard-object.test.ts +++ b/e2e/webpack/src/webpack-config-standard-object.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/react', '@nx/webpack']); it('should support a standard config object', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-env-variables.test.ts b/e2e/webpack/src/webpack-env-variables.test.ts index 551181f63e02e..c8ced7066c2e2 100644 --- a/e2e/webpack/src/webpack-env-variables.test.ts +++ b/e2e/webpack/src/webpack-env-variables.test.ts @@ -9,7 +9,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/web', '@nx/webpack']); it('should bundle in NX_PUBLIC_ environment variables', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-executor-options.test.ts b/e2e/webpack/src/webpack-executor-options.test.ts index 4c10fdbd85b2f..9f984342eac9b 100644 --- a/e2e/webpack/src/webpack-executor-options.test.ts +++ b/e2e/webpack/src/webpack-executor-options.test.ts @@ -9,7 +9,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/web', '@nx/webpack']); it('should allow options to be passed from the executor', async () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-libs-from-source.test.ts b/e2e/webpack/src/webpack-libs-from-source.test.ts index ce757f653034f..d2af3d6b4b467 100644 --- a/e2e/webpack/src/webpack-libs-from-source.test.ts +++ b/e2e/webpack/src/webpack-libs-from-source.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/web', '@nx/js', '@nx/webpack']); it('it should support building libraries and apps when buildLibsFromSource is false', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-node-compilers.test.ts b/e2e/webpack/src/webpack-node-compilers.test.ts index d256168310ed6..20e9f9a3b7714 100644 --- a/e2e/webpack/src/webpack-node-compilers.test.ts +++ b/e2e/webpack/src/webpack-node-compilers.test.ts @@ -10,7 +10,7 @@ import { join } from 'path'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(); + setupWebpackTest(['@nx/js', '@nx/webpack']); it('should be able to setup project to build node programs with webpack and different compilers', async () => { const myPkg = uniq('my-pkg'); diff --git a/e2e/webpack/src/webpack-setup.ts b/e2e/webpack/src/webpack-setup.ts index 1ac7ebef980a2..43ba9eb11607c 100644 --- a/e2e/webpack/src/webpack-setup.ts +++ b/e2e/webpack/src/webpack-setup.ts @@ -1,6 +1,38 @@ import { cleanupProject, newProject } from '@nx/e2e-utils'; -export function setupWebpackTest() { - beforeAll(() => newProject()); +// Define a type that matches what newProject accepts for packages +type NxPackage = + | '@nx/angular' + | '@nx/cypress' + | '@nx/docker' + | '@nx/eslint-plugin' + | '@nx/express' + | '@nx/esbuild' + | '@nx/gradle' + | '@nx/jest' + | '@nx/js' + | '@nx/eslint' + | '@nx/nest' + | '@nx/next' + | '@nx/node' + | '@nx/nuxt' + | '@nx/plugin' + | '@nx/playwright' + | '@nx/rollup' + | '@nx/react' + | '@nx/remix' + | '@nx/rspack' + | '@nx/storybook' + | '@nx/vue' + | '@nx/vite' + | '@nx/web' + | '@nx/webpack' + | '@nx/react-native' + | '@nx/expo'; + +export function setupWebpackTest(packages?: readonly NxPackage[]) { + beforeAll(() => + newProject({ packages: packages as Array | undefined }) + ); afterAll(() => cleanupProject()); } From c1ec8a1db38b18f37432267d89c56c6c866a59b5 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Thu, 16 Oct 2025 13:26:17 +0100 Subject: [PATCH 04/12] chore(repo): fix failing tests --- e2e/webpack/src/webpack-setup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/webpack/src/webpack-setup.ts b/e2e/webpack/src/webpack-setup.ts index 43ba9eb11607c..da6ff2774a290 100644 --- a/e2e/webpack/src/webpack-setup.ts +++ b/e2e/webpack/src/webpack-setup.ts @@ -1,6 +1,6 @@ import { cleanupProject, newProject } from '@nx/e2e-utils'; -// Define a type that matches what newProject accepts for packages + type NxPackage = | '@nx/angular' | '@nx/cypress' From d1e4fa4ec02a50c4fb9cbfaddbcf870822ae12cf Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Thu, 16 Oct 2025 13:27:45 +0100 Subject: [PATCH 05/12] chore(repo): format files --- e2e/webpack/src/webpack-setup.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e/webpack/src/webpack-setup.ts b/e2e/webpack/src/webpack-setup.ts index da6ff2774a290..84cb6f5f773bb 100644 --- a/e2e/webpack/src/webpack-setup.ts +++ b/e2e/webpack/src/webpack-setup.ts @@ -1,6 +1,5 @@ import { cleanupProject, newProject } from '@nx/e2e-utils'; - type NxPackage = | '@nx/angular' | '@nx/cypress' From 02b9a15acf85555980222614369a978ca5aa5a82 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Thu, 16 Oct 2025 18:22:56 +0100 Subject: [PATCH 06/12] chore(repo): setup all packages in webpack tests --- e2e/webpack/src/webpack-app-plugin.test.ts | 2 +- e2e/webpack/src/webpack-assets.test.ts | 2 +- e2e/webpack/src/webpack-babel-corejs.test.ts | 2 +- e2e/webpack/src/webpack-babel-env.test.ts | 2 +- .../src/webpack-compose-plugins.test.ts | 2 +- e2e/webpack/src/webpack-config-array.test.ts | 2 +- .../src/webpack-config-function-array.test.ts | 2 +- .../src/webpack-config-function.test.ts | 2 +- .../webpack-config-standard-object.test.ts | 2 +- e2e/webpack/src/webpack-env-variables.test.ts | 2 +- .../src/webpack-executor-options.test.ts | 2 +- .../src/webpack-libs-from-source.test.ts | 2 +- .../src/webpack-node-compilers.test.ts | 2 +- e2e/webpack/src/webpack-setup.ts | 35 ++----------------- 14 files changed, 15 insertions(+), 46 deletions(-) diff --git a/e2e/webpack/src/webpack-app-plugin.test.ts b/e2e/webpack/src/webpack-app-plugin.test.ts index b0045adf59522..6569b23b7df1e 100644 --- a/e2e/webpack/src/webpack-app-plugin.test.ts +++ b/e2e/webpack/src/webpack-app-plugin.test.ts @@ -9,7 +9,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/web', '@nx/webpack']); + setupWebpackTest(); it('should be able to build with NxWebpackPlugin and a standard webpack config file', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-assets.test.ts b/e2e/webpack/src/webpack-assets.test.ts index 9c2ad782610ee..6a346778f538c 100644 --- a/e2e/webpack/src/webpack-assets.test.ts +++ b/e2e/webpack/src/webpack-assets.test.ts @@ -8,7 +8,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/web', '@nx/webpack']); + setupWebpackTest(); it('should resolve assets from executors as relative to workspace root', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-babel-corejs.test.ts b/e2e/webpack/src/webpack-babel-corejs.test.ts index f606ff90a8925..861b0374c5900 100644 --- a/e2e/webpack/src/webpack-babel-corejs.test.ts +++ b/e2e/webpack/src/webpack-babel-corejs.test.ts @@ -10,7 +10,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/web', '@nx/webpack']); + setupWebpackTest(); it('should support babel + core-js to polyfill JS features', async () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-babel-env.test.ts b/e2e/webpack/src/webpack-babel-env.test.ts index 9c7cf7e3373dd..7d94b363f9358 100644 --- a/e2e/webpack/src/webpack-babel-env.test.ts +++ b/e2e/webpack/src/webpack-babel-env.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/js', '@nx/webpack']); + setupWebpackTest(); it('should use either BABEL_ENV or NODE_ENV value for Babel environment configuration', async () => { const myPkg = uniq('my-pkg'); diff --git a/e2e/webpack/src/webpack-compose-plugins.test.ts b/e2e/webpack/src/webpack-compose-plugins.test.ts index 017bf390ab395..f892fd1944b14 100644 --- a/e2e/webpack/src/webpack-compose-plugins.test.ts +++ b/e2e/webpack/src/webpack-compose-plugins.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/web', '@nx/webpack']); + setupWebpackTest(); it('should be able to support webpack config with nx enhanced and babel', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-array.test.ts b/e2e/webpack/src/webpack-config-array.test.ts index 622916bff35a5..05caa69e8d470 100644 --- a/e2e/webpack/src/webpack-config-array.test.ts +++ b/e2e/webpack/src/webpack-config-array.test.ts @@ -8,7 +8,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(['@nx/react', '@nx/webpack']); + setupWebpackTest(); it('should support an array of standard config objects', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-function-array.test.ts b/e2e/webpack/src/webpack-config-function-array.test.ts index 19823844a8093..82ff3f6fd66ca 100644 --- a/e2e/webpack/src/webpack-config-function-array.test.ts +++ b/e2e/webpack/src/webpack-config-function-array.test.ts @@ -8,7 +8,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(['@nx/react', '@nx/webpack']); + setupWebpackTest(); it('should support a function that returns an array of standard config objects', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-function.test.ts b/e2e/webpack/src/webpack-config-function.test.ts index 0b5100f574f38..d86039b6bcd47 100644 --- a/e2e/webpack/src/webpack-config-function.test.ts +++ b/e2e/webpack/src/webpack-config-function.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(['@nx/react', '@nx/webpack']); + setupWebpackTest(); it('should support a standard function that returns a config object', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-config-standard-object.test.ts b/e2e/webpack/src/webpack-config-standard-object.test.ts index d6afc40e371cc..432c9d3482261 100644 --- a/e2e/webpack/src/webpack-config-standard-object.test.ts +++ b/e2e/webpack/src/webpack-config-standard-object.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('config types', () => { - setupWebpackTest(['@nx/react', '@nx/webpack']); + setupWebpackTest(); it('should support a standard config object', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-env-variables.test.ts b/e2e/webpack/src/webpack-env-variables.test.ts index c8ced7066c2e2..551181f63e02e 100644 --- a/e2e/webpack/src/webpack-env-variables.test.ts +++ b/e2e/webpack/src/webpack-env-variables.test.ts @@ -9,7 +9,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/web', '@nx/webpack']); + setupWebpackTest(); it('should bundle in NX_PUBLIC_ environment variables', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-executor-options.test.ts b/e2e/webpack/src/webpack-executor-options.test.ts index 9f984342eac9b..4c10fdbd85b2f 100644 --- a/e2e/webpack/src/webpack-executor-options.test.ts +++ b/e2e/webpack/src/webpack-executor-options.test.ts @@ -9,7 +9,7 @@ import { import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/web', '@nx/webpack']); + setupWebpackTest(); it('should allow options to be passed from the executor', async () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-libs-from-source.test.ts b/e2e/webpack/src/webpack-libs-from-source.test.ts index d2af3d6b4b467..ce757f653034f 100644 --- a/e2e/webpack/src/webpack-libs-from-source.test.ts +++ b/e2e/webpack/src/webpack-libs-from-source.test.ts @@ -2,7 +2,7 @@ import { runCLI, uniq, updateFile } from '@nx/e2e-utils'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/web', '@nx/js', '@nx/webpack']); + setupWebpackTest(); it('it should support building libraries and apps when buildLibsFromSource is false', () => { const appName = uniq('app'); diff --git a/e2e/webpack/src/webpack-node-compilers.test.ts b/e2e/webpack/src/webpack-node-compilers.test.ts index 20e9f9a3b7714..d256168310ed6 100644 --- a/e2e/webpack/src/webpack-node-compilers.test.ts +++ b/e2e/webpack/src/webpack-node-compilers.test.ts @@ -10,7 +10,7 @@ import { join } from 'path'; import { setupWebpackTest } from './webpack-setup'; describe('Webpack Plugin', () => { - setupWebpackTest(['@nx/js', '@nx/webpack']); + setupWebpackTest(); it('should be able to setup project to build node programs with webpack and different compilers', async () => { const myPkg = uniq('my-pkg'); diff --git a/e2e/webpack/src/webpack-setup.ts b/e2e/webpack/src/webpack-setup.ts index 84cb6f5f773bb..1ac7ebef980a2 100644 --- a/e2e/webpack/src/webpack-setup.ts +++ b/e2e/webpack/src/webpack-setup.ts @@ -1,37 +1,6 @@ import { cleanupProject, newProject } from '@nx/e2e-utils'; -type NxPackage = - | '@nx/angular' - | '@nx/cypress' - | '@nx/docker' - | '@nx/eslint-plugin' - | '@nx/express' - | '@nx/esbuild' - | '@nx/gradle' - | '@nx/jest' - | '@nx/js' - | '@nx/eslint' - | '@nx/nest' - | '@nx/next' - | '@nx/node' - | '@nx/nuxt' - | '@nx/plugin' - | '@nx/playwright' - | '@nx/rollup' - | '@nx/react' - | '@nx/remix' - | '@nx/rspack' - | '@nx/storybook' - | '@nx/vue' - | '@nx/vite' - | '@nx/web' - | '@nx/webpack' - | '@nx/react-native' - | '@nx/expo'; - -export function setupWebpackTest(packages?: readonly NxPackage[]) { - beforeAll(() => - newProject({ packages: packages as Array | undefined }) - ); +export function setupWebpackTest() { + beforeAll(() => newProject()); afterAll(() => cleanupProject()); } From 18553f6606d6c5076f17375cef675db3d379bb5c Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Fri, 17 Oct 2025 13:56:43 +0100 Subject: [PATCH 07/12] chore(repo): bust cache --- nx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nx.json b/nx.json index 0c6ca02ce7bf2..82f3fa185cac4 100644 --- a/nx.json +++ b/nx.json @@ -330,7 +330,7 @@ } ], "parallel": 1, - "bust": 3, + "bust": 4, "defaultBase": "master", "sync": { "applyChanges": true From a63df819f71db7bd403fb9acc883248a3fe19398 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Fri, 17 Oct 2025 16:25:01 +0100 Subject: [PATCH 08/12] chore(repo): run conflicting tests serially --- .nx/workflows/dynamic-changesets.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.nx/workflows/dynamic-changesets.yaml b/.nx/workflows/dynamic-changesets.yaml index 8580c122f8c9c..108cad2469aa7 100644 --- a/.nx/workflows/dynamic-changesets.yaml +++ b/.nx/workflows/dynamic-changesets.yaml @@ -25,6 +25,8 @@ assignment-rules: - e2e-next - e2e-web - e2e-eslint + - e2e-remix + - e2e-cypress targets: - e2e-ci**react-package** - e2e-ci**react.test** @@ -36,6 +38,10 @@ assignment-rules: - e2e-ci**web** - e2e-ci**remix-ts-solution** - e2e-ci**linter** + - e2e-ci**module-federation/misc-rspack-interoperability** + - e2e-ci**cypress-legacy** + - e2e-ci**nx-remix** + - e2e-ci**cypress** run-on: - agent: linux-large parallelism: 1 From 866f0e21e457e124d7556c45ae1bef5ca780de16 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Fri, 17 Oct 2025 16:52:30 +0100 Subject: [PATCH 09/12] chore(repo): run conflicting tests serially --- .nx/workflows/dynamic-changesets.yaml | 4 ++++ nx.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.nx/workflows/dynamic-changesets.yaml b/.nx/workflows/dynamic-changesets.yaml index 108cad2469aa7..c4f0da65fe4a9 100644 --- a/.nx/workflows/dynamic-changesets.yaml +++ b/.nx/workflows/dynamic-changesets.yaml @@ -27,6 +27,7 @@ assignment-rules: - e2e-eslint - e2e-remix - e2e-cypress + - e2e-docker targets: - e2e-ci**react-package** - e2e-ci**react.test** @@ -39,6 +40,9 @@ assignment-rules: - e2e-ci**remix-ts-solution** - e2e-ci**linter** - e2e-ci**module-federation/misc-rspack-interoperability** + - e2e-ci**module-federation/dynamic-federation.webpack** + - e2e-ci**docker** + - e2e-ci**module-federation/misc-rspack-interoperability** - e2e-ci**cypress-legacy** - e2e-ci**nx-remix** - e2e-ci**cypress** diff --git a/nx.json b/nx.json index 82f3fa185cac4..65ac12ca68b14 100644 --- a/nx.json +++ b/nx.json @@ -330,7 +330,7 @@ } ], "parallel": 1, - "bust": 4, + "bust": 5, "defaultBase": "master", "sync": { "applyChanges": true From 0613153996c02c67793d9d7ef50dbf777bfbdfa0 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Fri, 17 Oct 2025 17:00:31 +0100 Subject: [PATCH 10/12] chore(repo): run conflicting tests serially --- nx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nx.json b/nx.json index 65ac12ca68b14..f7ce4fdc832e9 100644 --- a/nx.json +++ b/nx.json @@ -330,7 +330,7 @@ } ], "parallel": 1, - "bust": 5, + "bust": 6, "defaultBase": "master", "sync": { "applyChanges": true From cbf5d756a424f4494a8a218ff207af5ab695eaca Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Fri, 17 Oct 2025 22:54:17 +0100 Subject: [PATCH 11/12] chore(repo): switch all e2e tests to run serially --- .nx/workflows/dynamic-changesets.yaml | 18 +----------------- nx.json | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/.nx/workflows/dynamic-changesets.yaml b/.nx/workflows/dynamic-changesets.yaml index c4f0da65fe4a9..7e93d24e912e2 100644 --- a/.nx/workflows/dynamic-changesets.yaml +++ b/.nx/workflows/dynamic-changesets.yaml @@ -29,23 +29,7 @@ assignment-rules: - e2e-cypress - e2e-docker targets: - - e2e-ci**react-package** - - e2e-ci**react.test** - - e2e-ci**react-router-ts-solution** - - e2e-ci**next-e2e-and-snapshots** - - e2e-ci**next-generation** - - e2e-ci**next-ts-solutions** - - e2e-ci**next-webpack** - - e2e-ci**web** - - e2e-ci**remix-ts-solution** - - e2e-ci**linter** - - e2e-ci**module-federation/misc-rspack-interoperability** - - e2e-ci**module-federation/dynamic-federation.webpack** - - e2e-ci**docker** - - e2e-ci**module-federation/misc-rspack-interoperability** - - e2e-ci**cypress-legacy** - - e2e-ci**nx-remix** - - e2e-ci**cypress** + - e2e-ci** run-on: - agent: linux-large parallelism: 1 diff --git a/nx.json b/nx.json index f7ce4fdc832e9..f7f2298df0769 100644 --- a/nx.json +++ b/nx.json @@ -330,7 +330,7 @@ } ], "parallel": 1, - "bust": 6, + "bust": 12, "defaultBase": "master", "sync": { "applyChanges": true From d5ca2685525af91b770233a3b56534d1fef86e91 Mon Sep 17 00:00:00 2001 From: Rares Matei Date: Tue, 21 Oct 2025 14:23:41 +0100 Subject: [PATCH 12/12] chore(repo): fix env contents --- e2e/web/src/web-html-interpolation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/web/src/web-html-interpolation.test.ts b/e2e/web/src/web-html-interpolation.test.ts index c4dc054cf4b1d..0b045f4e9b652 100644 --- a/e2e/web/src/web-html-interpolation.test.ts +++ b/e2e/web/src/web-html-interpolation.test.ts @@ -33,7 +33,7 @@ describe('index.html interpolation', () => { const envFileContents = ` NX_PUBLIC_VARIABLE=foo SOME_OTHER_VARIABLE=bar - }`; + `; createFile(envFilePath);