Skip to content

Commit 9687d1f

Browse files
author
Angular Builds
committed
bb802d1 refactor(@angular-devkit/build-angular): only write test related files in Jest builder
1 parent e58c8f7 commit 9687d1f

File tree

7 files changed

+95
-32
lines changed

7 files changed

+95
-32
lines changed

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"name": "@angular-devkit/build-angular",
3-
"version": "18.2.0-next.3+sha-d257388",
3+
"version": "18.2.0-next.3+sha-bb802d1",
44
"description": "Angular Webpack Build Facade",
55
"main": "src/index.js",
66
"typings": "src/index.d.ts",
77
"builders": "builders.json",
88
"dependencies": {
99
"@ampproject/remapping": "2.3.0",
10-
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#d257388",
11-
"@angular-devkit/build-webpack": "github:angular/angular-devkit-build-webpack-builds#d257388",
12-
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#d257388",
13-
"@angular/build": "github:angular/angular-build-builds#d257388",
10+
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#bb802d1",
11+
"@angular-devkit/build-webpack": "github:angular/angular-devkit-build-webpack-builds#bb802d1",
12+
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#bb802d1",
13+
"@angular/build": "github:angular/angular-build-builds#bb802d1",
1414
"@babel/core": "7.25.2",
1515
"@babel/generator": "7.25.0",
1616
"@babel/helper-annotate-as-pure": "7.24.7",
@@ -21,7 +21,7 @@
2121
"@babel/preset-env": "7.25.2",
2222
"@babel/runtime": "7.25.0",
2323
"@discoveryjs/json-ext": "0.6.0",
24-
"@ngtools/webpack": "github:angular/ngtools-webpack-builds#d257388",
24+
"@ngtools/webpack": "github:angular/ngtools-webpack-builds#bb802d1",
2525
"@vitejs/plugin-basic-ssl": "1.1.0",
2626
"ansi-colors": "4.1.3",
2727
"autoprefixer": "10.4.19",

src/builders/jest/index.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
3333
const private_1 = require("@angular/build/private");
3434
const architect_1 = require("@angular-devkit/architect");
3535
const node_child_process_1 = require("node:child_process");
36+
const node_crypto_1 = require("node:crypto");
3637
const fs = __importStar(require("node:fs/promises"));
3738
const path = __importStar(require("node:path"));
3839
const node_util_1 = require("node:util");
3940
const color_1 = require("../../utils/color");
4041
const test_files_1 = require("../../utils/test-files");
4142
const schema_1 = require("../browser-esbuild/schema");
43+
const write_test_files_1 = require("../web-test-runner/write-test-files");
4244
const options_1 = require("./options");
4345
const execFile = (0, node_util_1.promisify)(node_child_process_1.execFile);
4446
/** Main execution function for the Jest builder. */
4547
exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
4648
context.logger.warn('NOTE: The Jest builder is currently EXPERIMENTAL and not ready for production use.');
4749
const options = (0, options_1.normalizeOptions)(schema);
48-
const testOut = 'dist/test-out'; // TODO(dgp1130): Hide in temp directory.
50+
const testOut = path.join(context.workspaceRoot, 'dist/test-out', (0, node_crypto_1.randomUUID)()); // TODO(dgp1130): Hide in temp directory.
4951
// Verify Jest installation and get the path to it's binary.
5052
// We need to `node_modules/.bin/jest`, but there is no means to resolve that directly. Fortunately Jest's `package.json` exports the
5153
// same file at `bin/jest`, so we can just resolve that instead.
@@ -83,7 +85,7 @@ exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
8385
// Build all the test files.
8486
const jestGlobal = path.join(__dirname, 'jest-global.mjs');
8587
const initTestBed = path.join(__dirname, 'init-test-bed.mjs');
86-
const buildResult = await build(context, {
88+
const buildResult = await first((0, private_1.buildApplicationInternal)({
8789
// Build all the test files and also the `jest-global` and `init-test-bed` scripts.
8890
entryPoints: new Set([...testFiles, jestGlobal, initTestBed]),
8991
tsConfig: options.tsConfig,
@@ -99,15 +101,23 @@ exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
99101
styles: false,
100102
vendor: false,
101103
},
102-
});
103-
if (!buildResult.success) {
104-
return buildResult;
104+
}, context, { write: false }));
105+
if (buildResult.kind === private_1.ResultKind.Failure) {
106+
return { success: false };
107+
}
108+
else if (buildResult.kind !== private_1.ResultKind.Full) {
109+
return {
110+
success: false,
111+
error: 'A full build result is required from the application builder.',
112+
};
105113
}
114+
// Write test files
115+
await (0, write_test_files_1.writeTestFiles)(buildResult.files, testOut);
106116
// Execute Jest on the built output directory.
107117
const jestProc = execFile(process.execPath, [
108118
'--experimental-vm-modules',
109119
jest,
110-
`--rootDir="${path.join(testOut, 'browser')}"`,
120+
`--rootDir="${testOut}"`,
111121
`--config=${path.join(__dirname, 'jest.config.mjs')}`,
112122
'--testEnvironment=jsdom',
113123
// TODO(dgp1130): Enable cache once we have a mechanism for properly clearing / disabling it.
@@ -150,19 +160,12 @@ exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
150160
}
151161
return { success: true };
152162
});
153-
async function build(context, options) {
154-
try {
155-
for await (const _ of (0, private_1.buildApplicationInternal)(options, context)) {
156-
// Nothing to do for each event, just wait for the whole build.
157-
}
158-
return { success: true };
159-
}
160-
catch (err) {
161-
return {
162-
success: false,
163-
error: err.message,
164-
};
163+
/** Returns the first item yielded by the given generator and cancels the execution. */
164+
async function first(generator) {
165+
for await (const value of generator) {
166+
return value;
165167
}
168+
throw new Error('Expected generator to emit at least once.');
166169
}
167170
/** Safely resolves the given Node module string. */
168171
function resolveModule(module) {

src/builders/web-test-runner/index.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
1212
Object.defineProperty(exports, "__esModule", { value: true });
1313
const private_1 = require("@angular/build/private");
1414
const architect_1 = require("@angular-devkit/architect");
15-
const node_fs_1 = require("node:fs");
15+
const node_crypto_1 = require("node:crypto");
16+
const promises_1 = __importDefault(require("node:fs/promises"));
1617
const node_module_1 = require("node:module");
1718
const node_path_1 = __importDefault(require("node:path"));
1819
const test_files_1 = require("../../utils/test-files");
1920
const schema_1 = require("../browser-esbuild/schema");
2021
const builder_status_warnings_1 = require("./builder-status-warnings");
2122
const options_1 = require("./options");
23+
const write_test_files_1 = require("./write-test-files");
2224
exports.default = (0, architect_1.createBuilder)(async (schema, ctx) => {
2325
ctx.logger.warn('NOTE: The Web Test Runner builder is currently EXPERIMENTAL and not ready for production use.');
2426
(0, builder_status_warnings_1.logBuilderStatusWarnings)(schema, ctx);
@@ -37,21 +39,29 @@ exports.default = (0, architect_1.createBuilder)(async (schema, ctx) => {
3739
};
3840
}
3941
const options = (0, options_1.normalizeOptions)(schema);
40-
const testDir = 'dist/test-out';
42+
const testDir = node_path_1.default.join(ctx.workspaceRoot, 'dist/test-out', (0, node_crypto_1.randomUUID)());
4143
// Parallelize startup work.
4244
const [testFiles] = await Promise.all([
4345
// Glob for files to test.
4446
(0, test_files_1.findTestFiles)(options.include, options.exclude, ctx.workspaceRoot),
4547
// Clean build output path.
46-
node_fs_1.promises.rm(testDir, { recursive: true, force: true }),
48+
promises_1.default.rm(testDir, { recursive: true, force: true }),
4749
]);
4850
// Build the tests and abort on any build failure.
4951
const buildOutput = await buildTests(testFiles, testDir, options, ctx);
5052
if (buildOutput.kind === private_1.ResultKind.Failure) {
5153
return { success: false };
5254
}
55+
else if (buildOutput.kind !== private_1.ResultKind.Full) {
56+
return {
57+
success: false,
58+
error: 'A full build result is required from the application builder.',
59+
};
60+
}
61+
// Write test files
62+
await (0, write_test_files_1.writeTestFiles)(buildOutput.files, testDir);
5363
// Run the built tests.
54-
return await runTests(wtr, `${testDir}/browser`, options);
64+
return await runTests(wtr, testDir, options);
5565
});
5666
/** Build all the given test files and write the result to the given output path. */
5767
async function buildTests(testFiles, outputPath, options, ctx) {
@@ -85,7 +95,7 @@ async function buildTests(testFiles, outputPath, options, ctx) {
8595
vendor: true,
8696
},
8797
polyfills,
88-
}, ctx));
98+
}, ctx, { write: false }));
8999
return buildOutput;
90100
}
91101
function extractZoneTesting(polyfills) {
@@ -96,7 +106,7 @@ function extractZoneTesting(polyfills) {
96106
/** Run Web Test Runner on the given directory of bundled JavaScript tests. */
97107
async function runTests(wtr, testDir, options) {
98108
const testPagePath = node_path_1.default.resolve(__dirname, 'test_page.html');
99-
const testPage = await node_fs_1.promises.readFile(testPagePath, 'utf8');
109+
const testPage = await promises_1.default.readFile(testPagePath, 'utf8');
100110
const runner = await wtr.startTestRunner({
101111
config: {
102112
rootDir: testDir,
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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+
import { ResultFile } from '@angular/build/private';
9+
export declare function writeTestFiles(files: Record<string, ResultFile>, testDir: string): Promise<void>;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
"use strict";
2+
/**
3+
* @license
4+
* Copyright Google LLC All Rights Reserved.
5+
*
6+
* Use of this source code is governed by an MIT-style license that can be
7+
* found in the LICENSE file at https://angular.dev/license
8+
*/
9+
var __importDefault = (this && this.__importDefault) || function (mod) {
10+
return (mod && mod.__esModule) ? mod : { "default": mod };
11+
};
12+
Object.defineProperty(exports, "__esModule", { value: true });
13+
exports.writeTestFiles = writeTestFiles;
14+
const build_1 = require("@angular/build");
15+
const private_1 = require("@angular/build/private");
16+
const promises_1 = __importDefault(require("node:fs/promises"));
17+
const node_path_1 = __importDefault(require("node:path"));
18+
async function writeTestFiles(files, testDir) {
19+
const directoryExists = new Set();
20+
// Writes the test related output files to disk and ensures the containing directories are present
21+
await (0, private_1.emitFilesToDisk)(Object.entries(files), async ([filePath, file]) => {
22+
if (file.type !== build_1.BuildOutputFileType.Browser && file.type !== build_1.BuildOutputFileType.Media) {
23+
return;
24+
}
25+
const fullFilePath = node_path_1.default.join(testDir, filePath);
26+
// Ensure output subdirectories exist
27+
const fileBasePath = node_path_1.default.dirname(fullFilePath);
28+
if (fileBasePath && !directoryExists.has(fileBasePath)) {
29+
await promises_1.default.mkdir(fileBasePath, { recursive: true });
30+
directoryExists.add(fileBasePath);
31+
}
32+
if (file.origin === 'memory') {
33+
// Write file contents
34+
await promises_1.default.writeFile(fullFilePath, file.contents);
35+
}
36+
else {
37+
// Copy file contents
38+
await promises_1.default.copyFile(file.inputPath, fullFilePath, promises_1.default.constants.COPYFILE_FICLONE);
39+
}
40+
});
41+
}

src/utils/normalize-cache.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
1010
exports.normalizeCacheOptions = normalizeCacheOptions;
1111
const node_path_1 = require("node:path");
1212
/** Version placeholder is replaced during the build process with actual package version */
13-
const VERSION = '18.2.0-next.3+sha-d257388';
13+
const VERSION = '18.2.0-next.3+sha-bb802d1';
1414
function hasCacheMetadata(value) {
1515
return (!!value &&
1616
typeof value === 'object' &&

uniqueId

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Wed Jul 31 2024 11:53:13 GMT+0000 (Coordinated Universal Time)
1+
Mon Aug 05 2024 17:50:53 GMT+0000 (Coordinated Universal Time)

0 commit comments

Comments
 (0)