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 {
cleanupProject,
killPort,
newProject,
promisifiedTreeKill,
readProjectConfig,
@ -15,9 +16,17 @@ import { names } from '@nrwl/devkit';
describe('Angular Projects', () => {
let proj: string;
let oldValue;
beforeAll(() => (proj = newProject()));
afterAll(() => cleanupProject());
beforeAll(() => {
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 () => {
// ACT + ASSERT
@ -60,7 +69,7 @@ describe('Angular Projects', () => {
import { AppComponent } from './app.component';
import { NxWelcomeComponent } from './nx-welcome.component';
import { RouterModule } from '@angular/router';
@NgModule({
declarations: [AppComponent, NxWelcomeComponent],
imports: [
@ -95,7 +104,7 @@ describe('Angular Projects', () => {
names(secondaryEntry).className
}Module } from '@${proj}/${secondaryEntry}';
import { RemoteEntryComponent } from './entry.component';
@NgModule({
declarations: [RemoteEntryComponent],
imports: [
@ -135,6 +144,8 @@ describe('Angular Projects', () => {
if (process && process.pid) {
await promisifiedTreeKill(process.pid, 'SIGKILL');
}
await killPort(port1);
await killPort(port2);
} catch (err) {
expect(err).toBeFalsy();
}
@ -168,21 +179,27 @@ describe('Angular Projects', () => {
`generate @nrwl/angular:remote ${remoteApp1} --ssr --no-interactive`
);
let process = await runCommandUntil(`serve-ssr ${remoteApp1}`, (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 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`
)
);
}
);
// port and process cleanup
try {
if (process && process.pid) {
await promisifiedTreeKill(process.pid, 'SIGKILL');
}
await killPort(port);
} catch (err) {
expect(err).toBeFalsy();
}
@ -204,25 +221,33 @@ describe('Angular Projects', () => {
const remoteApp2Port =
readProjectConfig(remoteApp2).targets.serve.options.port;
let process = await runCommandUntil(`serve-ssr ${hostApp}`, (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 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`
)
);
}
);
// 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();
}
@ -240,18 +265,24 @@ describe('Angular Projects', () => {
return project;
});
const port = 4501;
// ACT
let process = await runCommandUntil(`serve-ssr ${ssrApp}`, (output) => {
return output.includes(
`Angular Universal Live Development Server is listening on http://localhost:4200`
);
});
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();
}

View File

@ -11,13 +11,10 @@ import {
import { TargetConfiguration } from '@nrwl/devkit';
import { ChildProcess, exec, execSync, ExecSyncOptions } from 'child_process';
import { join } from 'path';
import { check as portCheck } from 'tcp-port-used';
import * as isCI from 'is-ci';
import { Workspaces } from '../../packages/nx/src/config/workspaces';
import { updateFile } from './file-utils';
import { logError, logInfo, logSuccess, stripConsoleColors } from './log-utils';
export const kill = require('kill-port');
import { logError, stripConsoleColors } from './log-utils';
export interface RunCmdOpts {
silenceError?: boolean;
@ -243,6 +240,15 @@ export function runCommandUntil(
p.stderr?.on('data', checkCriteria);
p.on('exit', (code) => {
if (!complete) {
if (isVerboseE2ERun()) {
logError(
`Original output:`,
output
.split('\n')
.map((l) => ` ${l}`)
.join('\n')
);
}
rej(`Exited with ${code}`);
} else {
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(
predicate: () => boolean,
opts: { timeout: number; ms: number; allowError?: boolean } = {

View File

@ -81,7 +81,7 @@ export function newProject({
packageInstall(packages.join(` `), projScope);
// stop the daemon
execSync('nx reset', {
execSync(`${getPackageManagerCommand().runNx} reset`, {
cwd: `${e2eCwd}/proj`,
stdio: isVerbose() ? 'inherit' : 'pipe',
});
@ -94,6 +94,14 @@ export function newProject({
if (isVerbose()) {
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;
} catch (e) {
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(
name: string,
{

View File

@ -12,8 +12,6 @@ import {
import * as path from 'path';
import { e2eCwd } from './get-env-info';
import { tmpProjPath } from './create-project-utils';
import { promisify } from 'util';
import * as treeKill from 'tree-kill';
export function createFile(f: string, content: string = ''): void {
const path = tmpProjPath(f);
@ -121,8 +119,3 @@ export function getSize(filePath: string): number {
export function tmpBackupProjPath(path?: string) {
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 './project-config-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();
export * from './bootstrap.server';"
export * from './bootstrap.server';
"
`;
exports[`Host App Generator --ssr should generate the correct files 5`] = `"import('./src/main.server');"`;

View File

@ -63,4 +63,4 @@ function run(): void {
run();
export * from './bootstrap.server';
export * from './bootstrap.server';

View File

@ -13,6 +13,8 @@ import {
corsVersion,
expressVersion,
moduleFederationNodeVersion,
typesCorsVersion,
typesExpressVersion,
} from '../../../utils/versions';
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,
'@module-federation/node': moduleFederationNodeVersion,
},
{}
{
'@types/cors': typesCorsVersion,
'@types/express': typesExpressVersion,
}
);
return installTask;

View File

@ -120,7 +120,8 @@ function run(): void {
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');"`;

View File

@ -71,4 +71,4 @@ function run(): void {
run();
export * from './bootstrap.server';
export * from './bootstrap.server';

View File

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

View File

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

View File

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