Skip to content

Commit 488e29d

Browse files
author
Angular Builds
committed
a9a3470 fix(@angular-devkit/build-angular): jasmine.clock with app builder
1 parent 3bb4202 commit 488e29d

File tree

6 files changed

+131
-15
lines changed

6 files changed

+131
-15
lines changed

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
{
22
"name": "@angular-devkit/build-angular",
3-
"version": "19.1.0-next.1+sha-8d35b9b",
3+
"version": "19.1.0-next.1+sha-a9a3470",
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#8d35b9b",
11-
"@angular-devkit/build-webpack": "github:angular/angular-devkit-build-webpack-builds#8d35b9b",
12-
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#8d35b9b",
13-
"@angular/build": "github:angular/angular-build-builds#8d35b9b",
10+
"@angular-devkit/architect": "github:angular/angular-devkit-architect-builds#a9a3470",
11+
"@angular-devkit/build-webpack": "github:angular/angular-devkit-build-webpack-builds#a9a3470",
12+
"@angular-devkit/core": "github:angular/angular-devkit-core-builds#a9a3470",
13+
"@angular/build": "github:angular/angular-build-builds#a9a3470",
1414
"@babel/core": "7.26.0",
1515
"@babel/generator": "7.26.3",
1616
"@babel/helper-annotate-as-pure": "7.25.9",
@@ -21,7 +21,7 @@
2121
"@babel/preset-env": "7.26.0",
2222
"@babel/runtime": "7.26.0",
2323
"@discoveryjs/json-ext": "0.6.3",
24-
"@ngtools/webpack": "github:angular/ngtools-webpack-builds#8d35b9b",
24+
"@ngtools/webpack": "github:angular/ngtools-webpack-builds#a9a3470",
2525
"@vitejs/plugin-basic-ssl": "1.2.0",
2626
"ansi-colors": "4.1.3",
2727
"autoprefixer": "10.4.20",
@@ -70,7 +70,7 @@
7070
"@angular/localize": "^19.0.0 || ^19.1.0-next.0",
7171
"@angular/platform-server": "^19.0.0 || ^19.1.0-next.0",
7272
"@angular/service-worker": "^19.0.0 || ^19.1.0-next.0",
73-
"@angular/ssr": "github:angular/angular-ssr-builds#8d35b9b",
73+
"@angular/ssr": "github:angular/angular-ssr-builds#a9a3470",
7474
"@web/test-runner": "^0.19.0",
7575
"browser-sync": "^3.0.2",
7676
"jest": "^29.5.0",
@@ -91,7 +91,7 @@
9191
"@angular/service-worker": {
9292
"optional": true
9393
},
94-
"@angular/ssr": "github:angular/angular-ssr-builds#8d35b9b",
94+
"@angular/ssr": "github:angular/angular-ssr-builds#a9a3470",
9595
"@web/test-runner": {
9696
"optional": true
9797
},

src/builders/karma/application_builder.js

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,57 @@ class AngularAssetsMiddleware {
103103
};
104104
}
105105
}
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 ('js' === (f.type ?? 'js')) {
149+
f.type = 'module';
150+
}
151+
}
152+
}, AngularPolyfillsPlugin),
153+
],
154+
};
155+
}
156+
}
106157
function injectKarmaReporter(buildOptions, buildIterator, karmaConfig, subscriber) {
107158
const reporterName = 'angular-progress-notifier';
108159
class ProgressNotifierReporter {
@@ -199,9 +250,21 @@ async function getProjectSourceRoot(context) {
199250
}
200251
function normalizePolyfills(polyfills) {
201252
if (typeof polyfills === 'string') {
202-
return [polyfills];
253+
polyfills = [polyfills];
203254
}
204-
return polyfills ?? [];
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+
];
205268
}
206269
async function collectEntrypoints(options, context, projectSourceRoot) {
207270
// Glob for files to test.
@@ -229,6 +292,10 @@ async function initializeApplication(options, context, karmaOptions, transforms
229292
const instrumentForCoverage = options.codeCoverage
230293
? createInstrumentationFilter(projectSourceRoot, getInstrumentationExcludedPaths(context.workspaceRoot, options.codeCoverageExclude ?? []))
231294
: 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+
}
232299
const buildOptions = {
233300
assets: options.assets,
234301
entryPoints,
@@ -245,7 +312,7 @@ async function initializeApplication(options, context, karmaOptions, transforms
245312
},
246313
instrumentForCoverage,
247314
styles: options.styles,
248-
polyfills: normalizePolyfills(options.polyfills),
315+
polyfills,
249316
webWorkerTsConfig: options.webWorkerTsConfig,
250317
watch: options.watch ?? !karmaOptions.singleRun,
251318
stylePreprocessorOptions: options.stylePreprocessorOptions,
@@ -260,10 +327,24 @@ async function initializeApplication(options, context, karmaOptions, transforms
260327
}
261328
// Write test files
262329
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+
};
263346
karmaOptions.files ??= [];
264347
karmaOptions.files.push(
265-
// Serve polyfills first.
266-
{ pattern: `${outputPath}/polyfills.js`, type: 'module', watched: false },
267348
// Serve global setup script.
268349
{ pattern: `${outputPath}/${mainName}.js`, type: 'module', watched: false },
269350
// Serve all source maps.
@@ -305,6 +386,9 @@ async function initializeApplication(options, context, karmaOptions, transforms
305386
parsedKarmaConfig.plugins.push(AngularAssetsMiddleware.createPlugin(buildOutput));
306387
parsedKarmaConfig.middleware ??= [];
307388
parsedKarmaConfig.middleware.push(AngularAssetsMiddleware.NAME);
389+
parsedKarmaConfig.plugins.push(AngularPolyfillsPlugin.createPlugin(polyfillsFile, jasmineCleanupFiles));
390+
parsedKarmaConfig.reporters ??= [];
391+
parsedKarmaConfig.reporters.push(AngularPolyfillsPlugin.NAME);
308392
// When using code-coverage, auto-add karma-coverage.
309393
// This was done as part of the karma plugin for webpack.
310394
if (options.codeCoverage &&

src/builders/karma/jasmine_global.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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+
})();
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
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+
})();

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 = '19.1.0-next.1+sha-8d35b9b';
13+
const VERSION = '19.1.0-next.1+sha-a9a3470';
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-
Fri Dec 13 2024 19:35:40 GMT+0000 (Coordinated Universal Time)
1+
Fri Dec 13 2024 20:16:46 GMT+0000 (Coordinated Universal Time)

0 commit comments

Comments
 (0)