From 85aee88f864908d614e4e05f0f59e3130a06389a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Fri, 17 Mar 2023 11:21:17 +0000 Subject: [PATCH] cleanup(angular): speed up e2e-angular-core tests --- e2e/angular-core/src/angular-linting.test.ts | 112 ++++----- .../src/module-federation.test.ts | 227 ++++++------------ e2e/angular-core/src/ng-add.test.ts | 67 ++---- e2e/angular-core/src/ng-cli.test.ts | 12 +- e2e/angular-core/src/projects.test.ts | 15 +- e2e/utils/process-utils.ts | 16 ++ 6 files changed, 161 insertions(+), 288 deletions(-) diff --git a/e2e/angular-core/src/angular-linting.test.ts b/e2e/angular-core/src/angular-linting.test.ts index 4e91baf76a568f..215ef02cc6cfcc 100644 --- a/e2e/angular-core/src/angular-linting.test.ts +++ b/e2e/angular-core/src/angular-linting.test.ts @@ -7,73 +7,63 @@ import { } from '@nrwl/e2e/utils'; import * as path from 'path'; -describe('Angular Package', () => { - describe('linting', () => { - beforeAll(() => newProject()); - afterAll(() => cleanupProject()); +describe('linting', () => { + beforeAll(() => newProject()); + afterAll(() => cleanupProject()); - it('should support eslint and pass linting on the standard generated code', async () => { - const myapp = uniq('myapp'); - runCLI( - `generate @nrwl/angular:app ${myapp} --linter=eslint --no-interactive` - ); - expect(runCLI(`lint ${myapp}`)).toContain('All files pass linting.'); + it('should lint correctly with eslint and handle external HTML files and inline templates', async () => { + const app = uniq('app'); + const lib = uniq('lib'); - const mylib = uniq('mylib'); - runCLI( - `generate @nrwl/angular:lib ${mylib} --linter=eslint --no-interactive` - ); - expect(runCLI(`lint ${mylib}`)).toContain('All files pass linting.'); - }); + runCLI( + `generate @nrwl/angular:app ${app} --linter=eslint --no-interactive` + ); + runCLI( + `generate @nrwl/angular:lib ${lib} --linter=eslint --no-interactive` + ); - it('should support eslint and successfully lint external HTML files and inline templates', async () => { - const myapp = uniq('myapp'); + // check app and lib pass linting for initial generated code + expect(runCLI(`lint ${app}`)).toContain('All files pass linting.'); + expect(runCLI(`lint ${lib}`)).toContain('All files pass linting.'); - runCLI( - `generate @nrwl/angular:app ${myapp} --linter=eslint --no-interactive` - ); + // External HTML template file + const templateWhichFailsBananaInBoxLintCheck = `
`; + updateFile( + `apps/${app}/src/app/app.component.html`, + templateWhichFailsBananaInBoxLintCheck + ); + // Inline template within component.ts file + const wrappedAsInlineTemplate = ` + import { Component } from '@angular/core'; - const templateWhichFailsBananaInBoxLintCheck = `
`; - const wrappedAsInlineTemplate = ` - import { Component } from '@angular/core'; + @Component({ + selector: 'inline-template-component', + template: \` + ${templateWhichFailsBananaInBoxLintCheck} + \`, + }) + export class InlineTemplateComponent {} + `; + updateFile( + `apps/${app}/src/app/inline-template.component.ts`, + wrappedAsInlineTemplate + ); - @Component({ - selector: 'inline-template-component', - template: \` - ${templateWhichFailsBananaInBoxLintCheck} - \`, - }) - export class InlineTemplateComponent {} - `; + const appLintStdOut = runCLI(`lint ${app}`, { silenceError: true }); + expect(appLintStdOut).toContain( + path.normalize(`apps/${app}/src/app/app.component.html`) + ); + expect(appLintStdOut).toContain(`1:6`); + expect(appLintStdOut).toContain(`Invalid binding syntax`); + expect(appLintStdOut).toContain( + path.normalize(`apps/${app}/src/app/inline-template.component.ts`) + ); - // External HTML template file - updateFile( - `apps/${myapp}/src/app/app.component.html`, - templateWhichFailsBananaInBoxLintCheck - ); - - // Inline template within component.ts file - updateFile( - `apps/${myapp}/src/app/inline-template.component.ts`, - wrappedAsInlineTemplate - ); - - const appLintStdOut = runCLI(`lint ${myapp}`, { silenceError: true }); - expect(appLintStdOut).toContain( - path.normalize(`apps/${myapp}/src/app/app.component.html`) - ); - expect(appLintStdOut).toContain(`1:6`); - expect(appLintStdOut).toContain(`Invalid binding syntax`); - expect(appLintStdOut).toContain( - path.normalize(`apps/${myapp}/src/app/inline-template.component.ts`) - ); - - expect(appLintStdOut).toContain(`5:21`); - expect(appLintStdOut).toContain( - `The selector should start with one of these prefixes` - ); - expect(appLintStdOut).toContain(`7:18`); - expect(appLintStdOut).toContain(`Invalid binding syntax`); - }); + expect(appLintStdOut).toContain(`5:19`); + expect(appLintStdOut).toContain( + `The selector should start with one of these prefixes` + ); + expect(appLintStdOut).toContain(`7:16`); + expect(appLintStdOut).toContain(`Invalid binding syntax`); }); }); diff --git a/e2e/angular-core/src/module-federation.test.ts b/e2e/angular-core/src/module-federation.test.ts index b9765f8ba1ac6d..29d028dab4cfd4 100644 --- a/e2e/angular-core/src/module-federation.test.ts +++ b/e2e/angular-core/src/module-federation.test.ts @@ -1,61 +1,58 @@ +import { names } from '@nrwl/devkit'; import { cleanupProject, - killPort, + killProcessAndPorts, newProject, - promisifiedTreeKill, readProjectConfig, runCLI, runCommandUntil, uniq, updateFile, - updateProjectConfig, } from '@nrwl/e2e/utils'; -import { ChildProcess } from 'child_process'; - -import { names } from '@nrwl/devkit'; -describe('Angular Projects', () => { +describe('Angular Module Federation', () => { let proj: string; - let oldValue; + let oldVerboseLoggingValue: string; beforeAll(() => { proj = newProject(); - oldValue = process.env.NX_E2E_VERBOSE_LOGGING; + oldVerboseLoggingValue = process.env.NX_E2E_VERBOSE_LOGGING; process.env.NX_E2E_VERBOSE_LOGGING = 'true'; }); afterAll(() => { cleanupProject(); - process.env.NX_E2E_VERBOSE_LOGGING = oldValue; + process.env.NX_E2E_VERBOSE_LOGGING = oldVerboseLoggingValue; }); - it('should serve the host and remote apps successfully, even with a shared library with a secondary entry point between them', async () => { - // ACT + ASSERT - const port1 = 4200; - const port2 = 4206; + it('should generate valid host and remote apps', async () => { const hostApp = uniq('app'); const remoteApp1 = uniq('remote'); const sharedLib = uniq('shared-lib'); const secondaryEntry = uniq('secondary'); + const hostPort = 4300; + const remotePort = 4301; // generate host app runCLI( `generate @nrwl/angular:host ${hostApp} --style=css --no-interactive` ); - - // generate remote apps + // generate remote app runCLI( - `generate @nrwl/angular:remote ${remoteApp1} --host=${hostApp} --port=${port2} --style=css --no-interactive` + `generate @nrwl/angular:remote ${remoteApp1} --host=${hostApp} --port=${remotePort} --style=css --no-interactive` ); - // generate a shared lib + // check default generated host is built successfully + const buildOutput = runCLI(`build ${hostApp}`); + expect(buildOutput).toContain('Successfully ran target build'); + + // generate a shared lib with a seconary entry point runCLI( `generate @nrwl/angular:library ${sharedLib} --buildable --no-interactive` ); runCLI( `generate @nrwl/angular:library-secondary-entry-point --library=${sharedLib} --name=${secondaryEntry} --no-interactive` ); - - // update the files to use shared library + // update host & remote files to use shared library updateFile( `apps/${hostApp}/src/app/app.module.ts`, `import { NgModule } from '@angular/core'; @@ -123,168 +120,78 @@ describe('Angular Projects', () => { ` ); - let process: ChildProcess; - - try { - process = await runCommandUntil( - `serve ${hostApp} --dev-remotes=${remoteApp1}`, - (output) => { - return ( - output.includes(`listening on localhost:${port2}`) && - output.includes(`listening on localhost:${port1}`) - ); - } - ); - } catch (err) { - console.error(err); - } + const process = await runCommandUntil( + `serve ${hostApp} --port=${hostPort} --dev-remotes=${remoteApp1}`, + (output) => + output.includes(`listening on localhost:${remotePort}`) && + output.includes(`listening on localhost:${hostPort}`) + ); // port and process cleanup - try { - if (process && process.pid) { - await promisifiedTreeKill(process.pid, 'SIGKILL'); - } - await killPort(port1); - await killPort(port2); - } catch (err) { - expect(err).toBeFalsy(); - } + await killProcessAndPorts(process.pid, hostPort, remotePort); }, 300000); - it('should build the host app successfully', async () => { - // ARRANGE - const hostApp = uniq('app'); - const remoteApp1 = uniq('remote'); - - // generate host app - runCLI(`generate @nrwl/angular:host ${hostApp} --no-interactive`); + it('should convert apps to MF successfully', async () => { + const app1 = uniq('app1'); + const app2 = uniq('app2'); + const app1Port = 4400; + const app2Port = 4401; - // generate remote apps + // generate apps runCLI( - `generate @nrwl/angular:remote ${remoteApp1} --host=${hostApp} --no-interactive` + `generate @nrwl/angular:application ${app1} --routing --no-interactive` ); + runCLI(`generate @nrwl/angular:application ${app2} --no-interactive`); - // ACT - const buildOutput = runCLI(`build ${hostApp}`); - - // ASSERT - expect(buildOutput).toContain('Successfully ran target build'); - }, 300000); - - it('should serve a ssr remote app successfully', async () => { - // ARRANGE - const remoteApp1 = uniq('remote'); - // generate remote apps + // convert apps runCLI( - `generate @nrwl/angular:remote ${remoteApp1} --ssr --no-interactive` + `generate @nrwl/angular:setup-mf ${app1} --mfType=host --port=${app1Port} --no-interactive` + ); + runCLI( + `generate @nrwl/angular:setup-mf ${app2} --mfType=remote --host=${app1} --port=${app2Port} --no-interactive` ); - const port = 4301; - - let process = await runCommandUntil( - `serve-ssr ${remoteApp1} --port=${port}`, - (output) => { - return ( - output.includes(`Browser application bundle generation complete.`) && - output.includes(`Server application bundle generation complete.`) && - output.includes( - `Angular Universal Live Development Server is listening` - ) - ); - } + const process = await runCommandUntil( + `serve ${app1} --dev-remotes=${app2}`, + (output) => + output.includes(`listening on localhost:${app1Port}`) && + output.includes(`listening on localhost:${app2Port}`) ); // port and process cleanup - try { - if (process && process.pid) { - await promisifiedTreeKill(process.pid, 'SIGKILL'); - } - await killPort(port); - } catch (err) { - expect(err).toBeFalsy(); - } - }, 10_000_000); + await killProcessAndPorts(process.pid, app1Port, app2Port); + }, 20_000_000); + + it('should scaffold MF + SSR setup successfully', async () => { + const host = uniq('host'); + const remote1 = uniq('remote1'); + const remote2 = uniq('remote2'); - it('should scaffold a ssr MF setup successfully', async () => { - // ARRANGE - const remoteApp1 = uniq('remote1'); - const remoteApp2 = uniq('remote2'); - const hostApp = uniq('host1'); // generate remote apps runCLI( - `generate @nrwl/angular:host ${hostApp} --ssr --remotes=${remoteApp1},${remoteApp2} --no-interactive` + `generate @nrwl/angular:host ${host} --ssr --remotes=${remote1},${remote2} --no-interactive` ); // ports - const remoteApp1Port = - readProjectConfig(remoteApp1).targets.serve.options.port; - const remoteApp2Port = - readProjectConfig(remoteApp2).targets.serve.options.port; - - const port = 4401; - - let process = await runCommandUntil( - `serve-ssr ${hostApp} --port=${port}`, - (output) => { - return ( - output.includes( - `Node Express server listening on http://localhost:${remoteApp1Port}` - ) && - output.includes( - `Node Express server listening on http://localhost:${remoteApp2Port}` - ) && - output.includes( - `Angular Universal Live Development Server is listening` - ) - ); - } + const hostPort = 4500; + const remote1Port = readProjectConfig(remote1).targets.serve.options.port; + const remote2Port = readProjectConfig(remote2).targets.serve.options.port; + + const process = await runCommandUntil( + `serve-ssr ${host} --port=${hostPort}`, + (output) => + output.includes( + `Node Express server listening on http://localhost:${remote1Port}` + ) && + output.includes( + `Node Express server listening on http://localhost:${remote2Port}` + ) && + output.includes( + `Angular Universal Live Development Server is listening` + ) ); // port and process cleanup - try { - if (process && process.pid) { - await promisifiedTreeKill(process.pid, 'SIGKILL'); - } - await killPort(port); - await killPort(remoteApp1Port); - await killPort(remoteApp2Port); - } catch (err) { - expect(err).toBeFalsy(); - } + await killProcessAndPorts(process.pid, hostPort, remote1Port, remote2Port); }, 20_000_000); - - it('Custom Webpack Config for SSR - should serve the app correctly', async () => { - // ARRANGE - const ssrApp = uniq('app'); - - runCLI(`generate @nrwl/angular:app ${ssrApp} --no-interactive`); - runCLI(`generate @nrwl/angular:setup-ssr ${ssrApp} --no-interactive`); - - updateProjectConfig(ssrApp, (project) => { - project.targets.server.executor = '@nrwl/angular:webpack-server'; - return project; - }); - - const port = 4501; - - // ACT - let process = await runCommandUntil( - `serve-ssr ${ssrApp} --port=${port}`, - (output) => { - return output.includes( - `Angular Universal Live Development Server is listening on http://localhost:${port}` - ); - } - ); - - // port and process cleanup - try { - if (process && process.pid) { - await promisifiedTreeKill(process.pid, 'SIGKILL'); - } - await killPort(port); - } catch (err) { - expect(err).toBeFalsy(); - } - }, 300000); }); diff --git a/e2e/angular-core/src/ng-add.test.ts b/e2e/angular-core/src/ng-add.test.ts index 239045c7129004..129067eb7ce8ed 100644 --- a/e2e/angular-core/src/ng-add.test.ts +++ b/e2e/angular-core/src/ng-add.test.ts @@ -436,55 +436,12 @@ describe('convert Angular CLI workspace to an Nx workspace', () => { ); }); - it('should support a workspace with multiple libraries', () => { - // add some libraries - const lib1 = uniq('lib1'); - const lib2 = uniq('lib2'); - runCommand(`ng g @schematics/angular:library ${lib1}`); - runCommand(`ng g @schematics/angular:library ${lib2}`); - - runNgAdd('@nrwl/angular', '--npm-scope projscope'); - - // check angular.json does not exist - checkFilesDoNotExist('angular.json'); - - // check building lib1 - let output = runCLI(`build ${lib1}`); - expect(output).toContain(`> nx run ${lib1}:build:production`); - expect(output).toContain( - `Successfully ran target build for project ${lib1}` - ); - checkFilesExist(`dist/${lib1}/package.json`); - - output = runCLI(`build ${lib1}`); - expect(output).toContain( - `> nx run ${lib1}:build:production [local cache]` - ); - expect(output).toContain( - `Successfully ran target build for project ${lib1}` - ); - - // check building lib2 - output = runCLI(`build ${lib2}`); - expect(output).toContain(`> nx run ${lib2}:build:production`); - expect(output).toContain( - `Successfully ran target build for project ${lib2}` - ); - checkFilesExist(`dist/${lib2}/package.json`); - - output = runCLI(`build ${lib2}`); - expect(output).toContain( - `> nx run ${lib2}:build:production [local cache]` - ); - expect(output).toContain( - `Successfully ran target build for project ${lib2}` - ); - }); - - it('should support a workspace with multiple applications', () => { - // add another app + it('should support a workspace with multiple projects', () => { + // add other projects const app1 = uniq('app1'); + const lib1 = uniq('lib1'); runCommand(`ng g @schematics/angular:application ${app1}`); + runCommand(`ng g @schematics/angular:library ${lib1}`); runNgAdd('@nrwl/angular', '--npm-scope projscope'); @@ -526,5 +483,21 @@ describe('convert Angular CLI workspace to an Nx workspace', () => { expect(output).toContain( `Successfully ran target build for project ${app1}` ); + + // check building lib1 + output = runCLI(`build ${lib1}`); + expect(output).toContain(`> nx run ${lib1}:build:production`); + expect(output).toContain( + `Successfully ran target build for project ${lib1}` + ); + checkFilesExist(`dist/${lib1}/package.json`); + + output = runCLI(`build ${lib1}`); + expect(output).toContain( + `> nx run ${lib1}:build:production [local cache]` + ); + expect(output).toContain( + `Successfully ran target build for project ${lib1}` + ); }); }); diff --git a/e2e/angular-core/src/ng-cli.test.ts b/e2e/angular-core/src/ng-cli.test.ts index 7ece5d77376a71..f77ff996d0f3cb 100644 --- a/e2e/angular-core/src/ng-cli.test.ts +++ b/e2e/angular-core/src/ng-cli.test.ts @@ -1,17 +1,15 @@ -import * as isCI from 'is-ci'; import { checkFilesExist, + cleanupProject, getSelectedPackageManager, packageInstall, readJson, runCommand, runNgNew, - tmpProjPath, uniq, updateFile, } from '@nrwl/e2e/utils'; import { PackageManager } from 'nx/src/utils/package-manager'; -import { removeSync } from 'fs-extra'; describe('using Nx executors and generators with Angular CLI', () => { let project: string; @@ -23,13 +21,7 @@ describe('using Nx executors and generators with Angular CLI', () => { runNgNew(project, packageManager); }); - afterEach(() => { - if (isCI) { - try { - removeSync(tmpProjPath()); - } catch (e) {} - } - }); + afterEach(() => cleanupProject({ skipReset: true })); it('should convert Nx executors into Angular CLI compatible builders', () => { packageInstall('@nrwl/angular'); diff --git a/e2e/angular-core/src/projects.test.ts b/e2e/angular-core/src/projects.test.ts index 1ded053b620cf0..1488a16e9cbc72 100644 --- a/e2e/angular-core/src/projects.test.ts +++ b/e2e/angular-core/src/projects.test.ts @@ -1,10 +1,11 @@ +import { names } from '@nrwl/devkit'; import { checkFilesExist, cleanupProject, getSize, killPorts, + killProcessAndPorts, newProject, - promisifiedTreeKill, readFile, runCLI, runCommandUntil, @@ -15,8 +16,6 @@ import { updateProjectConfig, } from '@nrwl/e2e/utils'; -import { names } from '@nrwl/devkit'; - describe('Angular Projects', () => { let proj: string; @@ -82,18 +81,14 @@ describe('Angular Projects', () => { expect(await killPorts()).toBeTruthy(); } + const appPort = 4207; const process = await runCommandUntil( - `serve my-dir-${myapp} -- --port=4207`, + `serve my-dir-${myapp} -- --port=${appPort}`, (output) => output.includes(`listening on localhost:4207`) ); // port and process cleanup - try { - await promisifiedTreeKill(process.pid, 'SIGKILL'); - await killPorts(4207); - } catch (err) { - expect(err).toBeFalsy(); - } + killProcessAndPorts(process.pid, appPort); }, 1000000); it('should build the dependent buildable lib and its child lib, as well as the app', async () => { diff --git a/e2e/utils/process-utils.ts b/e2e/utils/process-utils.ts index 672d9d459822b0..e17997c0a51736 100644 --- a/e2e/utils/process-utils.ts +++ b/e2e/utils/process-utils.ts @@ -39,3 +39,19 @@ export async function killPorts(port?: number): Promise { ? await killPort(port) : (await killPort(3333)) && (await killPort(4200)); } + +export async function killProcessAndPorts( + pid: number | undefined, + ...ports: number[] +): Promise { + try { + if (pid) { + await promisifiedTreeKill(pid, 'SIGKILL'); + } + for (const port of ports) { + await killPort(port); + } + } catch (err) { + expect(err).toBeFalsy(); + } +}