Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,7 @@ jobs:
strategy:
fail-fast: false
matrix:
# These tests can generate a significant amount of temp files, especially when
# flaky targets are retried. The larger machine type comes with 2x more SSD space.
os: [ubuntu-latest-4core]
os: [ubuntu-latest]
node: [22]
subset: [yarn, pnpm]
shard: [0, 1, 2]
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,7 @@ jobs:
strategy:
fail-fast: false
matrix:
# These tests can generate a significant amount of temp files, especially when
# flaky targets are retried. The larger machine type comes with 2x more SSD space.
os: [ubuntu-latest-4core]
os: [ubuntu-latest]
node: [22]
subset: [yarn, pnpm]
shard: [0, 1, 2]
Expand Down
19 changes: 0 additions & 19 deletions tests/legacy-cli/e2e/setup/001-create-tmp-dir.ts

This file was deleted.

12 changes: 7 additions & 5 deletions tests/legacy-cli/e2e/utils/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { getGlobalVariable } from './env';
import { resolve } from 'node:path';
import { copyFile } from './fs';
import { installWorkspacePackages, setRegistry } from './packages';
import { useBuiltPackagesVersions } from './project';
import { getTestProjectDir, useBuiltPackagesVersions } from './project';

export function assetDir(assetName: string) {
return join(__dirname, '../e2e/assets', assetName);
Expand All @@ -21,7 +21,7 @@ export function copyProjectAsset(assetName: string, to?: string) {

export function copyAssets(assetName: string, to?: string) {
const seed = +Date.now();
const tempRoot = join(getGlobalVariable('projects-root'), 'assets', assetName + '-' + seed);
const tempRoot = join(getTestAssetsDir(), assetName + '-' + seed);
const root = assetDir(assetName);

return Promise.resolve()
Expand All @@ -30,9 +30,7 @@ export function copyAssets(assetName: string, to?: string) {

return allFiles.reduce((promise, filePath) => {
const toPath =
to !== undefined
? resolve(getGlobalVariable('projects-root'), 'test-project', to, filePath)
: join(tempRoot, filePath);
to !== undefined ? resolve(getTestProjectDir(), to, filePath) : join(tempRoot, filePath);

return promise
.then(() => copyFile(join(root, filePath), toPath))
Expand Down Expand Up @@ -65,3 +63,7 @@ export async function createProjectFromAsset(

return () => setRegistry(true /** useTestRegistry */);
}

export function getTestAssetsDir(): string {
return join(getGlobalVariable('projects-root'), 'assets');
}
5 changes: 5 additions & 0 deletions tests/legacy-cli/e2e/utils/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { gitCommit } from './git';
import { findFreePort } from './network';
import { installWorkspacePackages, PkgInfo } from './packages';
import { execAndWaitForOutputToMatch, git, ng } from './process';
import { join } from 'node:path';

export function updateJsonFile(filePath: string, fn: (json: any) => any | void) {
return readFile(filePath).then((tsConfigJson) => {
Expand Down Expand Up @@ -270,3 +271,7 @@ export function updateServerFileForEsbuild(filepath: string): Promise<void> {
`,
);
}

export function getTestProjectDir(): string {
return join(getGlobalVariable('projects-root'), 'test-project');
}
21 changes: 13 additions & 8 deletions tests/legacy-cli/e2e/utils/registry.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { ChildProcess, fork } from 'node:child_process';
import { on } from 'node:events';
import { mkdir } from 'node:fs/promises';
import { join } from 'node:path';
import { getGlobalVariable } from './env';
import { writeFile, readFile } from './fs';
import { mktempd } from './utils';
import { existsSync } from 'node:fs';

export async function createNpmRegistry(
port: number,
httpsPort: number,
withAuthentication = false,
): Promise<ChildProcess> {
// Setup local package registry
const registryPath = await mktempd('angular-cli-e2e-registry-');
const registryPath = join(getGlobalVariable('tmp-root'), 'registry');
if (!existsSync(registryPath)) {
await mkdir(registryPath);
}

const configFileName = withAuthentication ? 'verdaccio_auth.yaml' : 'verdaccio.yaml';
let configContent = await readFile(join(__dirname, '../', configFileName));
configContent = configContent
.replace(/\$\{HTTP_PORT\}/g, String(port))
.replace(/\$\{HTTPS_PORT\}/g, String(httpsPort));
const configPath = join(registryPath, configFileName);

let configContent = await readFile(
join(__dirname, '../', withAuthentication ? 'verdaccio_auth.yaml' : 'verdaccio.yaml'),
);
configContent = configContent.replace(/\$\{HTTP_PORT\}/g, String(port));
configContent = configContent.replace(/\$\{HTTPS_PORT\}/g, String(httpsPort));
const configPath = join(registryPath, 'verdaccio.yaml');
await writeFile(configPath, configContent);

const verdaccioServer = fork(require.resolve('verdaccio/bin/verdaccio'), ['-c', configPath]);
Expand Down
125 changes: 71 additions & 54 deletions tests/legacy-cli/e2e_runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import colors from 'ansi-colors';
import glob from 'fast-glob';
import * as path from 'node:path';
import * as fs from 'node:fs';
import { rm } from 'node:fs/promises';
import { getGlobalVariable, setGlobalVariable } from './e2e/utils/env';
import { gitClean } from './e2e/utils/git';
import { createNpmRegistry } from './e2e/utils/registry';
Expand All @@ -13,7 +14,8 @@ import { findFreePort } from './e2e/utils/network';
import { extractFile } from './e2e/utils/tar';
import { realpathSync } from 'node:fs';
import { PkgInfo } from './e2e/utils/packages';
import { rm } from 'node:fs/promises';
import { getTestProjectDir } from './e2e/utils/project';
import { mktempd } from './e2e/utils/utils';

Error.stackTraceLimit = Infinity;

Expand All @@ -30,13 +32,9 @@ Error.stackTraceLimit = Infinity;
* --ng-snapshots Install angular snapshot builds in the test project.
* --glob Run tests matching this glob pattern (relative to tests/e2e/).
* --ignore Ignore tests matching this glob pattern.
* --reuse=/path Use a path instead of create a new project. That project should have been
* created, and npm installed. Ideally you want a project created by a previous
* run of e2e.
* --nb-shards Total number of shards that this is part of. Default is 2 if --shard is
* passed in.
* --shard Index of this processes' shard.
* --tmpdir=path Override temporary directory to use for new projects.
* --package-manager Package manager to use.
* --package=path An npm package to be published before running tests
*
Expand All @@ -57,8 +55,6 @@ const parsed = parseArgs({
'nosilent': { type: 'boolean' },
'package': { type: 'string', multiple: true, default: ['./dist/_*.tgz'] },
'package-manager': { type: 'string', default: 'npm' },
'reuse': { type: 'string' },
'tmpdir': { type: 'string' },
'verbose': { type: 'boolean' },

'nb-shards': { type: 'string' },
Expand Down Expand Up @@ -226,57 +222,68 @@ process.env.CHROME_BIN = path.resolve(process.env.CHROME_BIN!);
process.env.CHROME_PATH = path.resolve(process.env.CHROME_PATH!);
process.env.CHROMEDRIVER_BIN = path.resolve(process.env.CHROMEDRIVER_BIN!);

Promise.all([findFreePort(), findFreePort(), findPackageTars()])
.then(async ([httpPort, httpsPort, packageTars]) => {
setGlobalVariable('package-registry', 'http://localhost:' + httpPort);
setGlobalVariable('package-secure-registry', 'http://localhost:' + httpsPort);
setGlobalVariable('package-tars', packageTars);

// NPM registries for the lifetime of the test execution
const registryProcess = await createNpmRegistry(httpPort, httpPort);
const secureRegistryProcess = await createNpmRegistry(httpPort, httpsPort, true);

try {
await runSteps(runSetup, allSetups, 'setup');
await runSteps(runInitializer, allInitializers, 'initializer');
await runSteps(runTest, testsToRun, 'test');

if (shardId !== null) {
console.log(colors.green(`Done shard ${shardId} of ${nbShards}.`));
} else {
console.log(colors.green('Done.'));
}
(async () => {
const tempRoot = await mktempd('angular-cli-e2e-', process.env.E2E_TEMP);
setGlobalVariable('tmp-root', tempRoot);

process.on('SIGINT', deleteTemporaryRoot);
process.on('exit', deleteTemporaryRoot);

const [httpPort, httpsPort, packageTars] = await Promise.all([
findFreePort(),
findFreePort(),
findPackageTars(),
]);
setGlobalVariable('package-registry', 'http://localhost:' + httpPort);
setGlobalVariable('package-secure-registry', 'http://localhost:' + httpsPort);
setGlobalVariable('package-tars', packageTars);

// NPM registries for the lifetime of the test execution
const registryProcess = await createNpmRegistry(httpPort, httpPort);
const secureRegistryProcess = await createNpmRegistry(httpPort, httpsPort, true);

try {
console.log(` Using "${tempRoot}" as temporary directory for a new project.`);

await runSteps(runSetup, allSetups, 'setup');
await runSteps(runInitializer, allInitializers, 'initializer');
await runSteps(runTest, testsToRun, 'test');

if (shardId !== null) {
console.log(colors.green(`Done shard ${shardId} of ${nbShards}.`));
} else {
console.log(colors.green('Done.'));
}

process.exitCode = 0;
} catch (err) {
if (err instanceof Error) {
console.log('\n');
console.error(colors.red(err.message));
if (err.stack) {
console.error(colors.red(err.stack));
}
} else {
console.error(colors.red(String(err)));
process.exitCode = 0;
} catch (err) {
if (err instanceof Error) {
console.log('\n');
console.error(colors.red(err.message));
if (err.stack) {
console.error(colors.red(err.stack));
}
} else {
console.error(colors.red(String(err)));
}

if (argv.debug) {
console.log(`Current Directory: ${process.cwd()}`);
console.log('Will loop forever while you debug... CTRL-C to quit.');
if (argv.debug) {
console.log(`Current Directory: ${process.cwd()}`);
console.log('Will loop forever while you debug... CTRL-C to quit.');

// Wait forever until user explicitly cancels.
await new Promise(() => {});
}

process.exitCode = 1;
} finally {
registryProcess.kill();
secureRegistryProcess.kill();
// Wait forever until user explicitly cancels.
await new Promise(() => {});
}
})
.catch((err) => {
console.error(colors.red(`Unkown Error: ${err}`));

process.exitCode = 1;
});
} finally {
registryProcess.kill();
secureRegistryProcess.kill();
}
})().catch((err) => {
console.error(colors.red(`Unkown Error: ${err}`));
process.exitCode = 1;
});

async function runSteps(
run: (name: string) => Promise<void> | void,
Expand Down Expand Up @@ -334,7 +341,7 @@ function runInitializer(absoluteName: string): Promise<void> {
* Run a file from the main 'test-project' directory in a subprocess via launchTestProcess().
*/
async function runTest(absoluteName: string): Promise<void> {
process.chdir(join(getGlobalVariable('projects-root'), 'test-project'));
process.chdir(getTestProjectDir());

await launchTestProcess(absoluteName);
await cleanTestProject();
Expand All @@ -343,7 +350,7 @@ async function runTest(absoluteName: string): Promise<void> {
async function cleanTestProject() {
await gitClean();

const testProject = join(getGlobalVariable('projects-root'), 'test-project');
const testProject = getTestProjectDir();

// Note: Dist directory is not cleared between tests, as `git clean`
// doesn't delete it.
Expand Down Expand Up @@ -406,3 +413,13 @@ async function findPackageTars(): Promise<{ [pkg: string]: PkgInfo }> {
{} as { [pkg: string]: PkgInfo },
);
}

function deleteTemporaryRoot(): void {
try {
fs.rmSync(getGlobalVariable('tmp-root'), {
recursive: true,
force: true,
maxRetries: 3,
});
} catch {}
}