From 6d03405ae78078c04a0b65fdb847ef1a0f01add2 Mon Sep 17 00:00:00 2001 From: MeAkib Date: Thu, 29 Oct 2026 00:39:39 +0600 Subject: [PATCH 1/2] fix(@angular/build): require only the launchers the karma configuration loads The upfront dependency validation of the unit-test builder's karma runner derives a launcher package from each browser name. This requests packages that do not exist, such as `karma-chromium-launcher` for `ChromiumHeadless` (provided by `karma-chrome-launcher`) or a package named after a custom launcher defined in a Karma configuration file, so `ng test` fails before running. Follow the vitest runner: skip the launcher validation when a custom configuration is used, since it loads its own plugins, and otherwise require `karma-chrome-launcher`, the only launcher of the built-in configuration. New unit specs for the karma runner's dependency validation fail without this change. --- .../builders/unit-test/runners/karma/index.ts | 10 +++----- .../unit-test/runners/karma/index_spec.ts | 25 ++++++++++++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/packages/angular/build/src/builders/unit-test/runners/karma/index.ts b/packages/angular/build/src/builders/unit-test/runners/karma/index.ts index b4720e91f350..cc9bba0aa1be 100644 --- a/packages/angular/build/src/builders/unit-test/runners/karma/index.ts +++ b/packages/angular/build/src/builders/unit-test/runners/karma/index.ts @@ -22,12 +22,10 @@ const KarmaTestRunner: TestRunner = { checker.check('karma'); checker.check('karma-jasmine'); - // Check for browser launchers - if (options.browsers?.length) { - for (const browser of options.browsers) { - const launcherName = `karma-${browser.toLowerCase().split('headless')[0]}-launcher`; - checker.check(launcherName); - } + // A custom configuration loads its own launcher plugins and may define custom launchers. + // The built-in configuration only loads the Chrome launcher, which also provides Chromium. + if (!options.runnerConfig) { + checker.check('karma-chrome-launcher'); } if (options.coverage.enabled) { diff --git a/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts b/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts index 8d291f03775e..b8b3dcc6655e 100644 --- a/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts +++ b/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts @@ -11,10 +11,14 @@ import KarmaTestRunner from './index'; describe('KarmaTestRunner', () => { describe('validateDependencies', () => { - function createOptions(coverageEnabled: boolean): NormalizedUnitTestBuilderOptions { + function createOptions( + coverageEnabled: boolean, + options: Partial = {}, + ): NormalizedUnitTestBuilderOptions { return { projectSourceRoot: '/non-existent', coverage: { enabled: coverageEnabled }, + ...options, } as NormalizedUnitTestBuilderOptions; } @@ -29,5 +33,24 @@ describe('KarmaTestRunner', () => { /karma-coverage/, ); }); + + it('requires karma-chrome-launcher for Chromium with the built-in configuration', () => { + const options = createOptions(false, { browsers: ['ChromiumHeadless'], runnerConfig: false }); + + expect(() => KarmaTestRunner.validateDependencies?.(options)).toThrowError( + /^(?!.*karma-chromium-launcher).*karma-chrome-launcher/s, + ); + }); + + it('does not require launchers for the browsers of a custom configuration', () => { + const options = createOptions(false, { + browsers: ['ChromeNoSandbox'], + runnerConfig: 'karma.conf.js', + }); + + expect(() => KarmaTestRunner.validateDependencies?.(options)).toThrowError( + /^(?!.*-launcher)/s, + ); + }); }); }); From d97e1c41cacb1bd294ddf10bc6be122285d9211d Mon Sep 17 00:00:00 2001 From: Shuaib Hasan Akib <48770016+MeAkib@users.noreply.github.com> Date: Thu, 29 Oct 2026 00:49:24 +0600 Subject: [PATCH 2/2] fixup! fix(@angular/build): require only the launchers the karma configuration loads Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- .../build/src/builders/unit-test/runners/karma/index_spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts b/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts index b8b3dcc6655e..2e9f5f0876ef 100644 --- a/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts +++ b/packages/angular/build/src/builders/unit-test/runners/karma/index_spec.ts @@ -35,7 +35,7 @@ describe('KarmaTestRunner', () => { }); it('requires karma-chrome-launcher for Chromium with the built-in configuration', () => { - const options = createOptions(false, { browsers: ['ChromiumHeadless'], runnerConfig: false }); + const options = createOptions(false, { browsers: ['ChromiumHeadless'] }); expect(() => KarmaTestRunner.validateDependencies?.(options)).toThrowError( /^(?!.*karma-chromium-launcher).*karma-chrome-launcher/s,