Skip to content

Commit f81b620

Browse files
authored
build: switch karma tests to rules_browsers (#30820)
* build: switch karma tests to `rules_browsers` Switches Karma tests to our new browser testing ruleset, that is using much more recent browser versions, and a more up-to-date future-proof test runner called `@web/test-runner`; that is also one of the options for Angular CLI. Also updates the browsers because now we are using Puppeteer, yay! this should allow us to stay up-to-date much easier! * build: speed up legacy tests bundle I've noticed a speed up from 4min to like 30seconds that way. Sass also recommends the sync variant.
1 parent a7ff33c commit f81b620

11 files changed

+86
-95
lines changed

WORKSPACE

+18-4
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ build_bazel_rules_nodejs_dependencies()
6565

6666
http_archive(
6767
name = "aspect_rules_js",
68-
sha256 = "75c25a0f15a9e4592bbda45b57aa089e4bf17f9176fd735351e8c6444df87b52",
69-
strip_prefix = "rules_js-2.1.0",
70-
url = "https://github.com/aspect-build/rules_js/releases/download/v2.1.0/rules_js-v2.1.0.tar.gz",
68+
sha256 = "3388abe9b9728ef68ea8d8301f932b11b2c9a271d74741ddd5f3b34d1db843ac",
69+
strip_prefix = "rules_js-2.1.1",
70+
url = "https://github.com/aspect-build/rules_js/releases/download/v2.1.1/rules_js-v2.1.1.tar.gz",
7171
)
7272

7373
load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies")
@@ -249,7 +249,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
249249

250250
git_repository(
251251
name = "devinfra",
252-
commit = "e4bf37af223483ce00f9316d227fd62cd744dc4b",
252+
commit = "b45dfa77df2021b23eeda5928ca6cd8bb89b21e7",
253253
remote = "https://github.com/angular/dev-infra.git",
254254
)
255255

@@ -299,3 +299,17 @@ esbuild_register_toolchains(
299299
name = "esbuild",
300300
esbuild_version = LATEST_ESBUILD_VERSION,
301301
)
302+
303+
git_repository(
304+
name = "rules_browsers",
305+
commit = "7e23dc705680369a323f520909d3984ae794965e",
306+
remote = "https://github.com/devversion/rules_browsers.git",
307+
)
308+
309+
load("@rules_browsers//setup:step_1.bzl", "rules_browsers_setup_1")
310+
311+
rules_browsers_setup_1()
312+
313+
load("@rules_browsers//setup:step_2.bzl", "rules_browsers_setup_2")
314+
315+
rules_browsers_setup_2()

scripts/create-legacy-tests-bundle.mjs

+19-16
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import fs from 'fs';
77
import glob from 'glob';
88
import module from 'module';
99
import {dirname, join, relative} from 'path';
10-
import sass from 'sass';
10+
import * as sass from 'sass';
1111
import url from 'url';
1212
import tsNode from 'ts-node';
1313

@@ -65,6 +65,7 @@ async function main() {
6565
format: 'iife',
6666
target: 'es2015',
6767
outfile: outFile,
68+
treeShaking: false,
6869
plugins: [esbuildResolvePlugin, esbuildLinkerPlugin],
6970
stdin: {contents: specEntryPointFile, resolveDir: projectDir},
7071
});
@@ -85,22 +86,26 @@ async function main() {
8586
*/
8687
async function compileSassFiles() {
8788
const sassFiles = glob.sync('src/**/!(_*|theme).scss', {cwd: projectDir, absolute: true});
88-
const sassTasks = [];
89+
const writeTasks = [];
8990

91+
let count = 0;
9092
for (const file of sassFiles) {
9193
const outRelativePath = relative(projectDir, file).replace(/\.scss$/, '.css');
9294
const outPath = join(projectDir, outRelativePath);
93-
const task = renderSassFileAsync(file).then(async content => {
95+
const content = renderSassFile(file).css;
96+
97+
count++;
98+
console.error(`Compiled ${count}/${sassFiles.length} files`);
99+
100+
writeTasks.push(async () => {
94101
console.info('Compiled, now writing:', outRelativePath);
95102
await fs.promises.mkdir(dirname(outPath), {recursive: true});
96103
await fs.promises.writeFile(outPath, content);
97104
});
98-
99-
sassTasks.push(task);
100105
}
101106

102-
// Wait for all Sass compilations to finish.
103-
await Promise.all(sassTasks);
107+
// Start all writes and wait for them to finish.
108+
await Promise.all(writeTasks.map(task => task()));
104109
}
105110

106111
/**
@@ -131,7 +136,7 @@ async function compileProjectWithNgtsc() {
131136
async function createEntryPointSpecFile() {
132137
const testFiles = glob.sync('**/*.spec.js', {absolute: true, cwd: legacyOutputDir});
133138

134-
let specEntryPointFile = `import './test/angular-test-init-spec.ts';`;
139+
let specEntryPointFile = `import './test/angular-test.init.ts';`;
135140
let i = 0;
136141
const testNamespaces = [];
137142

@@ -155,14 +160,12 @@ async function createEntryPointSpecFile() {
155160
return specEntryPointFile;
156161
}
157162

158-
/** Helper function to render a Sass file asynchronously using promises. */
159-
async function renderSassFileAsync(inputFile) {
160-
return sass
161-
.compileAsync(inputFile, {
162-
loadPaths: [nodeModulesDir, projectDir],
163-
importers: [localPackageSassImporter],
164-
})
165-
.then(result => result.css);
163+
/** Helper function to render a Sass file. */
164+
function renderSassFile(inputFile) {
165+
return sass.compile(inputFile, {
166+
loadPaths: [nodeModulesDir, projectDir],
167+
importers: [localPackageSassImporter],
168+
});
166169
}
167170

168171
/**

src/BUILD.bazel

+5-5
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ dgeni_api_docs(
4949
# Add all Angular packages to the sources because some Material exports use
5050
# Angular exports and these should not cause any warnings when Dgeni uses the
5151
# type checker to parse our TypeScript sources.
52-
"@npm//@angular/core",
53-
"@npm//@angular/common",
54-
"@npm//@angular/forms",
55-
"@npm//@angular/animations",
56-
"@npm//@angular/platform-browser",
52+
"//:node_modules/@angular/core",
53+
"//:node_modules/@angular/common",
54+
"//:node_modules/@angular/forms",
55+
"//:node_modules/@angular/animations",
56+
"//:node_modules/@angular/platform-browser",
5757
],
5858
entry_points = {
5959
"cdk": cdkApiEntryPoints,

src/cdk/a11y/key-manager/list-key-manager.spec.ts

+18-12
Original file line numberDiff line numberDiff line change
@@ -272,34 +272,40 @@ describe('Key managers', () => {
272272
});
273273
});
274274

275-
describe('with `vertical` direction', function (this: KeyEventTestContext) {
275+
describe('with `vertical` direction', () => {
276+
let context: KeyEventTestContext = {} as KeyEventTestContext;
277+
276278
beforeEach(() => {
277279
keyManager.withVerticalOrientation();
278-
this.nextKeyEvent = createKeyboardEvent('keydown', DOWN_ARROW);
279-
this.prevKeyEvent = createKeyboardEvent('keydown', UP_ARROW);
280+
context.nextKeyEvent = createKeyboardEvent('keydown', DOWN_ARROW);
281+
context.prevKeyEvent = createKeyboardEvent('keydown', UP_ARROW);
280282
});
281283

282-
runDirectionalKeyTests.call(this);
284+
runDirectionalKeyTests.call(context);
283285
});
284286

285-
describe('with `ltr` direction', function (this: KeyEventTestContext) {
287+
describe('with `ltr` direction', () => {
288+
let context: KeyEventTestContext = {} as KeyEventTestContext;
289+
286290
beforeEach(() => {
287291
keyManager.withHorizontalOrientation('ltr');
288-
this.nextKeyEvent = createKeyboardEvent('keydown', RIGHT_ARROW);
289-
this.prevKeyEvent = createKeyboardEvent('keydown', LEFT_ARROW);
292+
context.nextKeyEvent = createKeyboardEvent('keydown', RIGHT_ARROW);
293+
context.prevKeyEvent = createKeyboardEvent('keydown', LEFT_ARROW);
290294
});
291295

292-
runDirectionalKeyTests.call(this);
296+
runDirectionalKeyTests.call(context);
293297
});
294298

295-
describe('with `rtl` direction', function (this: KeyEventTestContext) {
299+
describe('with `rtl` direction', () => {
300+
let context: KeyEventTestContext = {} as KeyEventTestContext;
301+
296302
beforeEach(() => {
297303
keyManager.withHorizontalOrientation('rtl');
298-
this.nextKeyEvent = createKeyboardEvent('keydown', LEFT_ARROW);
299-
this.prevKeyEvent = createKeyboardEvent('keydown', RIGHT_ARROW);
304+
context.nextKeyEvent = createKeyboardEvent('keydown', LEFT_ARROW);
305+
context.prevKeyEvent = createKeyboardEvent('keydown', RIGHT_ARROW);
300306
});
301307

302-
runDirectionalKeyTests.call(this);
308+
runDirectionalKeyTests.call(context);
303309
});
304310

305311
/**

src/cdk/testing/tests/webdriver-test.bzl

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ def webdriver_test(name, deps, tags = [], **kwargs):
1212
tags = tags + ["manual"],
1313
data = [
1414
":%s_bundle" % name,
15-
"@npm//@angular/build-tooling/bazel/browsers/chromium",
15+
"@rules_browsers//src/browsers/chromium",
1616
],
1717
env = {
18-
"CHROMIUM_BIN": "$(CHROMIUM)",
18+
"CHROME_HEADLESS_BIN": "$(CHROME-HEADLESS-SHELL)",
1919
"CHROMEDRIVER": "$(CHROMEDRIVER)",
2020
},
21-
toolchains = ["@npm//@angular/build-tooling/bazel/browsers/chromium:toolchain_alias"],
21+
toolchains = ["@rules_browsers//src/browsers/chromium:toolchain_alias"],
2222
**kwargs
2323
)
2424

src/cdk/testing/tests/webdriver.e2e.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const projectRoot = path.resolve(__dirname, '../../../');
2121
const port = process.env['TEST_SERVER_PORT'];
2222

2323
const chromeDriver = path.join(projectRoot, process.env['CHROMEDRIVER']!);
24-
const chromiumBin = path.join(projectRoot, process.env['CHROMIUM_BIN']!);
24+
const chromiumBin = path.join(projectRoot, process.env['CHROME_HEADLESS_BIN']!);
2525

2626
setDefaultService(
2727
new ServiceBuilder(chromeDriver).enableVerboseLogging().loggingTo('/tmp/test.txt').build(),

test/BUILD.bazel

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ ts_project(
1616
name = "angular_test_init",
1717
testonly = True,
1818
# This file *must* end with "spec" in order for "karma_web_test_suite" to load it.
19-
srcs = ["angular-test-init-spec.ts"],
19+
srcs = ["angular-test.init.ts"],
2020
tsconfig = ":tsconfig",
2121
deps = [
2222
"//:node_modules/@angular/core",
2323
"//:node_modules/@angular/platform-browser",
24+
"//:node_modules/reflect-metadata",
25+
"//:node_modules/zone.js",
2426
],
2527
)

test/angular-test-init-spec.ts renamed to test/angular-test.init.ts

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import 'zone.js';
10+
import 'zone.js/testing';
11+
import 'reflect-metadata';
12+
913
import {ErrorHandler, NgModule, provideExperimentalZonelessChangeDetection} from '@angular/core';
1014
import {TestBed} from '@angular/core/testing';
1115
import {BrowserTestingModule, platformBrowserTesting} from '@angular/platform-browser/testing';

test/karma.conf.js

-15
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,6 @@ module.exports = config => {
2929
},
3030
],
3131
files: [
32-
{pattern: 'node_modules/reflect-metadata/Reflect.js', included: true, watched: false},
33-
{pattern: 'node_modules/zone.js/bundles/zone.umd.min.js', included: true, watched: false},
34-
{pattern: 'node_modules/zone.js/bundles/proxy.umd.min.js', included: true, watched: false},
35-
{pattern: 'node_modules/zone.js/bundles/sync-test.umd.js', included: true, watched: false},
36-
{
37-
pattern: 'node_modules/zone.js/bundles/jasmine-patch.umd.min.js',
38-
included: true,
39-
watched: false,
40-
},
41-
{pattern: 'node_modules/zone.js/bundles/async-test.umd.js', included: true, watched: false},
42-
{
43-
pattern: 'node_modules/zone.js/bundles/fake-async-test.umd.js',
44-
included: true,
45-
watched: false,
46-
},
4732
{
4833
pattern: 'node_modules/moment/min/moment-with-locales.min.js',
4934
included: false,

tools/defaults.bzl

+7-19
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ load("@npm//@angular/build-tooling/bazel/integration:index.bzl", _integration_te
88
load("@npm//@angular/build-tooling/bazel/esbuild:index.bzl", _esbuild = "esbuild", _esbuild_config = "esbuild_config")
99
load("@npm//@angular/build-tooling/bazel/http-server:index.bzl", _http_server = "http_server")
1010
load("@npm//@angular/build-tooling/bazel:extract_js_module_output.bzl", "extract_js_module_output")
11-
load("@npm//@bazel/protractor:index.bzl", _protractor_web_test_suite = "protractor_web_test_suite")
1211
load("//:packages.bzl", "NO_STAMP_NPM_PACKAGE_SUBSTITUTIONS", "NPM_PACKAGE_SUBSTITUTIONS")
1312
load("//:pkg-externals.bzl", "PKG_EXTERNALS")
1413
load("//tools/markdown-to-html:index.bzl", _markdown_to_html = "markdown_to_html")
1514
load("//tools/extract-tokens:index.bzl", _extract_tokens = "extract_tokens")
1615
load("//tools/bazel:ng_package_interop.bzl", "ng_package_interop")
1716
load("//tools:defaults2.bzl", "spec_bundle", _karma_web_test_suite = "karma_web_test_suite")
17+
load("@npm//@bazel/protractor:index.bzl", _protractor_web_test_suite = "protractor_web_test_suite")
1818

1919
npmPackageSubstitutions = select({
2020
"//tools:stamp": NPM_PACKAGE_SUBSTITUTIONS,
@@ -190,21 +190,7 @@ def node_integration_test(setup_chromium = False, node_repository = "nodejs", **
190190
**kwargs
191191
)
192192

193-
def ng_web_test_suite(deps = [], static_css = [], exclude_init_script = False, **kwargs):
194-
bootstrap = [
195-
# This matches the ZoneJS bundles used in default CLI projects. See:
196-
# https://github.com/angular/angular-cli/blob/main/packages/schematics/angular/application/files/src/polyfills.ts.template#L58
197-
# https://github.com/angular/angular-cli/blob/main/packages/schematics/angular/application/files/src/test.ts.template#L3
198-
# Note `zone.js/dist/zone.js` is aliased in the CLI to point to the evergreen
199-
# output that does not include legacy patches. See: https://github.com/angular/angular/issues/35157.
200-
# TODO: Consider adding the legacy patches when testing Saucelabs/Browserstack with Bazel.
201-
# CLI loads the legacy patches conditionally for ES5 legacy browsers. See:
202-
# https://github.com/angular/angular-cli/blob/277bad3895cbce6de80aa10a05c349b10d9e09df/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/common.ts#L141
203-
"@npm//:node_modules/zone.js/bundles/zone.umd.js",
204-
"@npm//:node_modules/zone.js/bundles/zone-testing.umd.js",
205-
"@npm//:node_modules/reflect-metadata/Reflect.js",
206-
] + kwargs.pop("bootstrap", [])
207-
193+
def ng_web_test_suite(deps = [], static_css = [], **kwargs):
208194
# Always include a prebuilt theme in the test suite because otherwise tests, which depend on CSS
209195
# that is needed for measuring, will unexpectedly fail. Also always adding a prebuilt theme
210196
# reduces the amount of setup that is needed to create a test suite Bazel target. Note that the
@@ -213,6 +199,8 @@ def ng_web_test_suite(deps = [], static_css = [], exclude_init_script = False, *
213199
"//src/material/prebuilt-themes:azure-blue",
214200
]
215201

202+
bootstrap = []
203+
216204
# Workaround for https://github.com/bazelbuild/rules_typescript/issues/301
217205
# Since some of our tests depend on CSS files which are not part of the `ng_project` rule,
218206
# we need to somehow load static CSS files within Karma (e.g. overlay prebuilt). Those styles
@@ -226,7 +214,7 @@ def ng_web_test_suite(deps = [], static_css = [], exclude_init_script = False, *
226214
native.genrule(
227215
name = css_id,
228216
srcs = [css_label],
229-
outs = ["%s.css.js" % css_id],
217+
outs = ["%s.css.init.js" % css_id],
230218
output_to_bindir = True,
231219
cmd = """
232220
files=($(execpaths %s))
@@ -244,8 +232,8 @@ def ng_web_test_suite(deps = [], static_css = [], exclude_init_script = False, *
244232

245233
karma_web_test_suite(
246234
# Depend on our custom test initialization script. This needs to be the first dependency.
247-
deps = deps if exclude_init_script else ["//test:angular_test_init"] + deps,
248-
bootstrap = bootstrap,
235+
deps = deps,
236+
bootstrap = ["//test:angular_test_init"] + bootstrap,
249237
**kwargs
250238
)
251239

tools/defaults2.bzl

+8-19
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ load("//tools/bazel:ts_project_interop.bzl", _ts_project = "ts_project")
33
load("//tools/bazel:module_name.bzl", "compute_module_name")
44
load("@aspect_rules_js//npm:defs.bzl", _npm_package = "npm_package")
55
load("@rules_angular//src/ng_project:index.bzl", _ng_project = "ng_project")
6-
load("@devinfra//bazel/spec-bundling:index_rjs.bzl", "spec_bundle_amd", _spec_bundle = "spec_bundle")
7-
load("@devinfra//bazel/karma:index.bzl", _karma_web_test_suite = "karma_web_test_suite")
6+
load("@devinfra//bazel/spec-bundling:index_rjs.bzl", _spec_bundle = "spec_bundle")
7+
load("@rules_browsers//src/wtr:index.bzl", "wtr_test")
88

99
spec_bundle = _spec_bundle
1010

@@ -56,7 +56,7 @@ def ng_project(
5656
# if False and not testonly:
5757
# _make_tsec_test(kwargs["name"])
5858

59-
def jasmine_test(name, data = [], args = [], external = [], **kwargs):
59+
def jasmine_test(name, data = [], args = [], **kwargs):
6060
# Create relative path to root, from current package dir. Necessary as
6161
# we change the `chdir` below to the package directory.
6262
relative_to_root = "/".join([".."] * len(native.package_name().split("/")))
@@ -77,11 +77,11 @@ def jasmine_test(name, data = [], args = [], external = [], **kwargs):
7777
**kwargs
7878
)
7979

80-
def karma_web_test_suite(name, tags = [], deps = [], browsers = None, **kwargs):
81-
spec_bundle_amd(
80+
def karma_web_test_suite(name, tags = [], deps = [], bootstrap = [], **kwargs):
81+
spec_bundle(
8282
name = "%s_bundle" % name,
83-
workspace_name = "angular_material",
8483
srcs = ["//src:build-tsconfig"],
84+
bootstrap = bootstrap,
8585
deps = deps,
8686
config = {
8787
"resolveExtensions": [".js"],
@@ -91,20 +91,9 @@ def karma_web_test_suite(name, tags = [], deps = [], browsers = None, **kwargs):
9191

9292
test_tags = ["partial-compilation-integration"] + tags
9393

94-
# Set up default browsers if no explicit `browsers` have been specified.
95-
if browsers == None:
96-
test_tags.append("native")
97-
browsers = [
98-
# Note: when changing the browser names here, also update the "yarn test"
99-
# script to reflect the new browser names.
100-
"@npm//@angular/build-tooling/bazel/browsers/chromium:chromium",
101-
"@npm//@angular/build-tooling/bazel/browsers/firefox:firefox",
102-
]
103-
104-
_karma_web_test_suite(
94+
wtr_test(
10595
name = name,
106-
tags = test_tags,
10796
deps = [":%s_bundle" % name],
108-
browsers = browsers,
97+
tags = test_tags,
10998
**kwargs
11099
)

0 commit comments

Comments
 (0)