Skip to content

Commit

Permalink
fix(angular): fix e2e tests to support pnpm v7 (#15587)
Browse files Browse the repository at this point in the history
  • Loading branch information
meeroslav committed Mar 16, 2023
1 parent 10a69b7 commit c690461
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 80 deletions.
93 changes: 62 additions & 31 deletions e2e/angular-core/src/module-federation.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
cleanupProject,
killPort,
newProject,
promisifiedTreeKill,
readProjectConfig,
Expand All @@ -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
Expand Down Expand Up @@ -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: [
Expand Down Expand Up @@ -95,7 +104,7 @@ describe('Angular Projects', () => {
names(secondaryEntry).className
}Module } from '@${proj}/${secondaryEntry}';
import { RemoteEntryComponent } from './entry.component';
@NgModule({
declarations: [RemoteEntryComponent],
imports: [
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
}
Expand All @@ -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();
}
Expand Down
45 changes: 10 additions & 35 deletions e2e/utils/command-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 } = {
Expand Down
18 changes: 17 additions & 1 deletion e2e/utils/create-project-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
});
Expand All @@ -94,13 +94,29 @@ 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);
throw e;
}
}

// 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,
{
Expand Down
7 changes: 0 additions & 7 deletions e2e/utils/file-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
1 change: 1 addition & 0 deletions e2e/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
41 changes: 41 additions & 0 deletions e2e/utils/process-utils.ts
Original file line number Diff line number Diff line change
@@ -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));
}
Original file line number Diff line number Diff line change
Expand Up @@ -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');"`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ function run(): void {

run();

export * from './bootstrap.server';
export * from './bootstrap.server';
7 changes: 6 additions & 1 deletion packages/angular/src/generators/host/lib/add-ssr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
corsVersion,
expressVersion,
moduleFederationNodeVersion,
typesCorsVersion,
typesExpressVersion,
} from '../../../utils/versions';

export async function addSsr(tree: Tree, options: Schema, appName: string) {
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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');"`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,4 @@ function run(): void {

run();

export * from './bootstrap.server';
export * from './bootstrap.server';
Loading

0 comments on commit c690461

Please sign in to comment.