From 51c8f5acde086a4540f46f2aef1f48d2b5448ba7 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 28 Oct 2025 11:08:32 +0000 Subject: [PATCH 1/2] refactor(docs-infra): switch to esbuild pipeline for unit tests Removes the webpack-based Karma setup in favor of the new esbuild-based pipeline for running unit tests. This change simplifies the testing configuration and improves performance. - Deletes the old Karma configuration and test entry point. - Updates `angular.json` to use the `@angular-devkit/build-angular:browser-esbuild` builder for tests. - Adjusts test files to align with the new setup. --- adev/BUILD.bazel | 8 +- adev/angular.json | 18 ++-- adev/karma.conf.js | 85 ------------------- adev/package.json | 31 +++---- adev/src/app/app.component.spec.ts | 8 +- .../services/a-dev-title-strategy.spec.ts | 2 +- adev/test-main.ts | 18 ---- adev/tools/BUILD.bazel | 12 --- adev/tools/windows-chromium-path.js | 49 ----------- pnpm-lock.yaml | 3 + 10 files changed, 33 insertions(+), 201 deletions(-) delete mode 100644 adev/karma.conf.js delete mode 100644 adev/test-main.ts delete mode 100644 adev/tools/BUILD.bazel delete mode 100644 adev/tools/windows-chromium-path.js diff --git a/adev/BUILD.bazel b/adev/BUILD.bazel index b6fdf6222d6c..5e1f413c7cd0 100644 --- a/adev/BUILD.bazel +++ b/adev/BUILD.bazel @@ -82,10 +82,7 @@ APPLICATION_DEPS = [ ":node_modules/w3c-keyname", ] -TEST_FILES = APPLICATION_FILES + [ - "karma.conf.js", - "test-main.ts", -] + glob(["src/**/*.spec.ts"]) +TEST_FILES = APPLICATION_FILES + glob(["src/app/**/*.spec.ts"]) TEST_DEPS = [ dep @@ -93,8 +90,6 @@ TEST_DEPS = [ if dep != ":node_modules/@types/node" ] + [ "@rules_browsers//browsers/chromium", - "@rules_browsers//browsers/firefox", - "//adev/tools:windows-chromium-path", ] ng_config(name = "ng_config") @@ -164,6 +159,5 @@ ng_test( project_name = "angular-dev", toolchains = [ "@rules_browsers//browsers/chromium:toolchain_alias", - "@rules_browsers//browsers/firefox:toolchain_alias", ], ) diff --git a/adev/angular.json b/adev/angular.json index eeb7555e3da7..0d62fd2a88ce 100644 --- a/adev/angular.json +++ b/adev/angular.json @@ -81,17 +81,13 @@ } }, "test": { - "builder": "@angular/build:karma", - "options": { - "tsConfig": "tsconfig.spec.json", - "include": ["src/app"], - "karmaConfig": "karma.conf.js", - "main": "test-main.ts", - "inlineStyleLanguage": "scss", - "assets": ["src/favicon.ico", "src/assets"], - "styles": ["@angular/docs/styles/global-styles.scss"], - "scripts": [], - "webWorkerTsConfig": "tsconfig.worker.json" + "builder": "@angular/build:unit-test", + "options": { + "runner": "karma", + "browsers": ["ChromeHeadlessNoSandbox"], + "include": [ + "src/app/**/*.spec.ts" + ] } } } diff --git a/adev/karma.conf.js b/adev/karma.conf.js deleted file mode 100644 index 4ede04755519..000000000000 --- a/adev/karma.conf.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - * @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 - */ - -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -const {getAdjustedChromeBinPathForWindows} = require('./tools/windows-chromium-path'); - -process.env.CHROME_BIN = getAdjustedChromeBinPathForWindows(); - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage'), - {'reporter:jasmine-seed': ['type', JasmineSeedReporter]}, - ], - proxies: { - '/dummy/image': 'src/assets/images/logos/angular/angular.png', - }, - client: { - clearContext: false, // leave Jasmine Spec Runner output visible in browser - jasmine: { - // you can add configuration options for Jasmine here - // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html - // for example, you can disable the random execution with `random: false` - // or set a specific seed with `seed: 4321` - random: true, - seed: '', - }, - }, - jasmineHtmlReporter: { - suppressAll: true, // removes the duplicated traces - }, - coverageReporter: { - dir: require('path').join(__dirname, './coverage/site'), - subdir: '.', - reporters: [{type: 'html'}, {type: 'text-summary'}], - }, - reporters: ['progress', 'kjhtml', 'jasmine-seed'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - customLaunchers: { - ChromeHeadlessNoSandbox: { - base: 'ChromeHeadless', - // See /integration/README.md#browser-tests for more info on these args - flags: [ - '--no-sandbox', - '--headless', - '--disable-gpu', - '--disable-dev-shm-usage', - '--hide-scrollbars', - '--mute-audio', - ], - }, - }, - browsers: ['ChromeHeadlessNoSandbox'], - browserNoActivityTimeout: 60000, - singleRun: false, - restartOnFileChange: true, - }); -}; - -// Helpers -function JasmineSeedReporter(baseReporterDecorator) { - baseReporterDecorator(this); - - this.onBrowserComplete = (browser, result) => { - const seed = result.order && result.order.random && result.order.seed; - if (seed) this.write(`${browser}: Randomized with seed ${seed}.\n`); - }; - - this.onRunComplete = () => undefined; -} diff --git a/adev/package.json b/adev/package.json index cf67ae5085fe..b9588420ea7f 100644 --- a/adev/package.json +++ b/adev/package.json @@ -1,14 +1,17 @@ { "dependencies": { + "@algolia/client-common": "5.41.0", "@algolia/client-search": "5.41.0", + "@algolia/requester-browser-xhr": "5.41.0", + "@algolia/requester-node-http": "5.41.0", "@angular-devkit/build-angular": "21.0.0-next.9", "@angular/animations": "workspace:*", "@angular/build": "21.0.0-next.9", "@angular/cdk": "21.0.0-next.10", "@angular/cli": "21.0.0-next.9", "@angular/common": "workspace:*", - "@angular/compiler-cli": "workspace:*", "@angular/compiler": "workspace:*", + "@angular/compiler-cli": "workspace:*", "@angular/core": "workspace:*", "@angular/docs": "workspace:*", "@angular/forms": "workspace:*", @@ -30,8 +33,13 @@ "@codemirror/state": "6.5.2", "@codemirror/view": "6.38.6", "@lezer/common": "1.3.0", + "@lezer/css": "1.3.0", "@lezer/highlight": "1.2.2", + "@lezer/html": "1.3.12", "@lezer/javascript": "1.5.4", + "@lezer/lr": "1.4.2", + "@lezer/sass": "1.1.0", + "@marijn/find-cluster-break": "1.0.2", "@stackblitz/sdk": "1.11.0", "@types/dom-navigation": "1.0.6", "@types/jasmine": "5.1.12", @@ -43,6 +51,7 @@ "@xterm/xterm": "5.5.0", "algoliasearch": "5.41.0", "angular-split": "20.0.0", + "crelt": "1.0.6", "diff": "8.0.2", "emoji-regex": "10.6.0", "fflate": "0.8.2", @@ -50,37 +59,29 @@ "jsdom": "27.0.1", "karma-chrome-launcher": "3.2.0", "karma-coverage": "2.2.1", - "karma-jasmine-html-reporter": "2.1.0", "karma-jasmine": "5.1.0", + "karma-jasmine-html-reporter": "2.1.0", "marked": "16.4.1", "mermaid": "11.12.0", "ngx-progressbar": "14.0.0", "open-in-idx": "0.1.1", "playwright-core": "1.56.1", - "preact-render-to-string": "6.6.3", "preact": "10.27.2", + "preact-render-to-string": "6.6.3", "prettier": "3.6.2", "rxjs": "7.8.2", "shiki": "3.14.0", + "style-mod": "4.1.3", "tinyglobby": "0.2.15", "tslib": "2.8.1", "typescript": "5.9.3", + "w3c-keyname": "2.2.8", "xhr2": "0.2.1", - "zone.js": "0.15.1", - "@algolia/client-common": "5.41.0", - "@algolia/requester-browser-xhr": "5.41.0", - "@algolia/requester-node-http": "5.41.0", - "@lezer/css": "1.3.0", - "@lezer/html": "1.3.12", - "@lezer/lr": "1.4.2", - "@lezer/sass": "1.1.0", - "@marijn/find-cluster-break": "1.0.2", - "crelt": "1.0.6", - "style-mod": "4.1.3", - "w3c-keyname": "2.2.8" + "zone.js": "0.15.1" }, "devDependencies": { "autoprefixer": "10.4.21", + "karma": "~6.4.4", "postcss": "8.5.6", "tailwindcss": "3.4.18" } diff --git a/adev/src/app/app.component.spec.ts b/adev/src/app/app.component.spec.ts index a77f9c5cf68b..1b5360966333 100644 --- a/adev/src/app/app.component.spec.ts +++ b/adev/src/app/app.component.spec.ts @@ -18,8 +18,9 @@ describe('AppComponent', () => { const fakeSearch = {}; const fakeWindow = {location: {hostname: 'angular.dev'}}; - it('should create the app', () => { - TestBed.configureTestingModule({ + it('should create the app', async () => { + await TestBed.configureTestingModule({ + imports: [AppComponent], providers: [ provideHttpClient(), provideHttpClientTesting(), @@ -33,7 +34,8 @@ describe('AppComponent', () => { useValue: fakeSearch, }, ], - }); + }).compileComponents(); + const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app).toBeTruthy(); diff --git a/adev/src/app/core/services/a-dev-title-strategy.spec.ts b/adev/src/app/core/services/a-dev-title-strategy.spec.ts index 82a7d3082e3e..808716a7a619 100644 --- a/adev/src/app/core/services/a-dev-title-strategy.spec.ts +++ b/adev/src/app/core/services/a-dev-title-strategy.spec.ts @@ -13,7 +13,7 @@ import {Router, provideRouter} from '@angular/router'; import {Title} from '@angular/platform-browser'; import {Component} from '@angular/core'; -@Component({}) +@Component({template: ''}) class FakeComponent {} describe('ADevTitleStrategy', () => { diff --git a/adev/test-main.ts b/adev/test-main.ts deleted file mode 100644 index 1c4ba42ec158..000000000000 --- a/adev/test-main.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @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 {NgModule, provideZonelessChangeDetection} from '@angular/core'; -import {TestBed} from '@angular/core/testing'; -import {BrowserTestingModule, platformBrowserTesting} from '@angular/platform-browser/testing'; - -@NgModule({ - providers: [provideZonelessChangeDetection()], -}) -export class TestModule {} - -TestBed.initTestEnvironment([BrowserTestingModule, TestModule], platformBrowserTesting()); diff --git a/adev/tools/BUILD.bazel b/adev/tools/BUILD.bazel deleted file mode 100644 index 7b9cbe3e6db1..000000000000 --- a/adev/tools/BUILD.bazel +++ /dev/null @@ -1,12 +0,0 @@ -load("@aspect_rules_js//js:defs.bzl", "js_library") - -package(default_visibility = [ - "//adev:__subpackages__", -]) - -js_library( - name = "windows-chromium-path", - srcs = [ - "windows-chromium-path.js", - ], -) diff --git a/adev/tools/windows-chromium-path.js b/adev/tools/windows-chromium-path.js deleted file mode 100644 index 483bff23b22b..000000000000 --- a/adev/tools/windows-chromium-path.js +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @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 - */ - -const os = require('os'); -const path = require('path'); - -/* - TODO: this is a hack; the root cause should be found and fixed. - - For some unknown reason, the symlinked copy of chromium under runfiles won't run under - karma on Windows. To work around this, use chromium under the execroot in the external - folder and point to that instead. - - Return: - The adjusted absolute chromium path to use on Windows. On other platforms this is a - noop and returns the existing process.env.CHROME_BIN. -*/ -exports.getAdjustedChromeBinPathForWindows = function () { - if (os.platform() === 'win32') { - const runfilesWorkspaceRoot = path.join(process.env.RUNFILES, 'angular'); - - // Get the path to chromium from the runfiles base folder. By default, the Bazel make var - // $(CHROMIUM) (which CHROME_BIN is set to) has a preceding '../' to escape the workspace - // root within runfiles. Additional '../' may have been prepended to cancel out any chdirs. - const chromiumPath = process.env.CHROME_BIN.replace(/^(\.\.\/)*/, ''); - - // Escape from runfiles to the exec root - const execRootSlashWorkspace = 'execroot' + path.sep + 'angular'; - const index = runfilesWorkspaceRoot.indexOf(execRootSlashWorkspace); - const execRootPath = runfilesWorkspaceRoot.substring(0, index + execRootSlashWorkspace.length); - const runfilesToExecRoot = path.relative(runfilesWorkspaceRoot, execRootPath); - - // Resolve the path to chromium under the execroot - const chromiumExecRootPath = path.resolve( - runfilesWorkspaceRoot, - runfilesToExecRoot, - 'external', - chromiumPath, - ); - - return chromiumExecRootPath; - } - return process.env.CHROME_BIN; -}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ee4a3c47526..e9ec1fd4d6ff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -740,6 +740,9 @@ importers: autoprefixer: specifier: 10.4.21 version: 10.4.21(postcss@8.5.6) + karma: + specifier: ~6.4.4 + version: 6.4.4(bufferutil@4.0.9)(utf-8-validate@6.0.5) postcss: specifier: 8.5.6 version: 8.5.6 From 75e9329a7effbc6d857f8ec0335274f00ef02753 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 29 Oct 2025 08:05:38 +0000 Subject: [PATCH 2/2] build: update dependency node to v22.21.1 See associated pull request for more information. --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index aa50a62f2194..5767036af0e2 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22.21.0 +22.21.1