@angular-devkit/build-angular 19.2.0-next.2 → 19.2.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +18 -18
- package/src/builders/app-shell/index.js +2 -2
- package/src/builders/browser/index.js +2 -2
- package/src/builders/dev-server/webpack-server.js +2 -2
- package/src/builders/extract-i18n/ivy-extract-loader.js +1 -1
- package/src/builders/karma/browser_builder.js +2 -2
- package/src/builders/karma/find-tests-plugin.js +4 -4
- package/src/builders/karma/index.js +22 -7
- package/src/builders/prerender/index.js +2 -2
- package/src/builders/protractor/index.js +3 -3
- package/src/builders/ssr-dev-server/index.js +5 -5
- package/src/builders/ssr-dev-server/utils.d.ts +1 -1
- package/src/builders/ssr-dev-server/utils.js +5 -5
- package/src/builders/web-test-runner/index.js +1 -1
- package/src/builders/web-test-runner/schema.d.ts +4 -0
- package/src/builders/web-test-runner/schema.json +5 -0
- package/src/tools/webpack/configs/common.js +1 -1
- package/src/tools/webpack/configs/dev-server.js +15 -15
- package/src/tools/webpack/plugins/any-component-style-budget-checker.js +1 -1
- package/src/tools/webpack/plugins/common-js-usage-warn-plugin.js +2 -2
- package/src/tools/webpack/plugins/hmr/hmr-loader.js +2 -2
- package/src/tools/webpack/plugins/index-html-webpack-plugin.js +4 -4
- package/src/tools/webpack/plugins/postcss-cli-resources.js +2 -2
- package/src/tools/webpack/plugins/scripts-webpack-plugin.js +1 -1
- package/src/tools/webpack/plugins/styles-webpack-plugin.js +3 -3
- package/src/tools/webpack/plugins/transfer-size-plugin.js +3 -3
- package/src/tools/webpack/utils/helpers.js +3 -3
- package/src/utils/error.js +2 -2
- package/src/utils/i18n-inlining.js +2 -2
- package/src/utils/normalize-asset-patterns.js +3 -3
- package/src/utils/normalize-cache.js +1 -1
- package/src/utils/normalize-file-replacements.js +4 -4
- package/src/utils/normalize-polyfills.js +4 -4
- package/src/utils/output-paths.js +5 -5
- package/src/utils/process-bundle.js +4 -4
- package/src/utils/read-tsconfig.js +1 -1
- package/src/utils/run-module-as-observable-fork.js +4 -4
- package/src/utils/webpack-browser-config.js +1 -1
- package/src/builders/karma/application_builder.d.ts +0 -19
- package/src/builders/karma/application_builder.js +0 -458
- package/src/builders/karma/find-tests.d.ts +0 -15
- package/src/builders/karma/find-tests.js +0 -144
- package/src/builders/karma/init_test_bed.js +0 -19
- package/src/builders/karma/jasmine_global.js +0 -18
- package/src/builders/karma/jasmine_global_cleanup.js +0 -14
|
@@ -1,458 +0,0 @@
|
|
|
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
-
}
|
|
15
|
-
Object.defineProperty(o, k2, desc);
|
|
16
|
-
}) : (function(o, m, k, k2) {
|
|
17
|
-
if (k2 === undefined) k2 = k;
|
|
18
|
-
o[k2] = m[k];
|
|
19
|
-
}));
|
|
20
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
-
}) : function(o, v) {
|
|
23
|
-
o["default"] = v;
|
|
24
|
-
});
|
|
25
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
-
var ownKeys = function(o) {
|
|
27
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
-
var ar = [];
|
|
29
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
-
return ar;
|
|
31
|
-
};
|
|
32
|
-
return ownKeys(o);
|
|
33
|
-
};
|
|
34
|
-
return function (mod) {
|
|
35
|
-
if (mod && mod.__esModule) return mod;
|
|
36
|
-
var result = {};
|
|
37
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
-
__setModuleDefault(result, mod);
|
|
39
|
-
return result;
|
|
40
|
-
};
|
|
41
|
-
})();
|
|
42
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
43
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
44
|
-
};
|
|
45
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.execute = execute;
|
|
47
|
-
exports.writeTestFiles = writeTestFiles;
|
|
48
|
-
const build_1 = require("@angular/build");
|
|
49
|
-
const private_1 = require("@angular/build/private");
|
|
50
|
-
const crypto_1 = require("crypto");
|
|
51
|
-
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
52
|
-
const fs = __importStar(require("fs/promises"));
|
|
53
|
-
const path = __importStar(require("path"));
|
|
54
|
-
const rxjs_1 = require("rxjs");
|
|
55
|
-
const schema_1 = require("../browser-esbuild/schema");
|
|
56
|
-
const find_tests_1 = require("./find-tests");
|
|
57
|
-
class ApplicationBuildError extends Error {
|
|
58
|
-
constructor(message) {
|
|
59
|
-
super(message);
|
|
60
|
-
this.name = 'ApplicationBuildError';
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
const LATEST_BUILD_FILES_TOKEN = 'angularLatestBuildFiles';
|
|
64
|
-
class AngularAssetsMiddleware {
|
|
65
|
-
serveFile;
|
|
66
|
-
latestBuildFiles;
|
|
67
|
-
static $inject = ['serveFile', LATEST_BUILD_FILES_TOKEN];
|
|
68
|
-
static NAME = 'angular-test-assets';
|
|
69
|
-
constructor(serveFile, latestBuildFiles) {
|
|
70
|
-
this.serveFile = serveFile;
|
|
71
|
-
this.latestBuildFiles = latestBuildFiles;
|
|
72
|
-
}
|
|
73
|
-
handle(req, res, next) {
|
|
74
|
-
let err = null;
|
|
75
|
-
try {
|
|
76
|
-
const url = new URL(`http://${req.headers['host']}${req.url}`);
|
|
77
|
-
const file = this.latestBuildFiles.files[url.pathname.slice(1)];
|
|
78
|
-
if (file?.origin === 'disk') {
|
|
79
|
-
this.serveFile(file.inputPath, undefined, res);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
else if (file?.origin === 'memory') {
|
|
83
|
-
// Include pathname to help with Content-Type headers.
|
|
84
|
-
this.serveFile(`/unused/${url.pathname}`, undefined, res, undefined, file.contents, true);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch (e) {
|
|
89
|
-
err = e;
|
|
90
|
-
}
|
|
91
|
-
next(err);
|
|
92
|
-
}
|
|
93
|
-
static createPlugin(initialFiles) {
|
|
94
|
-
return {
|
|
95
|
-
[LATEST_BUILD_FILES_TOKEN]: ['value', { files: { ...initialFiles.files } }],
|
|
96
|
-
[`middleware:${AngularAssetsMiddleware.NAME}`]: [
|
|
97
|
-
'factory',
|
|
98
|
-
Object.assign((...args) => {
|
|
99
|
-
const inst = new AngularAssetsMiddleware(...args);
|
|
100
|
-
return inst.handle.bind(inst);
|
|
101
|
-
}, AngularAssetsMiddleware),
|
|
102
|
-
],
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
class AngularPolyfillsPlugin {
|
|
107
|
-
static $inject = ['config.files'];
|
|
108
|
-
static NAME = 'angular-polyfills';
|
|
109
|
-
static createPlugin(polyfillsFile, jasmineCleanupFiles) {
|
|
110
|
-
return {
|
|
111
|
-
// This has to be a "reporter" because reporters run _after_ frameworks
|
|
112
|
-
// and karma-jasmine-html-reporter injects additional scripts that may
|
|
113
|
-
// depend on Jasmine but aren't modules - which means that they would run
|
|
114
|
-
// _before_ all module code (including jasmine).
|
|
115
|
-
[`reporter:${AngularPolyfillsPlugin.NAME}`]: [
|
|
116
|
-
'factory',
|
|
117
|
-
Object.assign((files) => {
|
|
118
|
-
// The correct order is zone.js -> jasmine -> zone.js/testing.
|
|
119
|
-
// Jasmine has to see the patched version of the global `setTimeout`
|
|
120
|
-
// function so it doesn't cache the unpatched version. And /testing
|
|
121
|
-
// needs to see the global `jasmine` object so it can patch it.
|
|
122
|
-
const polyfillsIndex = 0;
|
|
123
|
-
files.splice(polyfillsIndex, 0, polyfillsFile);
|
|
124
|
-
// Insert just before test_main.js.
|
|
125
|
-
const zoneTestingIndex = files.findIndex((f) => {
|
|
126
|
-
if (typeof f === 'string') {
|
|
127
|
-
return false;
|
|
128
|
-
}
|
|
129
|
-
return f.pattern.endsWith('/test_main.js');
|
|
130
|
-
});
|
|
131
|
-
if (zoneTestingIndex === -1) {
|
|
132
|
-
throw new Error('Could not find test entrypoint file.');
|
|
133
|
-
}
|
|
134
|
-
files.splice(zoneTestingIndex, 0, jasmineCleanupFiles);
|
|
135
|
-
// We need to ensure that all files are served as modules, otherwise
|
|
136
|
-
// the order in the files list gets really confusing: Karma doesn't
|
|
137
|
-
// set defer on scripts, so all scripts with type=js will run first,
|
|
138
|
-
// even if type=module files appeared earlier in `files`.
|
|
139
|
-
for (const f of files) {
|
|
140
|
-
if (typeof f === 'string') {
|
|
141
|
-
throw new Error(`Unexpected string-based file: "${f}"`);
|
|
142
|
-
}
|
|
143
|
-
if (f.included === false) {
|
|
144
|
-
// Don't worry about files that aren't included on the initial
|
|
145
|
-
// page load. `type` won't affect them.
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
if (f.pattern.endsWith('.js') && 'js' === (f.type ?? 'js')) {
|
|
149
|
-
f.type = 'module';
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}, AngularPolyfillsPlugin),
|
|
153
|
-
],
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
function injectKarmaReporter(buildOptions, buildIterator, karmaConfig, subscriber) {
|
|
158
|
-
const reporterName = 'angular-progress-notifier';
|
|
159
|
-
class ProgressNotifierReporter {
|
|
160
|
-
emitter;
|
|
161
|
-
latestBuildFiles;
|
|
162
|
-
static $inject = ['emitter', LATEST_BUILD_FILES_TOKEN];
|
|
163
|
-
constructor(emitter, latestBuildFiles) {
|
|
164
|
-
this.emitter = emitter;
|
|
165
|
-
this.latestBuildFiles = latestBuildFiles;
|
|
166
|
-
this.startWatchingBuild();
|
|
167
|
-
}
|
|
168
|
-
startWatchingBuild() {
|
|
169
|
-
void (async () => {
|
|
170
|
-
// This is effectively "for await of but skip what's already consumed".
|
|
171
|
-
let isDone = false; // to mark the loop condition as "not constant".
|
|
172
|
-
while (!isDone) {
|
|
173
|
-
const { done, value: buildOutput } = await buildIterator.next();
|
|
174
|
-
if (done) {
|
|
175
|
-
isDone = true;
|
|
176
|
-
break;
|
|
177
|
-
}
|
|
178
|
-
if (buildOutput.kind === private_1.ResultKind.Failure) {
|
|
179
|
-
subscriber.next({ success: false, message: 'Build failed' });
|
|
180
|
-
}
|
|
181
|
-
else if (buildOutput.kind === private_1.ResultKind.Incremental ||
|
|
182
|
-
buildOutput.kind === private_1.ResultKind.Full) {
|
|
183
|
-
if (buildOutput.kind === private_1.ResultKind.Full) {
|
|
184
|
-
this.latestBuildFiles.files = buildOutput.files;
|
|
185
|
-
}
|
|
186
|
-
else {
|
|
187
|
-
this.latestBuildFiles.files = {
|
|
188
|
-
...this.latestBuildFiles.files,
|
|
189
|
-
...buildOutput.files,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
await writeTestFiles(buildOutput.files, buildOptions.outputPath);
|
|
193
|
-
this.emitter.refreshFiles();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
})();
|
|
197
|
-
}
|
|
198
|
-
onRunComplete = function (_browsers, results) {
|
|
199
|
-
if (results.exitCode === 0) {
|
|
200
|
-
subscriber.next({ success: true });
|
|
201
|
-
}
|
|
202
|
-
else {
|
|
203
|
-
subscriber.next({ success: false });
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
karmaConfig.reporters ??= [];
|
|
208
|
-
karmaConfig.reporters.push(reporterName);
|
|
209
|
-
karmaConfig.plugins ??= [];
|
|
210
|
-
karmaConfig.plugins.push({
|
|
211
|
-
[`reporter:${reporterName}`]: [
|
|
212
|
-
'factory',
|
|
213
|
-
Object.assign((...args) => new ProgressNotifierReporter(...args), ProgressNotifierReporter),
|
|
214
|
-
],
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
function execute(options, context, karmaOptions, transforms = {}) {
|
|
218
|
-
return (0, rxjs_1.from)(initializeApplication(options, context, karmaOptions, transforms)).pipe((0, rxjs_1.switchMap)(([karma, karmaConfig, buildOptions, buildIterator]) => new rxjs_1.Observable((subscriber) => {
|
|
219
|
-
// If `--watch` is explicitly enabled or if we are keeping the Karma
|
|
220
|
-
// process running, we should hook Karma into the build.
|
|
221
|
-
if (buildIterator) {
|
|
222
|
-
injectKarmaReporter(buildOptions, buildIterator, karmaConfig, subscriber);
|
|
223
|
-
}
|
|
224
|
-
// Complete the observable once the Karma server returns.
|
|
225
|
-
const karmaServer = new karma.Server(karmaConfig, (exitCode) => {
|
|
226
|
-
subscriber.next({ success: exitCode === 0 });
|
|
227
|
-
subscriber.complete();
|
|
228
|
-
});
|
|
229
|
-
const karmaStart = karmaServer.start();
|
|
230
|
-
// Cleanup, signal Karma to exit.
|
|
231
|
-
return () => {
|
|
232
|
-
void karmaStart.then(() => karmaServer.stop());
|
|
233
|
-
};
|
|
234
|
-
})), (0, rxjs_1.catchError)((err) => {
|
|
235
|
-
if (err instanceof ApplicationBuildError) {
|
|
236
|
-
return (0, rxjs_1.of)({ success: false, message: err.message });
|
|
237
|
-
}
|
|
238
|
-
throw err;
|
|
239
|
-
}), (0, rxjs_1.defaultIfEmpty)({ success: false }));
|
|
240
|
-
}
|
|
241
|
-
async function getProjectSourceRoot(context) {
|
|
242
|
-
// We have already validated that the project name is set before calling this function.
|
|
243
|
-
const projectName = context.target?.project;
|
|
244
|
-
if (!projectName) {
|
|
245
|
-
return context.workspaceRoot;
|
|
246
|
-
}
|
|
247
|
-
const projectMetadata = await context.getProjectMetadata(projectName);
|
|
248
|
-
const sourceRoot = (projectMetadata.sourceRoot ?? projectMetadata.root ?? '');
|
|
249
|
-
return path.join(context.workspaceRoot, sourceRoot);
|
|
250
|
-
}
|
|
251
|
-
function normalizePolyfills(polyfills) {
|
|
252
|
-
if (typeof polyfills === 'string') {
|
|
253
|
-
polyfills = [polyfills];
|
|
254
|
-
}
|
|
255
|
-
else if (!polyfills) {
|
|
256
|
-
polyfills = [];
|
|
257
|
-
}
|
|
258
|
-
const jasmineGlobalEntryPoint = '@angular-devkit/build-angular/src/builders/karma/jasmine_global.js';
|
|
259
|
-
const jasmineGlobalCleanupEntrypoint = '@angular-devkit/build-angular/src/builders/karma/jasmine_global_cleanup.js';
|
|
260
|
-
const zoneTestingEntryPoint = 'zone.js/testing';
|
|
261
|
-
const polyfillsExludingZoneTesting = polyfills.filter((p) => p !== zoneTestingEntryPoint);
|
|
262
|
-
return [
|
|
263
|
-
polyfillsExludingZoneTesting.concat([jasmineGlobalEntryPoint]),
|
|
264
|
-
polyfillsExludingZoneTesting.length === polyfills.length
|
|
265
|
-
? [jasmineGlobalCleanupEntrypoint]
|
|
266
|
-
: [jasmineGlobalCleanupEntrypoint, zoneTestingEntryPoint],
|
|
267
|
-
];
|
|
268
|
-
}
|
|
269
|
-
async function collectEntrypoints(options, context, projectSourceRoot) {
|
|
270
|
-
// Glob for files to test.
|
|
271
|
-
const testFiles = await (0, find_tests_1.findTests)(options.include ?? [], options.exclude ?? [], context.workspaceRoot, projectSourceRoot);
|
|
272
|
-
return (0, find_tests_1.getTestEntrypoints)(testFiles, { projectSourceRoot, workspaceRoot: context.workspaceRoot });
|
|
273
|
-
}
|
|
274
|
-
async function initializeApplication(options, context, karmaOptions, transforms = {}) {
|
|
275
|
-
if (transforms.webpackConfiguration) {
|
|
276
|
-
context.logger.warn(`This build is using the application builder but transforms.webpackConfiguration was provided. The transform will be ignored.`);
|
|
277
|
-
}
|
|
278
|
-
const outputPath = path.join(context.workspaceRoot, 'dist/test-out', (0, crypto_1.randomUUID)());
|
|
279
|
-
const projectSourceRoot = await getProjectSourceRoot(context);
|
|
280
|
-
const [karma, entryPoints] = await Promise.all([
|
|
281
|
-
Promise.resolve().then(() => __importStar(require('karma'))),
|
|
282
|
-
collectEntrypoints(options, context, projectSourceRoot),
|
|
283
|
-
fs.rm(outputPath, { recursive: true, force: true }),
|
|
284
|
-
]);
|
|
285
|
-
const mainName = 'test_main';
|
|
286
|
-
if (options.main) {
|
|
287
|
-
entryPoints.set(mainName, options.main);
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
entryPoints.set(mainName, '@angular-devkit/build-angular/src/builders/karma/init_test_bed.js');
|
|
291
|
-
}
|
|
292
|
-
const instrumentForCoverage = options.codeCoverage
|
|
293
|
-
? createInstrumentationFilter(projectSourceRoot, getInstrumentationExcludedPaths(context.workspaceRoot, options.codeCoverageExclude ?? []))
|
|
294
|
-
: undefined;
|
|
295
|
-
const [polyfills, jasmineCleanup] = normalizePolyfills(options.polyfills);
|
|
296
|
-
for (let idx = 0; idx < jasmineCleanup.length; ++idx) {
|
|
297
|
-
entryPoints.set(`jasmine-cleanup-${idx}`, jasmineCleanup[idx]);
|
|
298
|
-
}
|
|
299
|
-
const buildOptions = {
|
|
300
|
-
assets: options.assets,
|
|
301
|
-
entryPoints,
|
|
302
|
-
tsConfig: options.tsConfig,
|
|
303
|
-
outputPath,
|
|
304
|
-
aot: options.aot,
|
|
305
|
-
index: false,
|
|
306
|
-
outputHashing: schema_1.OutputHashing.None,
|
|
307
|
-
optimization: false,
|
|
308
|
-
sourceMap: {
|
|
309
|
-
scripts: true,
|
|
310
|
-
styles: true,
|
|
311
|
-
vendor: true,
|
|
312
|
-
},
|
|
313
|
-
instrumentForCoverage,
|
|
314
|
-
styles: options.styles,
|
|
315
|
-
polyfills,
|
|
316
|
-
webWorkerTsConfig: options.webWorkerTsConfig,
|
|
317
|
-
watch: options.watch ?? !karmaOptions.singleRun,
|
|
318
|
-
stylePreprocessorOptions: options.stylePreprocessorOptions,
|
|
319
|
-
};
|
|
320
|
-
// Build tests with `application` builder, using test files as entry points.
|
|
321
|
-
const [buildOutput, buildIterator] = await first((0, private_1.buildApplicationInternal)(buildOptions, context), { cancel: !buildOptions.watch });
|
|
322
|
-
if (buildOutput.kind === private_1.ResultKind.Failure) {
|
|
323
|
-
throw new ApplicationBuildError('Build failed');
|
|
324
|
-
}
|
|
325
|
-
else if (buildOutput.kind !== private_1.ResultKind.Full) {
|
|
326
|
-
throw new ApplicationBuildError('A full build result is required from the application builder.');
|
|
327
|
-
}
|
|
328
|
-
// Write test files
|
|
329
|
-
await writeTestFiles(buildOutput.files, buildOptions.outputPath);
|
|
330
|
-
// We need to add this to the beginning *after* the testing framework has
|
|
331
|
-
// prepended its files.
|
|
332
|
-
const polyfillsFile = {
|
|
333
|
-
pattern: `${outputPath}/polyfills.js`,
|
|
334
|
-
included: true,
|
|
335
|
-
served: true,
|
|
336
|
-
type: 'module',
|
|
337
|
-
watched: false,
|
|
338
|
-
};
|
|
339
|
-
const jasmineCleanupFiles = {
|
|
340
|
-
pattern: `${outputPath}/jasmine-cleanup-*.js`,
|
|
341
|
-
included: true,
|
|
342
|
-
served: true,
|
|
343
|
-
type: 'module',
|
|
344
|
-
watched: false,
|
|
345
|
-
};
|
|
346
|
-
karmaOptions.files ??= [];
|
|
347
|
-
karmaOptions.files.push(
|
|
348
|
-
// Serve global setup script.
|
|
349
|
-
{ pattern: `${outputPath}/${mainName}.js`, type: 'module', watched: false },
|
|
350
|
-
// Serve all source maps.
|
|
351
|
-
{ pattern: `${outputPath}/*.map`, included: false, watched: false },
|
|
352
|
-
// These are the test entrypoints.
|
|
353
|
-
{ pattern: `${outputPath}/spec-*.js`, type: 'module', watched: false });
|
|
354
|
-
if (hasChunkOrWorkerFiles(buildOutput.files)) {
|
|
355
|
-
karmaOptions.files.push(
|
|
356
|
-
// Allow loading of chunk-* files but don't include them all on load.
|
|
357
|
-
{
|
|
358
|
-
pattern: `${outputPath}/{chunk,worker}-*.js`,
|
|
359
|
-
type: 'module',
|
|
360
|
-
included: false,
|
|
361
|
-
watched: false,
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
|
-
if (options.styles?.length) {
|
|
365
|
-
// Serve CSS outputs on page load, these are the global styles.
|
|
366
|
-
karmaOptions.files.push({ pattern: `${outputPath}/*.css`, type: 'css', watched: false });
|
|
367
|
-
}
|
|
368
|
-
const parsedKarmaConfig = await karma.config.parseConfig(options.karmaConfig && path.resolve(context.workspaceRoot, options.karmaConfig), transforms.karmaOptions ? transforms.karmaOptions(karmaOptions) : karmaOptions, { promiseConfig: true, throwErrors: true });
|
|
369
|
-
// Remove the webpack plugin/framework:
|
|
370
|
-
// Alternative would be to make the Karma plugin "smart" but that's a tall order
|
|
371
|
-
// with managing unneeded imports etc..
|
|
372
|
-
parsedKarmaConfig.plugins ??= [];
|
|
373
|
-
const pluginLengthBefore = parsedKarmaConfig.plugins.length;
|
|
374
|
-
parsedKarmaConfig.plugins = parsedKarmaConfig.plugins.filter((plugin) => {
|
|
375
|
-
if (typeof plugin === 'string') {
|
|
376
|
-
return plugin !== 'framework:@angular-devkit/build-angular';
|
|
377
|
-
}
|
|
378
|
-
return !plugin['framework:@angular-devkit/build-angular'];
|
|
379
|
-
});
|
|
380
|
-
parsedKarmaConfig.frameworks ??= [];
|
|
381
|
-
parsedKarmaConfig.frameworks = parsedKarmaConfig.frameworks.filter((framework) => framework !== '@angular-devkit/build-angular');
|
|
382
|
-
const pluginLengthAfter = parsedKarmaConfig.plugins.length;
|
|
383
|
-
if (pluginLengthBefore !== pluginLengthAfter) {
|
|
384
|
-
context.logger.warn(`Ignoring framework "@angular-devkit/build-angular" from karma config file because it's not compatible with the application builder.`);
|
|
385
|
-
}
|
|
386
|
-
parsedKarmaConfig.plugins.push(AngularAssetsMiddleware.createPlugin(buildOutput));
|
|
387
|
-
parsedKarmaConfig.middleware ??= [];
|
|
388
|
-
parsedKarmaConfig.middleware.push(AngularAssetsMiddleware.NAME);
|
|
389
|
-
parsedKarmaConfig.plugins.push(AngularPolyfillsPlugin.createPlugin(polyfillsFile, jasmineCleanupFiles));
|
|
390
|
-
parsedKarmaConfig.reporters ??= [];
|
|
391
|
-
parsedKarmaConfig.reporters.push(AngularPolyfillsPlugin.NAME);
|
|
392
|
-
// When using code-coverage, auto-add karma-coverage.
|
|
393
|
-
// This was done as part of the karma plugin for webpack.
|
|
394
|
-
if (options.codeCoverage &&
|
|
395
|
-
!parsedKarmaConfig.reporters?.some((r) => r === 'coverage' || r === 'coverage-istanbul')) {
|
|
396
|
-
parsedKarmaConfig.reporters = (parsedKarmaConfig.reporters ?? []).concat(['coverage']);
|
|
397
|
-
}
|
|
398
|
-
return [karma, parsedKarmaConfig, buildOptions, buildIterator];
|
|
399
|
-
}
|
|
400
|
-
function hasChunkOrWorkerFiles(files) {
|
|
401
|
-
return Object.keys(files).some((filename) => {
|
|
402
|
-
return /(?:^|\/)(?:worker|chunk)[^/]+\.js$/.test(filename);
|
|
403
|
-
});
|
|
404
|
-
}
|
|
405
|
-
async function writeTestFiles(files, testDir) {
|
|
406
|
-
const directoryExists = new Set();
|
|
407
|
-
// Writes the test related output files to disk and ensures the containing directories are present
|
|
408
|
-
await (0, private_1.emitFilesToDisk)(Object.entries(files), async ([filePath, file]) => {
|
|
409
|
-
if (file.type !== build_1.BuildOutputFileType.Browser && file.type !== build_1.BuildOutputFileType.Media) {
|
|
410
|
-
return;
|
|
411
|
-
}
|
|
412
|
-
const fullFilePath = path.join(testDir, filePath);
|
|
413
|
-
// Ensure output subdirectories exist
|
|
414
|
-
const fileBasePath = path.dirname(fullFilePath);
|
|
415
|
-
if (fileBasePath && !directoryExists.has(fileBasePath)) {
|
|
416
|
-
await fs.mkdir(fileBasePath, { recursive: true });
|
|
417
|
-
directoryExists.add(fileBasePath);
|
|
418
|
-
}
|
|
419
|
-
if (file.origin === 'memory') {
|
|
420
|
-
// Write file contents
|
|
421
|
-
await fs.writeFile(fullFilePath, file.contents);
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
// Copy file contents
|
|
425
|
-
await fs.copyFile(file.inputPath, fullFilePath, fs.constants.COPYFILE_FICLONE);
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
/** Returns the first item yielded by the given generator and cancels the execution. */
|
|
430
|
-
async function first(generator, { cancel }) {
|
|
431
|
-
if (!cancel) {
|
|
432
|
-
const iterator = generator[Symbol.asyncIterator]();
|
|
433
|
-
const firstValue = await iterator.next();
|
|
434
|
-
if (firstValue.done) {
|
|
435
|
-
throw new Error('Expected generator to emit at least once.');
|
|
436
|
-
}
|
|
437
|
-
return [firstValue.value, iterator];
|
|
438
|
-
}
|
|
439
|
-
for await (const value of generator) {
|
|
440
|
-
return [value, null];
|
|
441
|
-
}
|
|
442
|
-
throw new Error('Expected generator to emit at least once.');
|
|
443
|
-
}
|
|
444
|
-
function createInstrumentationFilter(includedBasePath, excludedPaths) {
|
|
445
|
-
return (request) => {
|
|
446
|
-
return (!excludedPaths.has(request) &&
|
|
447
|
-
!/\.(e2e|spec)\.tsx?$|[\\/]node_modules[\\/]/.test(request) &&
|
|
448
|
-
request.startsWith(includedBasePath));
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
function getInstrumentationExcludedPaths(root, excludedPaths) {
|
|
452
|
-
const excluded = new Set();
|
|
453
|
-
for (const excludeGlob of excludedPaths) {
|
|
454
|
-
const excludePath = excludeGlob[0] === '/' ? excludeGlob.slice(1) : excludeGlob;
|
|
455
|
-
fast_glob_1.default.sync(excludePath, { cwd: root }).forEach((p) => excluded.add(path.join(root, p)));
|
|
456
|
-
}
|
|
457
|
-
return excluded;
|
|
458
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
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
|
-
export declare function findTests(include: string[], exclude: string[], workspaceRoot: string, projectSourceRoot: string): Promise<string[]>;
|
|
9
|
-
interface TestEntrypointsOptions {
|
|
10
|
-
projectSourceRoot: string;
|
|
11
|
-
workspaceRoot: string;
|
|
12
|
-
}
|
|
13
|
-
/** Generate unique bundle names for a set of test files. */
|
|
14
|
-
export declare function getTestEntrypoints(testFiles: string[], { projectSourceRoot, workspaceRoot }: TestEntrypointsOptions): Map<string, string>;
|
|
15
|
-
export {};
|
|
@@ -1,144 +0,0 @@
|
|
|
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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
-
}
|
|
15
|
-
Object.defineProperty(o, k2, desc);
|
|
16
|
-
}) : (function(o, m, k, k2) {
|
|
17
|
-
if (k2 === undefined) k2 = k;
|
|
18
|
-
o[k2] = m[k];
|
|
19
|
-
}));
|
|
20
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
-
}) : function(o, v) {
|
|
23
|
-
o["default"] = v;
|
|
24
|
-
});
|
|
25
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
-
var ownKeys = function(o) {
|
|
27
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
-
var ar = [];
|
|
29
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
-
return ar;
|
|
31
|
-
};
|
|
32
|
-
return ownKeys(o);
|
|
33
|
-
};
|
|
34
|
-
return function (mod) {
|
|
35
|
-
if (mod && mod.__esModule) return mod;
|
|
36
|
-
var result = {};
|
|
37
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
-
__setModuleDefault(result, mod);
|
|
39
|
-
return result;
|
|
40
|
-
};
|
|
41
|
-
})();
|
|
42
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
-
exports.findTests = findTests;
|
|
44
|
-
exports.getTestEntrypoints = getTestEntrypoints;
|
|
45
|
-
const fast_glob_1 = __importStar(require("fast-glob"));
|
|
46
|
-
const fs_1 = require("fs");
|
|
47
|
-
const path_1 = require("path");
|
|
48
|
-
/* Go through all patterns and find unique list of files */
|
|
49
|
-
async function findTests(include, exclude, workspaceRoot, projectSourceRoot) {
|
|
50
|
-
const matchingTestsPromises = include.map((pattern) => findMatchingTests(pattern, exclude, workspaceRoot, projectSourceRoot));
|
|
51
|
-
const files = await Promise.all(matchingTestsPromises);
|
|
52
|
-
// Unique file names
|
|
53
|
-
return [...new Set(files.flat())];
|
|
54
|
-
}
|
|
55
|
-
/** Generate unique bundle names for a set of test files. */
|
|
56
|
-
function getTestEntrypoints(testFiles, { projectSourceRoot, workspaceRoot }) {
|
|
57
|
-
const seen = new Set();
|
|
58
|
-
return new Map(Array.from(testFiles, (testFile) => {
|
|
59
|
-
const relativePath = removeRoots(testFile, [projectSourceRoot, workspaceRoot])
|
|
60
|
-
// Strip leading dots and path separators.
|
|
61
|
-
.replace(/^[./\\]+/, '')
|
|
62
|
-
// Replace any path separators with dashes.
|
|
63
|
-
.replace(/[/\\]/g, '-');
|
|
64
|
-
const baseName = `spec-${(0, path_1.basename)(relativePath, (0, path_1.extname)(relativePath))}`;
|
|
65
|
-
let uniqueName = baseName;
|
|
66
|
-
let suffix = 2;
|
|
67
|
-
while (seen.has(uniqueName)) {
|
|
68
|
-
uniqueName = `${baseName}-${suffix}`.replace(/([^\w](?:spec|test))-([\d]+)$/, '-$2$1');
|
|
69
|
-
++suffix;
|
|
70
|
-
}
|
|
71
|
-
seen.add(uniqueName);
|
|
72
|
-
return [uniqueName, testFile];
|
|
73
|
-
}));
|
|
74
|
-
}
|
|
75
|
-
const normalizePath = (path) => path.replace(/\\/g, '/');
|
|
76
|
-
const removeLeadingSlash = (pattern) => {
|
|
77
|
-
if (pattern.charAt(0) === '/') {
|
|
78
|
-
return pattern.substring(1);
|
|
79
|
-
}
|
|
80
|
-
return pattern;
|
|
81
|
-
};
|
|
82
|
-
const removeRelativeRoot = (path, root) => {
|
|
83
|
-
if (path.startsWith(root)) {
|
|
84
|
-
return path.substring(root.length);
|
|
85
|
-
}
|
|
86
|
-
return path;
|
|
87
|
-
};
|
|
88
|
-
function removeRoots(path, roots) {
|
|
89
|
-
for (const root of roots) {
|
|
90
|
-
if (path.startsWith(root)) {
|
|
91
|
-
return path.substring(root.length);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return (0, path_1.basename)(path);
|
|
95
|
-
}
|
|
96
|
-
async function findMatchingTests(pattern, ignore, workspaceRoot, projectSourceRoot) {
|
|
97
|
-
// normalize pattern, glob lib only accepts forward slashes
|
|
98
|
-
let normalizedPattern = normalizePath(pattern);
|
|
99
|
-
normalizedPattern = removeLeadingSlash(normalizedPattern);
|
|
100
|
-
const relativeProjectRoot = normalizePath((0, path_1.relative)(workspaceRoot, projectSourceRoot) + '/');
|
|
101
|
-
// remove relativeProjectRoot to support relative paths from root
|
|
102
|
-
// such paths are easy to get when running scripts via IDEs
|
|
103
|
-
normalizedPattern = removeRelativeRoot(normalizedPattern, relativeProjectRoot);
|
|
104
|
-
// special logic when pattern does not look like a glob
|
|
105
|
-
if (!(0, fast_glob_1.isDynamicPattern)(normalizedPattern)) {
|
|
106
|
-
if (await isDirectory((0, path_1.join)(projectSourceRoot, normalizedPattern))) {
|
|
107
|
-
normalizedPattern = `${normalizedPattern}/**/*.spec.@(ts|tsx)`;
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
// see if matching spec file exists
|
|
111
|
-
const fileExt = (0, path_1.extname)(normalizedPattern);
|
|
112
|
-
// Replace extension to `.spec.ext`. Example: `src/app/app.component.ts`-> `src/app/app.component.spec.ts`
|
|
113
|
-
const potentialSpec = (0, path_1.join)(projectSourceRoot, (0, path_1.dirname)(normalizedPattern), `${(0, path_1.basename)(normalizedPattern, fileExt)}.spec${fileExt}`);
|
|
114
|
-
if (await exists(potentialSpec)) {
|
|
115
|
-
return [potentialSpec];
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
// normalize the patterns in the ignore list
|
|
120
|
-
const normalizedIgnorePatternList = ignore.map((pattern) => removeRelativeRoot(removeLeadingSlash(normalizePath(pattern)), relativeProjectRoot));
|
|
121
|
-
return (0, fast_glob_1.default)(normalizedPattern, {
|
|
122
|
-
cwd: projectSourceRoot,
|
|
123
|
-
absolute: true,
|
|
124
|
-
ignore: ['**/node_modules/**', ...normalizedIgnorePatternList],
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
async function isDirectory(path) {
|
|
128
|
-
try {
|
|
129
|
-
const stats = await fs_1.promises.stat(path);
|
|
130
|
-
return stats.isDirectory();
|
|
131
|
-
}
|
|
132
|
-
catch {
|
|
133
|
-
return false;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
async function exists(path) {
|
|
137
|
-
try {
|
|
138
|
-
await fs_1.promises.access(path, fs_1.constants.F_OK);
|
|
139
|
-
return true;
|
|
140
|
-
}
|
|
141
|
-
catch {
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
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 { getTestBed } from '@angular/core/testing';
|
|
10
|
-
import {
|
|
11
|
-
BrowserDynamicTestingModule,
|
|
12
|
-
platformBrowserDynamicTesting,
|
|
13
|
-
} from '@angular/platform-browser-dynamic/testing';
|
|
14
|
-
|
|
15
|
-
// Initialize the Angular testing environment.
|
|
16
|
-
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), {
|
|
17
|
-
errorOnUnknownElements: true,
|
|
18
|
-
errorOnUnknownProperties: true,
|
|
19
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
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
|
-
// See: https://github.com/jasmine/jasmine/issues/2015
|
|
10
|
-
(function () {
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
// jasmine will ignore `window` unless it returns this specific (but uncommon)
|
|
14
|
-
// value from toString().
|
|
15
|
-
window.toString = function () {
|
|
16
|
-
return '[object GjsGlobal]';
|
|
17
|
-
};
|
|
18
|
-
})();
|
|
@@ -1,14 +0,0 @@
|
|
|
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
|
-
// See: https://github.com/jasmine/jasmine/issues/2015
|
|
10
|
-
(function () {
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
delete window.toString;
|
|
14
|
-
})();
|