Skip to content

Commit 24be1e7

Browse files
committed
refactor(@angular-devkit/build-angular): only write test related files in WTR builder
With the structured build results available, the WTR builder can now more easily write only the needed files to a temporary location. This reduces the need to assume build directory output structure and reduces the amount of potential filesystem calls. The temporary files are also now written into a UUID subdirectory within the existing `dist/test-out` location. This allows for multiple projects to be tested concurrently without overwriting each other.
1 parent 3f74f90 commit 24be1e7

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

packages/angular_devkit/build_angular/src/builders/web-test-runner/index.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
import { Result, ResultKind, buildApplicationInternal } from '@angular/build/private';
1010
import { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
1111
import type * as WebTestRunner from '@web/test-runner';
12-
import { promises as fs } from 'node:fs';
12+
import { randomUUID } from 'node:crypto';
13+
import fs from 'node:fs/promises';
1314
import { createRequire } from 'node:module';
1415
import path from 'node:path';
1516
import { findTestFiles } from '../../utils/test-files';
1617
import { OutputHashing } from '../browser-esbuild/schema';
1718
import { logBuilderStatusWarnings } from './builder-status-warnings';
1819
import { WtrBuilderOptions, normalizeOptions } from './options';
1920
import { Schema } from './schema';
21+
import { writeTestFiles } from './write-test-files';
2022

2123
export default createBuilder(
2224
async (schema: Schema, ctx: BuilderContext): Promise<BuilderOutput> => {
@@ -41,7 +43,8 @@ export default createBuilder(
4143
}
4244

4345
const options = normalizeOptions(schema);
44-
const testDir = 'dist/test-out';
46+
47+
const testDir = path.join(ctx.workspaceRoot, 'dist/test-out', randomUUID());
4548

4649
// Parallelize startup work.
4750
const [testFiles] = await Promise.all([
@@ -55,10 +58,18 @@ export default createBuilder(
5558
const buildOutput = await buildTests(testFiles, testDir, options, ctx);
5659
if (buildOutput.kind === ResultKind.Failure) {
5760
return { success: false };
61+
} else if (buildOutput.kind !== ResultKind.Full) {
62+
return {
63+
success: false,
64+
error: 'A full build result is required from the application builder.',
65+
};
5866
}
5967

68+
// Write test files
69+
await writeTestFiles(buildOutput.files, testDir);
70+
6071
// Run the built tests.
61-
return await runTests(wtr, `${testDir}/browser`, options);
72+
return await runTests(wtr, testDir, options);
6273
},
6374
);
6475

@@ -105,6 +116,7 @@ async function buildTests(
105116
polyfills,
106117
},
107118
ctx,
119+
{ write: false },
108120
),
109121
);
110122

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import { BuildOutputFileType } from '@angular/build';
10+
import { ResultFile, emitFilesToDisk } from '@angular/build/private';
11+
import fs from 'node:fs/promises';
12+
import path from 'node:path';
13+
14+
export async function writeTestFiles(files: Record<string, ResultFile>, testDir: string) {
15+
const directoryExists = new Set<string>();
16+
// Writes the test related output files to disk and ensures the containing directories are present
17+
await emitFilesToDisk(Object.entries(files), async ([filePath, file]) => {
18+
if (file.type !== BuildOutputFileType.Browser && file.type !== BuildOutputFileType.Media) {
19+
return;
20+
}
21+
22+
const fullFilePath = path.join(testDir, filePath);
23+
24+
// Ensure output subdirectories exist
25+
const fileBasePath = path.dirname(fullFilePath);
26+
if (fileBasePath && !directoryExists.has(fileBasePath)) {
27+
await fs.mkdir(fileBasePath, { recursive: true });
28+
directoryExists.add(fileBasePath);
29+
}
30+
31+
if (file.origin === 'memory') {
32+
// Write file contents
33+
await fs.writeFile(fullFilePath, file.contents);
34+
} else {
35+
// Copy file contents
36+
await fs.copyFile(file.inputPath, fullFilePath, fs.constants.COPYFILE_FICLONE);
37+
}
38+
});
39+
}

0 commit comments

Comments
 (0)