From 581602e8e73edde63748ceeed1564b5d49b68b8c Mon Sep 17 00:00:00 2001 From: Jason Bedard Date: Wed, 8 Jun 2022 16:19:21 -0700 Subject: [PATCH] test: use random port for ng serve e2e tests --- tests/legacy-cli/e2e/tests/basic/rebuild.ts | 13 ++++++++----- tests/legacy-cli/e2e/tests/basic/serve.ts | 12 ++++++------ .../e2e/tests/commands/serve/serve-path.ts | 9 +++++---- tests/legacy-cli/e2e/tests/misc/fallback.ts | 4 ++-- tests/legacy-cli/e2e/tests/misc/proxy-config.ts | 2 +- tests/legacy-cli/e2e/tests/misc/public-host.ts | 10 +++++----- tests/legacy-cli/e2e/tests/misc/ssl-default.ts | 4 ++-- tests/legacy-cli/e2e/tests/misc/ssl-with-cert.ts | 4 ++-- tests/legacy-cli/e2e/utils/network.ts | 13 +++++++++++++ tests/legacy-cli/e2e/utils/project.ts | 13 +++++++++++-- tests/legacy-cli/e2e_runner.ts | 14 +------------- 11 files changed, 56 insertions(+), 42 deletions(-) create mode 100644 tests/legacy-cli/e2e/utils/network.ts diff --git a/tests/legacy-cli/e2e/tests/basic/rebuild.ts b/tests/legacy-cli/e2e/tests/basic/rebuild.ts index 486e6d3fb2..a1af3e8363 100644 --- a/tests/legacy-cli/e2e/tests/basic/rebuild.ts +++ b/tests/legacy-cli/e2e/tests/basic/rebuild.ts @@ -7,12 +7,15 @@ import { import { writeFile, writeMultipleFiles } from '../../utils/fs'; import { wait } from '../../utils/utils'; import fetch from 'node-fetch'; +import { findFreePort } from '../../utils/network'; const validBundleRegEx = / Compiled successfully./; -export default function () { +export default async function () { + const port = await findFreePort(); + return ( - execAndWaitForOutputToMatch('ng', ['serve'], validBundleRegEx) + execAndWaitForOutputToMatch('ng', ['serve', '--port', String(port)], validBundleRegEx) // Add a lazy module. .then(() => ng('generate', 'module', 'lazy', '--routing')) // Should trigger a rebuild with a new bundle. @@ -136,7 +139,7 @@ export default function () { ]), ) .then(() => wait(2000)) - .then(() => fetch('http://localhost:4200/main.js')) + .then(() => fetch(`http://localhost:${port}/main.js`)) .then((response) => response.text()) .then((body) => { if (!body.match(/\$\$_E2E_GOLDEN_VALUE_1/)) { @@ -158,7 +161,7 @@ export default function () { ]), ) .then(() => wait(2000)) - .then(() => fetch('http://localhost:4200/main.js')) + .then(() => fetch(`http://localhost:${port}/main.js`)) .then((response) => response.text()) .then((body) => { if (!body.match(/testingTESTING123/)) { @@ -174,7 +177,7 @@ export default function () { ]), ) .then(() => wait(2000)) - .then(() => fetch('http://localhost:4200/main.js')) + .then(() => fetch(`http://localhost:${port}/main.js`)) .then((response) => response.text()) .then((body) => { if (!body.match(/color:\s?blue/)) { diff --git a/tests/legacy-cli/e2e/tests/basic/serve.ts b/tests/legacy-cli/e2e/tests/basic/serve.ts index 9078c4779f..f0e893f2c5 100644 --- a/tests/legacy-cli/e2e/tests/basic/serve.ts +++ b/tests/legacy-cli/e2e/tests/basic/serve.ts @@ -5,20 +5,20 @@ import { ngServe } from '../../utils/project'; export default async function () { try { // Serve works without HMR - await ngServe('--no-hmr'); - await verifyResponse(); + const noHmrPort = await ngServe('--no-hmr'); + await verifyResponse(noHmrPort); await killAllProcesses(); // Serve works with HMR - await ngServe('--hmr'); - await verifyResponse(); + const hmrPort = await ngServe('--hmr'); + await verifyResponse(hmrPort); } finally { await killAllProcesses(); } } -async function verifyResponse(): Promise { - const response = await fetch('http://localhost:4200/'); +async function verifyResponse(port: number): Promise { + const response = await fetch(`http://localhost:${port}/`); if (!/<\/app-root>/.test(await response.text())) { throw new Error('Response does not match expected value.'); diff --git a/tests/legacy-cli/e2e/tests/commands/serve/serve-path.ts b/tests/legacy-cli/e2e/tests/commands/serve/serve-path.ts index 6217656a2a..d5783b7883 100644 --- a/tests/legacy-cli/e2e/tests/commands/serve/serve-path.ts +++ b/tests/legacy-cli/e2e/tests/commands/serve/serve-path.ts @@ -3,17 +3,18 @@ import fetch from 'node-fetch'; import { killAllProcesses } from '../../../utils/process'; import { ngServe } from '../../../utils/project'; -export default function () { +export default async function () { // TODO(architect): Delete this test. It is now in devkit/build-angular. + const port = await ngServe('--serve-path', 'test/'); + return Promise.resolve() - .then(() => ngServe('--serve-path', 'test/')) - .then(() => fetch('http://localhost:4200/test', { headers: { 'Accept': 'text/html' } })) + .then(() => fetch(`http://localhost:${port}/test`, { headers: { 'Accept': 'text/html' } })) .then(async (response) => { assert.strictEqual(response.status, 200); assert.match(await response.text(), /<\/app-root>/); }) - .then(() => fetch('http://localhost:4200/test/abc', { headers: { 'Accept': 'text/html' } })) + .then(() => fetch(`http://localhost:${port}/test/abc`, { headers: { 'Accept': 'text/html' } })) .then(async (response) => { assert.strictEqual(response.status, 200); assert.match(await response.text(), /<\/app-root>/); diff --git a/tests/legacy-cli/e2e/tests/misc/fallback.ts b/tests/legacy-cli/e2e/tests/misc/fallback.ts index bb3b27b150..925d694a48 100644 --- a/tests/legacy-cli/e2e/tests/misc/fallback.ts +++ b/tests/legacy-cli/e2e/tests/misc/fallback.ts @@ -12,7 +12,7 @@ export default function () { return ( Promise.resolve() .then(() => ngServe()) - .then(() => fetch('http://localhost:4200/', { headers: { 'Accept': 'text/html' } })) + .then((port) => fetch(`http://localhost:${port}/`, { headers: { 'Accept': 'text/html' } })) .then(async (response) => { assert.strictEqual(response.status, 200); assert.match(await response.text(), /<\/app-root>/); @@ -27,7 +27,7 @@ export default function () { }), ) .then(() => ngServe()) - .then(() => fetch('http://localhost:4200/', { headers: { 'Accept': 'text/html' } })) + .then((port) => fetch(`http://localhost:${port}/`, { headers: { 'Accept': 'text/html' } })) .then(async (response) => { assert.strictEqual(response.status, 200); assert.match(await response.text(), /<\/app-root>/); diff --git a/tests/legacy-cli/e2e/tests/misc/proxy-config.ts b/tests/legacy-cli/e2e/tests/misc/proxy-config.ts index ff860a0a78..edc0619ad7 100644 --- a/tests/legacy-cli/e2e/tests/misc/proxy-config.ts +++ b/tests/legacy-cli/e2e/tests/misc/proxy-config.ts @@ -34,7 +34,7 @@ export default function () { return Promise.resolve() .then(() => writeFile(proxyConfigFile, JSON.stringify(proxyConfig, null, 2))) .then(() => ngServe('--proxy-config', proxyConfigFile)) - .then(() => fetch('http://localhost:4200/api/test')) + .then((port) => fetch(`http://localhost:${port}/api/test`)) .then(async (response) => { assert.strictEqual(response.status, 200); assert.match(await response.text(), /TEST_API_RETURN/); diff --git a/tests/legacy-cli/e2e/tests/misc/public-host.ts b/tests/legacy-cli/e2e/tests/misc/public-host.ts index bf1e744486..6b5aa3c52d 100644 --- a/tests/legacy-cli/e2e/tests/misc/public-host.ts +++ b/tests/legacy-cli/e2e/tests/misc/public-host.ts @@ -11,12 +11,12 @@ export default function () { .filter((ni) => ni?.family === 'IPv4' && !ni?.internal) .map((ni) => ni!.address) .shift(); - const publicHost = `${firstLocalIp}:4200`; + const publicHost = `${firstLocalIp}`; const localAddress = `http://${publicHost}`; return Promise.resolve() .then(() => ngServe('--host=0.0.0.0', `--public-host=${publicHost}`)) - .then(() => fetch(localAddress)) + .then((port) => fetch(`${localAddress}:${port}`)) .then((response) => response.text()) .then((body) => { if (!body.match(/<\/app-root>/)) { @@ -25,7 +25,7 @@ export default function () { }) .then(() => killAllProcesses()) .then(() => ngServe('--host=0.0.0.0', `--disable-host-check`)) - .then(() => fetch(localAddress)) + .then((port) => fetch(`${localAddress}:${port}`)) .then((response) => response.text()) .then((body) => { if (!body.match(/<\/app-root>/)) { @@ -35,7 +35,7 @@ export default function () { .then(() => killAllProcesses()) .then(() => ngServe('--host=0.0.0.0', `--public-host=${localAddress}`)) - .then(() => fetch(localAddress)) + .then((port) => fetch(`${localAddress}:${port}`)) .then((response) => response.text()) .then((body) => { if (!body.match(/<\/app-root>/)) { @@ -44,7 +44,7 @@ export default function () { }) .then(() => killAllProcesses()) .then(() => ngServe('--host=0.0.0.0', `--public-host=${firstLocalIp}`)) - .then(() => fetch(localAddress)) + .then((port) => fetch(`${localAddress}:${port}`)) .then((response) => response.text()) .then((body) => { if (!body.match(/<\/app-root>/)) { diff --git a/tests/legacy-cli/e2e/tests/misc/ssl-default.ts b/tests/legacy-cli/e2e/tests/misc/ssl-default.ts index 0dd010337a..c985df57b7 100644 --- a/tests/legacy-cli/e2e/tests/misc/ssl-default.ts +++ b/tests/legacy-cli/e2e/tests/misc/ssl-default.ts @@ -8,9 +8,9 @@ export default async function () { // TODO(architect): Delete this test. It is now in devkit/build-angular. try { - await ngServe('--ssl', 'true'); + const port = await ngServe('--ssl', 'true'); - const response = await fetch('https://localhost:4200/', { + const response = await fetch(`https://localhost:${port}/`, { agent: new Agent({ rejectUnauthorized: false }), }); diff --git a/tests/legacy-cli/e2e/tests/misc/ssl-with-cert.ts b/tests/legacy-cli/e2e/tests/misc/ssl-with-cert.ts index 4ff12a5b22..d1f107cd0e 100644 --- a/tests/legacy-cli/e2e/tests/misc/ssl-with-cert.ts +++ b/tests/legacy-cli/e2e/tests/misc/ssl-with-cert.ts @@ -9,7 +9,7 @@ export default async function () { // TODO(architect): Delete this test. It is now in devkit/build-angular. try { - await ngServe( + const port = await ngServe( '--ssl', 'true', '--ssl-key', @@ -18,7 +18,7 @@ export default async function () { assetDir('ssl/server.crt'), ); - const response = await fetch('https://localhost:4200/', { + const response = await fetch(`https://localhost:${port}/`, { agent: new Agent({ rejectUnauthorized: false }), }); diff --git a/tests/legacy-cli/e2e/utils/network.ts b/tests/legacy-cli/e2e/utils/network.ts new file mode 100644 index 0000000000..e7cff34eec --- /dev/null +++ b/tests/legacy-cli/e2e/utils/network.ts @@ -0,0 +1,13 @@ +import { AddressInfo, createServer } from 'net'; + +export function findFreePort() { + return new Promise((resolve, reject) => { + const srv = createServer(); + srv.once('listening', () => { + const port = (srv.address() as AddressInfo).port; + srv.close((e) => (e ? reject(e) : resolve(port))); + }); + srv.once('error', (e) => srv.close(() => reject(e))); + srv.listen(); + }); +} diff --git a/tests/legacy-cli/e2e/utils/project.ts b/tests/legacy-cli/e2e/utils/project.ts index f55194f3b8..3f750464dd 100644 --- a/tests/legacy-cli/e2e/utils/project.ts +++ b/tests/legacy-cli/e2e/utils/project.ts @@ -6,6 +6,7 @@ import { packages } from '../../../../lib/packages'; import { getGlobalVariable } from './env'; import { prependToFile, readFile, replaceInFile, writeFile } from './fs'; import { gitCommit } from './git'; +import { findFreePort } from './network'; import { installWorkspacePackages } from './packages'; import { exec, execAndWaitForOutputToMatch, git, ng } from './process'; @@ -23,8 +24,16 @@ export function updateTsConfig(fn: (json: any) => any | void) { return updateJsonFile('tsconfig.json', fn); } -export function ngServe(...args: string[]) { - return execAndWaitForOutputToMatch('ng', ['serve', ...args], / Compiled successfully./); +export async function ngServe(...args: string[]) { + const port = await findFreePort(); + + await execAndWaitForOutputToMatch( + 'ng', + ['serve', '--port', String(port), ...args], + / Compiled successfully./, + ); + + return port; } export async function prepareProjectForE2e(name: string) { const argv: yargsParser.Arguments = getGlobalVariable('argv'); diff --git a/tests/legacy-cli/e2e_runner.ts b/tests/legacy-cli/e2e_runner.ts index 5dab8c7694..1cbe21956e 100644 --- a/tests/legacy-cli/e2e_runner.ts +++ b/tests/legacy-cli/e2e_runner.ts @@ -7,9 +7,9 @@ import * as path from 'path'; import { getGlobalVariable, setGlobalVariable } from './e2e/utils/env'; import { gitClean } from './e2e/utils/git'; import { createNpmRegistry } from './e2e/utils/registry'; -import { AddressInfo, createServer } from 'net'; import { launchTestProcess } from './e2e/utils/process'; import { join } from 'path'; +import { findFreePort } from './e2e/utils/network'; Error.stackTraceLimit = Infinity; @@ -254,15 +254,3 @@ function printFooter(testName: string, type: 'setup' | 'initializer' | 'test', s console.log(colors.green(`Last ${type} took `) + colors.bold.blue('' + t) + colors.green('s...')); console.log(''); } - -function findFreePort() { - return new Promise((resolve, reject) => { - const srv = createServer(); - srv.once('listening', () => { - const port = (srv.address() as AddressInfo).port; - srv.close((e) => (e ? reject(e) : resolve(port))); - }); - srv.once('error', (e) => srv.close(() => reject(e))); - srv.listen(); - }); -}