Skip to content

Commit aa2a5b3

Browse files
devversionjelbourn
authored andcommitted
build: create script that simplifies bazel testing workflow (#18016)
Instead of remembering what individual browser targets are called, and what the convention for Bazel labels is, we should just provide a script that simplifies the Bazel testing workflow. e.g. ```bash yarn test button [--local] [--firefox] [--no-watch] yarn test src/material/button src/cdk/bidi yarn test button slider coercion ``` Eventually we should document this script better in one of the contributing markdown files, but these docs need a general cleanup since they still mention Gulp.
1 parent 0e30214 commit aa2a5b3

File tree

3 files changed

+112
-2
lines changed

3 files changed

+112
-2
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
"bazel:buildifier": "find . -type f \\( -name \"*.bzl\" -or -name WORKSPACE -or -name BUILD -or -name BUILD.bazel \\) ! -path \"*/node_modules/*\" | xargs buildifier -v --warnings=attr-cfg,attr-license,attr-non-empty,attr-output-default,attr-single-file,constant-glob,ctx-args,depset-iteration,depset-union,dict-concatenation,duplicated-name,filetype,git-repository,http-archive,integer-division,load,load-on-top,native-build,native-package,output-group,package-name,package-on-top,redefined-variable,repository-name,same-origin-load,string-iteration,unused-variable,unsorted-dict-items,out-of-order-load",
1919
"bazel:format-lint": "yarn -s bazel:buildifier --lint=warn --mode=check",
2020
"dev-app": "ibazel run //src/dev-app:devserver",
21-
"test": "bazel test //src/... --test_tag_filters=-e2e,-browser:firefox-local --build_tag_filters=-browser:firefox-local --build_tests_only",
22-
"test-firefox": "bazel test //src/... --test_tag_filters=-e2e,-browser:chromium-local --build_tag_filters=-browser:chromium-local --build_tests_only",
21+
"test": "node ./scripts/run-component-tests.js",
22+
"test-local": "yarn -s test --local",
23+
"test-firefox": "yarn -s test --firefox",
2324
"lint": "yarn -s tslint && yarn -s bazel:format-lint && yarn -s ownerslint",
2425
"e2e": "bazel test //src/... --test_tag_filters=e2e",
2526
"deploy-dev-app": "node ./scripts/deploy-dev-app.js",

scripts/run-component-tests.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Script that simplifies the workflow of running unit tests for a component
5+
* using Bazel. Here are a few examples:
6+
*
7+
* node ./scripts/run-component-tests button | Runs Material button tests
8+
* node ./scripts/run-component-tests overlay | Runs CDK overlay tests
9+
* node ./scripts/run-component-tests src/cdk/a11y | Runs CDK a11y tests
10+
* node ./scripts/run-component-tests a11y overlay | Runs CDK a11y and overlay tests
11+
*
12+
* Supported command line flags:
13+
*
14+
* --local | If specified, no browser will be launched.
15+
* --firefox | Instead of Chrome being used for tests, Firefox will be used.
16+
* --no-watch | Watch mode is enabled by default. This flag opts-out to standard Bazel.
17+
*/
18+
19+
const minimist = require('minimist');
20+
const shelljs = require('shelljs');
21+
const chalk = require('chalk');
22+
const path = require('path');
23+
const args = process.argv.slice(2);
24+
25+
// Path to the project directory.
26+
const projectDir = path.join(__dirname, '../');
27+
28+
// Path to the directory that contains all packages.
29+
const packagesDir = path.join(projectDir, 'src/');
30+
31+
// List of packages where the specified component could be defined in. The script uses the
32+
// first package that contains the component (if no package is specified explicitly).
33+
// e.g. "button" will become "material/button", and "overlay" becomes "cdk/overlay".
34+
const orderedGuessPackages = ['material', 'cdk', 'material-experimental', 'cdk-experimental'];
35+
36+
// ShellJS should exit if any command fails.
37+
shelljs.set('-e');
38+
shelljs.cd(projectDir);
39+
40+
// Extracts the supported command line options.
41+
const {_: components, local, firefox, watch} = minimist(args, {
42+
boolean: ['local', 'firefox', 'watch'],
43+
default: {watch: true},
44+
});
45+
46+
// Exit if no component has been specified.
47+
if (!components.length) {
48+
console.error(chalk.red(
49+
'No component specified. Specify a component name, or pass a ' +
50+
'path to the component directory.'));
51+
process.exit(1);
52+
}
53+
54+
// We can only run a single target with "--local". Running multiple targets within the
55+
// same Karma server is not possible since each test target runs isolated from the others.
56+
if (local && components.length > 1) {
57+
console.error(chalk.red(
58+
'Unable to run multiple components tests in local mode. ' +
59+
'Only one component at a time can be run with "--local"'));
60+
process.exit(1);
61+
}
62+
63+
const bazelBinary = watch ? 'ibazel' : 'bazel';
64+
const bazelAction = local ? 'run' : 'test';
65+
const testTargetName =
66+
`unit_tests_${local ? 'local' : firefox ? 'firefox-local' : 'chromium-local'}`;
67+
const testLabels = components.map(t => `${getBazelPackageOfComponentName(t)}:${testTargetName}`);
68+
69+
// Runs Bazel for the determined test labels.
70+
shelljs.exec(`yarn -s ${bazelBinary} ${bazelAction} ${testLabels.join(' ')}`);
71+
72+
/**
73+
* Gets the Bazel package label for the specified component name. Throws if
74+
* the component could not be resolved to a Bazel package.
75+
*/
76+
function getBazelPackageOfComponentName(name) {
77+
// Before guessing any Bazel package, we test if the name contains the
78+
// package name already. If so, we just use that for Bazel package.
79+
const targetName = convertPathToBazelLabel(name);
80+
if (targetName !== null) {
81+
return targetName;
82+
}
83+
// If the name does not contain an explicit package name, we try guessing the
84+
// package name by walking through an ordered list of possible packages and checking
85+
// if a package contains a component with the given name. The first match will be used.
86+
for (let guessPackage of orderedGuessPackages) {
87+
const guessTargetName = convertPathToBazelLabel(path.join(packagesDir, guessPackage, name));
88+
if (guessTargetName !== null) {
89+
return guessTargetName;
90+
}
91+
}
92+
throw Error(chalk.red(`Could not find test target for specified component: ` +
93+
`${chalk.yellow(name)}. Looked in packages: ${orderedGuessPackages.join(', ')}`));
94+
}
95+
96+
/** Converts a path to a Bazel label. */
97+
function convertPathToBazelLabel(name) {
98+
if (shelljs.test('-d', name)) {
99+
return `//${convertPathToPosix(path.relative(projectDir, name))}`;
100+
}
101+
return null;
102+
}
103+
104+
/** Converts an arbitrary path to a Posix path. */
105+
function convertPathToPosix(pathName) {
106+
return pathName.replace(/\\/g, '/');
107+
}

tools/defaults.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ def ng_web_test_suite(deps = [], static_css = [], bootstrap = [], tags = [], **k
242242
"//test:angular_test_init",
243243
] + deps,
244244
browsers = [
245+
# Note: when changing the browser names here, also update the "yarn test"
246+
# script to reflect the new browser names.
245247
"@io_bazel_rules_webtesting//browsers:chromium-local",
246248
"@io_bazel_rules_webtesting//browsers:firefox-local",
247249
],

0 commit comments

Comments
 (0)