fix(angular): fix e2e tests to support pnpm v7 (#15587)

This commit is contained in:
Miroslav Jonaš 2023-03-16 12:22:22 +01:00 committed by GitHub
parent 10a69b7d0f
commit c6904619aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 153 additions and 80 deletions

View File

@ -1,5 +1,6 @@
import { import {
cleanupProject, cleanupProject,
killPort,
newProject, newProject,
promisifiedTreeKill, promisifiedTreeKill,
readProjectConfig, readProjectConfig,
@ -15,9 +16,17 @@ import { names } from '@nrwl/devkit';
describe('Angular Projects', () => { describe('Angular Projects', () => {
let proj: string; let proj: string;
let oldValue;
beforeAll(() => (proj = newProject())); beforeAll(() => {
afterAll(() => cleanupProject()); proj = newProject();
oldValue = process.env.NX_E2E_VERBOSE_LOGGING;
process.env.NX_E2E_VERBOSE_LOGGING = 'true';
});
afterAll(() => {
cleanupProject();
process.env.NX_E2E_VERBOSE_LOGGING = oldValue;
});
it('should serve the host and remote apps successfully, even with a shared library with a secondary entry point between them', async () => { it('should serve the host and remote apps successfully, even with a shared library with a secondary entry point between them', async () => {
// ACT + ASSERT // ACT + ASSERT
@ -135,6 +144,8 @@ describe('Angular Projects', () => {
if (process && process.pid) { if (process && process.pid) {
await promisifiedTreeKill(process.pid, 'SIGKILL'); await promisifiedTreeKill(process.pid, 'SIGKILL');
} }
await killPort(port1);
await killPort(port2);
} catch (err) { } catch (err) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
} }
@ -168,7 +179,11 @@ describe('Angular Projects', () => {
`generate @nrwl/angular:remote ${remoteApp1} --ssr --no-interactive` `generate @nrwl/angular:remote ${remoteApp1} --ssr --no-interactive`
); );
let process = await runCommandUntil(`serve-ssr ${remoteApp1}`, (output) => { const port = 4301;
let process = await runCommandUntil(
`serve-ssr ${remoteApp1} --port=${port}`,
(output) => {
return ( return (
output.includes(`Browser application bundle generation complete.`) && output.includes(`Browser application bundle generation complete.`) &&
output.includes(`Server application bundle generation complete.`) && output.includes(`Server application bundle generation complete.`) &&
@ -176,13 +191,15 @@ describe('Angular Projects', () => {
`Angular Universal Live Development Server is listening` `Angular Universal Live Development Server is listening`
) )
); );
}); }
);
// port and process cleanup // port and process cleanup
try { try {
if (process && process.pid) { if (process && process.pid) {
await promisifiedTreeKill(process.pid, 'SIGKILL'); await promisifiedTreeKill(process.pid, 'SIGKILL');
} }
await killPort(port);
} catch (err) { } catch (err) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
} }
@ -204,7 +221,11 @@ describe('Angular Projects', () => {
const remoteApp2Port = const remoteApp2Port =
readProjectConfig(remoteApp2).targets.serve.options.port; readProjectConfig(remoteApp2).targets.serve.options.port;
let process = await runCommandUntil(`serve-ssr ${hostApp}`, (output) => { const port = 4401;
let process = await runCommandUntil(
`serve-ssr ${hostApp} --port=${port}`,
(output) => {
return ( return (
output.includes( output.includes(
`Node Express server listening on http://localhost:${remoteApp1Port}` `Node Express server listening on http://localhost:${remoteApp1Port}`
@ -216,13 +237,17 @@ describe('Angular Projects', () => {
`Angular Universal Live Development Server is listening` `Angular Universal Live Development Server is listening`
) )
); );
}); }
);
// port and process cleanup // port and process cleanup
try { try {
if (process && process.pid) { if (process && process.pid) {
await promisifiedTreeKill(process.pid, 'SIGKILL'); await promisifiedTreeKill(process.pid, 'SIGKILL');
} }
await killPort(port);
await killPort(remoteApp1Port);
await killPort(remoteApp2Port);
} catch (err) { } catch (err) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
} }
@ -240,18 +265,24 @@ describe('Angular Projects', () => {
return project; return project;
}); });
const port = 4501;
// ACT // ACT
let process = await runCommandUntil(`serve-ssr ${ssrApp}`, (output) => { let process = await runCommandUntil(
`serve-ssr ${ssrApp} --port=${port}`,
(output) => {
return output.includes( return output.includes(
`Angular Universal Live Development Server is listening on http://localhost:4200` `Angular Universal Live Development Server is listening on http://localhost:${port}`
);
}
); );
});
// port and process cleanup // port and process cleanup
try { try {
if (process && process.pid) { if (process && process.pid) {
await promisifiedTreeKill(process.pid, 'SIGKILL'); await promisifiedTreeKill(process.pid, 'SIGKILL');
} }
await killPort(port);
} catch (err) { } catch (err) {
expect(err).toBeFalsy(); expect(err).toBeFalsy();
} }

View File

@ -11,13 +11,10 @@ import {
import { TargetConfiguration } from '@nrwl/devkit'; import { TargetConfiguration } from '@nrwl/devkit';
import { ChildProcess, exec, execSync, ExecSyncOptions } from 'child_process'; import { ChildProcess, exec, execSync, ExecSyncOptions } from 'child_process';
import { join } from 'path'; import { join } from 'path';
import { check as portCheck } from 'tcp-port-used';
import * as isCI from 'is-ci'; import * as isCI from 'is-ci';
import { Workspaces } from '../../packages/nx/src/config/workspaces'; import { Workspaces } from '../../packages/nx/src/config/workspaces';
import { updateFile } from './file-utils'; import { updateFile } from './file-utils';
import { logError, logInfo, logSuccess, stripConsoleColors } from './log-utils'; import { logError, stripConsoleColors } from './log-utils';
export const kill = require('kill-port');
export interface RunCmdOpts { export interface RunCmdOpts {
silenceError?: boolean; silenceError?: boolean;
@ -243,6 +240,15 @@ export function runCommandUntil(
p.stderr?.on('data', checkCriteria); p.stderr?.on('data', checkCriteria);
p.on('exit', (code) => { p.on('exit', (code) => {
if (!complete) { if (!complete) {
if (isVerboseE2ERun()) {
logError(
`Original output:`,
output
.split('\n')
.map((l) => ` ${l}`)
.join('\n')
);
}
rej(`Exited with ${code}`); rej(`Exited with ${code}`);
} else { } else {
res(p); res(p);
@ -398,37 +404,6 @@ export function runLernaCLI(
} }
} }
const KILL_PORT_DELAY = 5000;
export async function killPort(port: number): Promise<boolean> {
if (await portCheck(port)) {
try {
logInfo(`Attempting to close port ${port}`);
await kill(port);
await new Promise<void>((resolve) =>
setTimeout(() => resolve(), KILL_PORT_DELAY)
);
if (await portCheck(port)) {
logError(`Port ${port} still open`);
} else {
logSuccess(`Port ${port} successfully closed`);
return true;
}
} catch {
logError(`Port ${port} closing failed`);
}
return false;
} else {
return true;
}
}
export async function killPorts(port?: number): Promise<boolean> {
return port
? await killPort(port)
: (await killPort(3333)) && (await killPort(4200));
}
export function waitUntil( export function waitUntil(
predicate: () => boolean, predicate: () => boolean,
opts: { timeout: number; ms: number; allowError?: boolean } = { opts: { timeout: number; ms: number; allowError?: boolean } = {

View File

@ -81,7 +81,7 @@ export function newProject({
packageInstall(packages.join(` `), projScope); packageInstall(packages.join(` `), projScope);
// stop the daemon // stop the daemon
execSync('nx reset', { execSync(`${getPackageManagerCommand().runNx} reset`, {
cwd: `${e2eCwd}/proj`, cwd: `${e2eCwd}/proj`,
stdio: isVerbose() ? 'inherit' : 'pipe', stdio: isVerbose() ? 'inherit' : 'pipe',
}); });
@ -94,6 +94,14 @@ export function newProject({
if (isVerbose()) { if (isVerbose()) {
logInfo(`NX`, `E2E created a project: ${tmpProjPath()}`); logInfo(`NX`, `E2E created a project: ${tmpProjPath()}`);
} }
if (packageManager === 'pnpm') {
execSync(getPackageManagerCommand().install, {
cwd: tmpProjPath(),
stdio: 'pipe',
env: { CI: 'true', ...process.env },
encoding: 'utf-8',
});
}
return projScope; return projScope;
} catch (e) { } catch (e) {
logError(`Failed to set up project for e2e tests.`, e.message); logError(`Failed to set up project for e2e tests.`, e.message);
@ -101,6 +109,14 @@ export function newProject({
} }
} }
// pnpm v7 sadly doesn't automatically install peer dependencies
export function addPnpmRc() {
updateFile(
'.npmrc',
'strict-peer-dependencies=false\nauto-install-peers=true'
);
}
export function runCreateWorkspace( export function runCreateWorkspace(
name: string, name: string,
{ {

View File

@ -12,8 +12,6 @@ import {
import * as path from 'path'; import * as path from 'path';
import { e2eCwd } from './get-env-info'; import { e2eCwd } from './get-env-info';
import { tmpProjPath } from './create-project-utils'; import { tmpProjPath } from './create-project-utils';
import { promisify } from 'util';
import * as treeKill from 'tree-kill';
export function createFile(f: string, content: string = ''): void { export function createFile(f: string, content: string = ''): void {
const path = tmpProjPath(f); const path = tmpProjPath(f);
@ -121,8 +119,3 @@ export function getSize(filePath: string): number {
export function tmpBackupProjPath(path?: string) { export function tmpBackupProjPath(path?: string) {
return path ? `${e2eCwd}/proj-backup/${path}` : `${e2eCwd}/proj-backup`; return path ? `${e2eCwd}/proj-backup/${path}` : `${e2eCwd}/proj-backup`;
} }
export const promisifiedTreeKill: (
pid: number,
signal: string
) => Promise<void> = promisify(treeKill);

View File

@ -10,3 +10,4 @@ export * from './get-env-info';
export * from './log-utils'; export * from './log-utils';
export * from './project-config-utils'; export * from './project-config-utils';
export * from './test-utils'; export * from './test-utils';
export * from './process-utils';

View File

@ -0,0 +1,41 @@
import { promisify } from 'util';
import * as treeKill from 'tree-kill';
import { logError, logInfo, logSuccess } from './log-utils';
import { check as portCheck } from 'tcp-port-used';
export const kill = require('kill-port');
const KILL_PORT_DELAY = 5000;
export const promisifiedTreeKill: (
pid: number,
signal: string
) => Promise<void> = promisify(treeKill);
export async function killPort(port: number): Promise<boolean> {
if (await portCheck(port)) {
try {
logInfo(`Attempting to close port ${port}`);
await kill(port);
await new Promise<void>((resolve) =>
setTimeout(() => resolve(), KILL_PORT_DELAY)
);
if (await portCheck(port)) {
logError(`Port ${port} still open`);
} else {
logSuccess(`Port ${port} successfully closed`);
return true;
}
} catch {
logError(`Port ${port} closing failed`);
}
return false;
} else {
return true;
}
}
export async function killPorts(port?: number): Promise<boolean> {
return port
? await killPort(port)
: (await killPort(3333)) && (await killPort(4200));
}

View File

@ -124,7 +124,8 @@ function run(): void {
run(); run();
export * from './bootstrap.server';" export * from './bootstrap.server';
"
`; `;
exports[`Host App Generator --ssr should generate the correct files 5`] = `"import('./src/main.server');"`; exports[`Host App Generator --ssr should generate the correct files 5`] = `"import('./src/main.server');"`;

View File

@ -13,6 +13,8 @@ import {
corsVersion, corsVersion,
expressVersion, expressVersion,
moduleFederationNodeVersion, moduleFederationNodeVersion,
typesCorsVersion,
typesExpressVersion,
} from '../../../utils/versions'; } from '../../../utils/versions';
export async function addSsr(tree: Tree, options: Schema, appName: string) { export async function addSsr(tree: Tree, options: Schema, appName: string) {
@ -65,7 +67,10 @@ export async function addSsr(tree: Tree, options: Schema, appName: string) {
express: expressVersion, express: expressVersion,
'@module-federation/node': moduleFederationNodeVersion, '@module-federation/node': moduleFederationNodeVersion,
}, },
{} {
'@types/cors': typesCorsVersion,
'@types/express': typesExpressVersion,
}
); );
return installTask; return installTask;

View File

@ -120,7 +120,8 @@ function run(): void {
run(); run();
export * from './bootstrap.server';" export * from './bootstrap.server';
"
`; `;
exports[`MF Remote App Generator --ssr should generate the correct files 5`] = `"import('./src/main.server');"`; exports[`MF Remote App Generator --ssr should generate the correct files 5`] = `"import('./src/main.server');"`;

View File

@ -12,6 +12,8 @@ import {
corsVersion, corsVersion,
expressVersion, expressVersion,
moduleFederationNodeVersion, moduleFederationNodeVersion,
typesCorsVersion,
typesExpressVersion,
} from '../../../utils/versions'; } from '../../../utils/versions';
export async function addSsr( export async function addSsr(
@ -70,7 +72,10 @@ export async function addSsr(
express: expressVersion, express: expressVersion,
'@module-federation/node': moduleFederationNodeVersion, '@module-federation/node': moduleFederationNodeVersion,
}, },
{} {
'@types/cors': typesCorsVersion,
'@types/express': typesExpressVersion,
}
); );
return installTask; return installTask;

View File

@ -22,7 +22,9 @@ export const backwardCompatibleVersions: Record<
tsLibVersion: '^2.3.0', tsLibVersion: '^2.3.0',
ngUniversalVersion: '~14.2.0', ngUniversalVersion: '~14.2.0',
corsVersion: '~2.8.5', corsVersion: '~2.8.5',
typesCorsVersion: '~2.8.5',
expressVersion: '~4.18.2', expressVersion: '~4.18.2',
typesExpressVersion: '4.17.14',
moduleFederationNodeVersion: '^0.10.1', moduleFederationNodeVersion: '^0.10.1',
angularEslintVersion: '~14.0.4', angularEslintVersion: '~14.0.4',
tailwindVersion: '^3.0.2', tailwindVersion: '^3.0.2',

View File

@ -11,7 +11,9 @@ export const tsLibVersion = '^2.3.0';
export const ngUniversalVersion = '~15.1.0'; export const ngUniversalVersion = '~15.1.0';
export const corsVersion = '~2.8.5'; export const corsVersion = '~2.8.5';
export const typesCorsVersion = '~2.8.5';
export const expressVersion = '~4.18.2'; export const expressVersion = '~4.18.2';
export const typesExpressVersion = '4.17.14';
export const moduleFederationNodeVersion = '~0.10.1'; export const moduleFederationNodeVersion = '~0.10.1';
export const angularEslintVersion = '~15.0.0'; export const angularEslintVersion = '~15.0.0';