From ab96179867a709df99b894281ae83a8e9066beac Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Wed, 26 Mar 2025 13:46:35 -0400 Subject: [PATCH] fix(@angular/build): warn and remove jsdom launcher when used with karma The jsdom package does not currently support execution of ESM scripts. Attempting to use the karma jsdom launcher will cause test failures with potentially unclear error messages after the tests have been built and have started to execute. The karma application builder test runner will now issue a warning describing the problem and remove the jsdom launcher from the `browsers` option. The warning will be shown while analyzing the options and prior to the actual start of the test process. --- .../src/builders/karma/application_builder.ts | 12 +++++++ .../angular/build/src/builders/karma/index.ts | 2 +- .../karma/tests/options/browsers_spec.ts | 33 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 packages/angular/build/src/builders/karma/tests/options/browsers_spec.ts diff --git a/packages/angular/build/src/builders/karma/application_builder.ts b/packages/angular/build/src/builders/karma/application_builder.ts index eb724ba00700..41d2685ed484 100644 --- a/packages/angular/build/src/builders/karma/application_builder.ts +++ b/packages/angular/build/src/builders/karma/application_builder.ts @@ -361,6 +361,7 @@ async function collectEntrypoints( return getTestEntrypoints(testFiles, { projectSourceRoot, workspaceRoot: context.workspaceRoot }); } +// eslint-disable-next-line max-lines-per-function async function initializeApplication( options: KarmaBuilderOptions, context: BuilderContext, @@ -508,6 +509,17 @@ async function initializeApplication( { promiseConfig: true, throwErrors: true }, ); + // Check for jsdom which does not support executing ESM scripts. + // If present, remove jsdom and issue a warning. + const updatedBrowsers = parsedKarmaConfig.browsers?.filter((browser) => browser !== 'jsdom'); + if (parsedKarmaConfig.browsers?.length !== updatedBrowsers?.length) { + parsedKarmaConfig.browsers = updatedBrowsers; + context.logger.warn( + `'jsdom' does not support ESM code execution and cannot be used for karma testing.` + + ` The 'jsdom' entry has been removed from the 'browsers' option.`, + ); + } + // Remove the webpack plugin/framework: // Alternative would be to make the Karma plugin "smart" but that's a tall order // with managing unneeded imports etc.. diff --git a/packages/angular/build/src/builders/karma/index.ts b/packages/angular/build/src/builders/karma/index.ts index ca7ee3ed827e..1e5f5613e3a3 100644 --- a/packages/angular/build/src/builders/karma/index.ts +++ b/packages/angular/build/src/builders/karma/index.ts @@ -68,7 +68,7 @@ function getBaseKarmaOptions( // Convert browsers from a string to an array if (typeof options.browsers === 'string' && options.browsers) { - karmaOptions.browsers = options.browsers.split(','); + karmaOptions.browsers = options.browsers.split(',').map((browser) => browser.trim()); } else if (options.browsers === false) { karmaOptions.browsers = []; } diff --git a/packages/angular/build/src/builders/karma/tests/options/browsers_spec.ts b/packages/angular/build/src/builders/karma/tests/options/browsers_spec.ts new file mode 100644 index 000000000000..d3f774e750c5 --- /dev/null +++ b/packages/angular/build/src/builders/karma/tests/options/browsers_spec.ts @@ -0,0 +1,33 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ + +import { execute } from '../../index'; +import { BASE_OPTIONS, KARMA_BUILDER_INFO, describeKarmaBuilder } from '../setup'; + +describeKarmaBuilder(execute, KARMA_BUILDER_INFO, (harness, setupTarget) => { + describe('Option: "browsers"', () => { + it('should warn if jsdom is used', async () => { + await setupTarget(harness); + + harness.useTarget('test', { + ...BASE_OPTIONS, + browsers: BASE_OPTIONS.browsers + ',jsdom', + }); + + const { result, logs } = await harness.executeOnce(); + expect(result?.success).toBeTrue(); + expect(logs).toContain( + jasmine.objectContaining({ + message: jasmine.stringMatching( + `'jsdom' does not support ESM code execution and cannot be used for karma testing.`, + ), + }), + ); + }); + }); +});