mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-15 18:13:38 +08:00
test: run legacy-cli e2e tests via bazel
This commit is contained in:
parent
b8e68eb28a
commit
794e33ae72
4
.bazelrc
4
.bazelrc
@ -90,6 +90,10 @@ build:snapshot --workspace_status_command="yarn -s ng-dev release build-env-stam
|
||||
build:snapshot --stamp
|
||||
build:snapshot --//:enable_snapshot_repo_deps
|
||||
|
||||
build:e2e --workspace_status_command="yarn -s ng-dev release build-env-stamp --mode=release"
|
||||
build:e2e --stamp
|
||||
test:e2e --test_timeout=3600
|
||||
|
||||
build:local --//:enable_package_json_tar_deps
|
||||
|
||||
###############################
|
||||
|
@ -48,7 +48,9 @@ var_6: &only_pull_requests
|
||||
only:
|
||||
- /pull\/\d+/
|
||||
|
||||
# All e2e test suites
|
||||
var_7: &all_e2e_subsets ['npm', 'esbuild', 'yarn']
|
||||
var_8: &all_e2e_build_types ['e2e', 'snapshot']
|
||||
|
||||
# Executor Definitions
|
||||
# https://circleci.com/docs/2.0/reusing-config/#authoring-reusable-executors
|
||||
@ -63,10 +65,20 @@ executors:
|
||||
working_directory: ~/ng
|
||||
resource_class: small
|
||||
|
||||
bazel-executor:
|
||||
parameters:
|
||||
nodeversion:
|
||||
type: string
|
||||
default: *default_nodeversion
|
||||
docker:
|
||||
- image: cimg/node:<< parameters.nodeversion >>-browsers
|
||||
working_directory: ~/ng
|
||||
resource_class: xlarge
|
||||
|
||||
windows-executor:
|
||||
# Same as https://circleci.com/orbs/registry/orb/circleci/windows, but named.
|
||||
working_directory: ~/ng
|
||||
resource_class: windows.medium
|
||||
resource_class: windows.large
|
||||
shell: powershell.exe -ExecutionPolicy Bypass
|
||||
machine:
|
||||
# Contents of this image:
|
||||
@ -116,7 +128,7 @@ commands:
|
||||
- initialize_env
|
||||
- run: nvm install 16.13
|
||||
- run: nvm use 16.13
|
||||
- run: npm install -g yarn@1.22.10
|
||||
- run: npm install -g yarn@1.22.10 @bazel/bazelisk@${BAZELISK_VERSION}
|
||||
- run: node --version
|
||||
- run: yarn --version
|
||||
|
||||
@ -126,6 +138,7 @@ commands:
|
||||
type: env_var_name
|
||||
default: CIRCLE_PROJECT_REPONAME
|
||||
steps:
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- devinfra/setup-bazel-remote-exec:
|
||||
bazelrc: ./.bazelrc.user
|
||||
|
||||
@ -269,23 +282,24 @@ jobs:
|
||||
paths:
|
||||
- dist/_*.tgz
|
||||
|
||||
build-bazel-e2e:
|
||||
executor: action-executor
|
||||
resource_class: medium
|
||||
bazel-build:
|
||||
executor: bazel-executor
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- run: yarn bazel build //tests/legacy-cli/...
|
||||
- setup_bazel_rbe
|
||||
- run:
|
||||
name: Bazel Build Packages
|
||||
command: yarn bazel build //...
|
||||
- fail_fast
|
||||
|
||||
unit-test:
|
||||
executor: action-executor
|
||||
resource_class: xlarge
|
||||
bazel-test:
|
||||
executor: bazel-executor
|
||||
parameters:
|
||||
nodeversion:
|
||||
type: string
|
||||
default: *default_nodeversion_major
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- browser-tools/install-chrome
|
||||
- setup_bazel_rbe
|
||||
- run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
|
||||
- when:
|
||||
@ -311,6 +325,59 @@ jobs:
|
||||
no_output_timeout: 40m
|
||||
- fail_fast
|
||||
|
||||
bazel-e2e-tests:
|
||||
executor: bazel-executor
|
||||
parallelism: 8
|
||||
parameters:
|
||||
build_type:
|
||||
type: enum
|
||||
enum: *all_e2e_build_types
|
||||
default: 'e2e'
|
||||
subset:
|
||||
type: enum
|
||||
enum: *all_e2e_subsets
|
||||
default: 'npm'
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- initialize_env
|
||||
- setup_bazel_rbe
|
||||
- run: mkdir /mnt/ramdisk/e2e
|
||||
- run:
|
||||
name: Test << parameters.build_type >> << parameters.subset >>
|
||||
command: yarn bazel test --define=E2E_TEMP=/mnt/ramdisk/e2e --define=E2E_SHARD_TOTAL=${CIRCLE_NODE_TOTAL} --define=E2E_SHARD_INDEX=${CIRCLE_NODE_INDEX} --config=<< parameters.build_type >> //tests/legacy-cli:e2e.<< parameters.subset >>
|
||||
no_output_timeout: 40m
|
||||
- store_artifacts:
|
||||
path: dist/testlogs/tests/legacy-cli/e2e.<< parameters.subset >>
|
||||
- store_test_results:
|
||||
path: dist/testlogs/tests/legacy-cli/e2e.<< parameters.subset >>
|
||||
- fail_fast
|
||||
|
||||
bazel-test-browsers:
|
||||
executor: bazel-executor
|
||||
steps:
|
||||
- custom_attach_workspace
|
||||
- initialize_env
|
||||
- setup_bazel_rbe
|
||||
- run:
|
||||
name: Initialize Saucelabs
|
||||
command: setSecretVar SAUCE_ACCESS_KEY $(echo $SAUCE_ACCESS_KEY | rev)
|
||||
- run:
|
||||
name: Start Saucelabs Tunnel
|
||||
command: ./scripts/saucelabs/start-tunnel.sh
|
||||
background: true
|
||||
# Waits for the Saucelabs tunnel to be ready. This ensures that we don't run tests
|
||||
# too early without Saucelabs not being ready.
|
||||
- run: ./scripts/saucelabs/wait-for-tunnel.sh
|
||||
- run:
|
||||
name: E2E Saucelabs Tests
|
||||
command: yarn bazel test --config=saucelabs //tests/legacy-cli:e2e.saucelabs
|
||||
- run: ./scripts/saucelabs/stop-tunnel.sh
|
||||
- store_artifacts:
|
||||
path: dist/testlogs/tests/legacy-cli/e2e.saucelabs
|
||||
- store_test_results:
|
||||
path: dist/testlogs/tests/legacy-cli/e2e.saucelabs
|
||||
- fail_fast
|
||||
|
||||
snapshot_publish:
|
||||
executor: action-executor
|
||||
resource_class: medium
|
||||
@ -382,6 +449,48 @@ jobs:
|
||||
node tests\legacy-cli\run_e2e.js --nb-shards=$env:CIRCLE_NODE_TOTAL --shard=$env:CIRCLE_NODE_INDEX --tmpdir=X:/ramdisk/e2e-main --ignore="tests/misc/browsers.ts"
|
||||
- fail_fast
|
||||
|
||||
bazel-e2e-cli-win:
|
||||
executor: windows-executor
|
||||
parallelism: 12
|
||||
steps:
|
||||
- checkout
|
||||
- rebase_pr_win
|
||||
- setup_windows
|
||||
- restore_cache:
|
||||
keys:
|
||||
- *cache_key_win
|
||||
- run:
|
||||
# We use Arsenal Image Mounter (AIM) instead of ImDisk because of: https://github.com/nodejs/node/issues/6861
|
||||
# Useful resources for AIM: http://reboot.pro/index.php?showtopic=22068
|
||||
name: 'Arsenal Image Mounter (RAM Disk)'
|
||||
command: |
|
||||
pwsh ./.circleci/win-ram-disk.ps1
|
||||
- run: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
- save_cache:
|
||||
key: *cache_key_win
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
# Path where Arsenal Image Mounter files are downloaded.
|
||||
# Must match path in .circleci/win-ram-disk.ps1
|
||||
- ./aim
|
||||
- run:
|
||||
name: Execute E2E Tests
|
||||
environment:
|
||||
# Required by `yarn ng-dev`
|
||||
# See https://github.com/angular/angular/issues/46858
|
||||
PWD: .
|
||||
command: |
|
||||
mkdir X:/ramdisk/e2e
|
||||
bazel test --define=E2E_TEMP=X:/ramdisk/e2e --define=E2E_SHARD_TOTAL=$env:CIRCLE_NODE_TOTAL --define=E2E_SHARD_INDEX=$env:CIRCLE_NODE_INDEX --config=e2e //tests/legacy-cli:e2e.npm
|
||||
# This timeout provides time for the actual tests to timeout and report status
|
||||
# instead of CircleCI stopping the job without test failure information.
|
||||
no_output_timeout: 40m
|
||||
- fail_fast
|
||||
- store_artifacts:
|
||||
path: dist/testlogs/tests/legacy-cli/e2e.npm
|
||||
- store_test_results:
|
||||
path: dist/testlogs/tests/legacy-cli/e2e.npm
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
default_workflow:
|
||||
@ -457,23 +566,67 @@ workflows:
|
||||
# These jobs only really depend on Setup, but the build job is very quick to run (~35s) and
|
||||
# will catch any build errors before proceeding to the more lengthy and resource intensive
|
||||
# Bazel jobs.
|
||||
- unit-test:
|
||||
- bazel-test:
|
||||
name: test-node<< matrix.nodeversion >>
|
||||
matrix:
|
||||
parameters:
|
||||
nodeversion: *all_nodeversion_major
|
||||
requires:
|
||||
- build
|
||||
|
||||
# Compile the e2e tests with bazel to ensure the non-runtime typescript
|
||||
# compilation completes succesfully.
|
||||
- build-bazel-e2e:
|
||||
requires:
|
||||
- build
|
||||
- bazel-build
|
||||
|
||||
# Windows jobs
|
||||
- e2e-cli-win
|
||||
|
||||
- bazel-e2e-cli-win
|
||||
|
||||
# Bazel jobs
|
||||
- bazel-build:
|
||||
requires:
|
||||
- setup
|
||||
|
||||
- bazel-e2e-tests:
|
||||
name: bazel-e2e-cli-<< matrix.subset >>
|
||||
matrix:
|
||||
parameters:
|
||||
subset: *all_e2e_subsets
|
||||
build_type: 'e2e'
|
||||
filters:
|
||||
branches:
|
||||
ignore:
|
||||
- main
|
||||
- /\d+\.\d+\.x/
|
||||
requires:
|
||||
- bazel-build
|
||||
|
||||
- bazel-e2e-tests:
|
||||
name: bazel-e2e-snapshots-<< matrix.subset >>
|
||||
matrix:
|
||||
parameters:
|
||||
subset: *all_e2e_subsets
|
||||
build_type: 'snapshot'
|
||||
pre-steps:
|
||||
- when:
|
||||
condition:
|
||||
and:
|
||||
- not:
|
||||
equal: [main, << pipeline.git.branch >>]
|
||||
- not: << pipeline.parameters.snapshot_changed >>
|
||||
steps:
|
||||
# Don't run snapshot E2E's unless it's on the main branch or the snapshots file has been updated.
|
||||
- run: circleci-agent step halt
|
||||
requires:
|
||||
- bazel-build
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- main
|
||||
# This is needed to run this steps on Renovate PRs that amend the snapshots package.json
|
||||
- /^pull\/.*/
|
||||
|
||||
- bazel-test-browsers:
|
||||
requires:
|
||||
- bazel-build
|
||||
|
||||
# Publish jobs
|
||||
- snapshot_publish:
|
||||
<<: *only_release_branches
|
||||
|
@ -36,3 +36,8 @@ source $BASH_ENV;
|
||||
|
||||
# Disable husky.
|
||||
setPublicVar HUSKY 0
|
||||
|
||||
# Expose the Bazelisk version. We need to run Bazelisk globally since Windows has problems launching
|
||||
# Bazel from a node modules directoy that might be modified by the Bazel Yarn install then.
|
||||
setPublicVar BAZELISK_VERSION \
|
||||
"$(cd ${PROJECT_ROOT}; node -p 'require("./package.json").devDependencies["@bazel/bazelisk"]')"
|
@ -26,5 +26,6 @@ if (-not (Test-Path -Path $aimContents)) {
|
||||
./aim/cli/x64/aim_ll.exe --install ./aim/drivers
|
||||
|
||||
# Setup RAM disk mount. Same parameters as ImDisk
|
||||
# Ensure size is large enough to support the bazel 'shard_count's such as for e2e tests.
|
||||
# See: https://support.circleci.com/hc/en-us/articles/4411520952091-Create-a-windows-RAM-disk
|
||||
./aim/cli/x64/aim_ll.exe -a -s 5G -m X: -p "/fs:ntfs /q /y"
|
||||
./aim/cli/x64/aim_ll.exe -a -s 12G -m X: -p "/fs:ntfs /q /y"
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Use of this source code is governed by an MIT-style license that can be
|
||||
# found in the LICENSE file at https://angular.io/license
|
||||
load("@bazel_skylib//rules:common_settings.bzl", "bool_flag")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
@ -16,6 +17,14 @@ exports_files([
|
||||
"package.json",
|
||||
])
|
||||
|
||||
# Files required by e2e tests
|
||||
copy_to_bin(
|
||||
name = "config-files",
|
||||
srcs = [
|
||||
"package.json",
|
||||
],
|
||||
)
|
||||
|
||||
# Detect if the build is running under --stamp
|
||||
config_setting(
|
||||
name = "stamp",
|
||||
|
11
WORKSPACE
11
WORKSPACE
@ -98,3 +98,14 @@ nodejs_register_toolchains(
|
||||
name = "node16",
|
||||
node_version = "16.13.1",
|
||||
)
|
||||
|
||||
register_toolchains(
|
||||
"@npm//@angular/build-tooling/bazel/git-toolchain:git_linux_toolchain",
|
||||
"@npm//@angular/build-tooling/bazel/git-toolchain:git_macos_x86_toolchain",
|
||||
"@npm//@angular/build-tooling/bazel/git-toolchain:git_macos_arm64_toolchain",
|
||||
"@npm//@angular/build-tooling/bazel/git-toolchain:git_windows_toolchain",
|
||||
)
|
||||
|
||||
load("@npm//@angular/build-tooling/bazel/browsers:browser_repositories.bzl", "browser_repositories")
|
||||
|
||||
browser_repositories()
|
||||
|
@ -85,7 +85,7 @@ You can find more info about debugging [tests with Bazel in the docs.](https://g
|
||||
- Compile the packages being tested: `yarn build`
|
||||
- Run all tests: `node tests/legacy-cli/run_e2e.js`
|
||||
- Run a subset of the tests: `node tests/legacy-cli/run_e2e.js tests/legacy-cli/e2e/tests/i18n/ivy-localize-*`
|
||||
- Run on a custom set of npm packages (tar files): `node tests/legacy-cli/run_e2e.js --package _angular_cli.tgz _angular_create.tgz dist/*.tgz ...`
|
||||
- Run on a custom set of npm packages (tar files): `node tests/legacy-cli/run_e2e.js --package _angular_cli.tgz _angular_create.tgz dist/*.tgz tests/legacy-cli/e2e/tests/i18n/ivy-localize-*`
|
||||
|
||||
When running the debug commands, Node will stop and wait for a debugger to attach.
|
||||
You can attach your IDE to the debugger to stop on breakpoints and step through the code. Also, see [IDE Specific Usage](#ide-specific-usage) for a
|
||||
|
@ -23,7 +23,7 @@ class Version {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Convert this to use build-time version stamping after flipping the build script to use bazel
|
||||
// TODO(bazel): Convert this to use build-time version stamping after flipping the build script to use bazel
|
||||
// export const VERSION = new Version('0.0.0-PLACEHOLDER');
|
||||
export const VERSION = new Version(
|
||||
(
|
||||
|
@ -1,4 +1,5 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
load(":e2e.bzl", "e2e_suites")
|
||||
|
||||
ts_library(
|
||||
name = "runner",
|
||||
@ -11,16 +12,25 @@ ts_library(
|
||||
deps = [
|
||||
"//packages/angular_devkit/core",
|
||||
"//packages/angular_devkit/core/node",
|
||||
"//tests/legacy-cli/e2e/assets",
|
||||
"//tests/legacy-cli/e2e/utils",
|
||||
"@npm//@types/glob",
|
||||
"@npm//@types/yargs-parser",
|
||||
"@npm//ansi-colors",
|
||||
"@npm//yargs-parser",
|
||||
],
|
||||
)
|
||||
|
||||
e2e_suites(
|
||||
name = "e2e",
|
||||
data = [
|
||||
":runner",
|
||||
|
||||
# Tests + setup
|
||||
# Loaded dynamically at runtime, not compiletime deps
|
||||
"//tests/legacy-cli/e2e/assets",
|
||||
"//tests/legacy-cli/e2e/setup",
|
||||
"//tests/legacy-cli/e2e/initialize",
|
||||
"//tests/legacy-cli/e2e/tests",
|
||||
],
|
||||
runner = ":e2e_runner.ts",
|
||||
)
|
||||
|
158
tests/legacy-cli/e2e.bzl
Normal file
158
tests/legacy-cli/e2e.bzl
Normal file
@ -0,0 +1,158 @@
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
|
||||
|
||||
# bazel query --output=label "kind('pkg_tar', //packages/...)"
|
||||
TESTED_PACKAGES = [
|
||||
"//packages/angular/cli:npm_package_archive.tgz",
|
||||
"//packages/angular/create:npm_package_archive.tgz",
|
||||
"//packages/angular/pwa:npm_package_archive.tgz",
|
||||
"//packages/angular_devkit/architect:npm_package_archive.tgz",
|
||||
"//packages/angular_devkit/architect_cli:npm_package_archive.tgz",
|
||||
# this is private so don't use here
|
||||
# "//packages/angular_devkit/benchmark:npm_package_archive.tgz",
|
||||
"//packages/angular_devkit/build_angular:npm_package_archive.tgz",
|
||||
"//packages/angular_devkit/build_webpack:npm_package_archive.tgz",
|
||||
"//packages/angular_devkit/core:npm_package_archive.tgz",
|
||||
"//packages/angular_devkit/schematics:npm_package_archive.tgz",
|
||||
"//packages/angular_devkit/schematics_cli:npm_package_archive.tgz",
|
||||
"//packages/ngtools/webpack:npm_package_archive.tgz",
|
||||
"//packages/schematics/angular:npm_package_archive.tgz",
|
||||
]
|
||||
|
||||
# Number of bazel shards per test target
|
||||
TEST_SHARD_COUNT = 4
|
||||
|
||||
# NB: does not run on rbe because webdriver manager uses an absolute path to chromedriver
|
||||
# Requires network to fetch npm packages.
|
||||
TEST_TAGS = ["no-remote-exec", "requires-network"]
|
||||
|
||||
# Subset of tests for yarn/esbuild
|
||||
BROWSER_TESTS = ["tests/misc/browsers.js"]
|
||||
YARN_TESTS = ["tests/basic/**", "tests/update/**", "tests/commands/add/**"]
|
||||
ESBUILD_TESTS = ["tests/basic/**", "tests/build/prod-build.js"]
|
||||
|
||||
# Tests excluded for esbuild
|
||||
ESBUILD_IGNORE_TESTS = [
|
||||
"tests/basic/environment.js",
|
||||
"tests/basic/rebuild.js",
|
||||
"tests/basic/serve.js",
|
||||
"tests/basic/scripts-array.js",
|
||||
]
|
||||
|
||||
def _to_glob(patterns):
|
||||
if len(patterns) == 1:
|
||||
return patterns[0]
|
||||
|
||||
return "\"{%s}\"" % ",".join(patterns)
|
||||
|
||||
def e2e_suites(name, runner, data):
|
||||
"""
|
||||
Construct all e2e test suite targets
|
||||
|
||||
Args:
|
||||
name: the prefix to all rules
|
||||
runner: the e2e test runner entry point
|
||||
data: runtime deps such as tests and test data
|
||||
"""
|
||||
|
||||
# Default target meant to be run manually for debugging, customizing test cli via bazel
|
||||
_e2e_tests(name, runner = runner, data = data, tags = ["manual"])
|
||||
|
||||
# Pre-configured test suites
|
||||
# TODO: add node 14 + 16
|
||||
_e2e_suite(name, runner, "npm", data)
|
||||
_e2e_suite(name, runner, "yarn", data)
|
||||
_e2e_suite(name, runner, "esbuild", data)
|
||||
_e2e_suite(name, runner, "saucelabs", data)
|
||||
|
||||
def _e2e_tests(name, runner, **kwargs):
|
||||
# Always specify all the npm packages
|
||||
args = kwargs.pop("templated_args", []) + ["--package"] + [
|
||||
"$(rootpath %s)" % p
|
||||
for p in TESTED_PACKAGES
|
||||
]
|
||||
|
||||
# Always add all the npm packages as data
|
||||
data = kwargs.pop("data", []) + TESTED_PACKAGES
|
||||
|
||||
# Tags that must always be applied
|
||||
tags = kwargs.pop("tags", []) + TEST_TAGS
|
||||
|
||||
# Passthru E2E variables in case it is customized by CI etc
|
||||
configuration_env_vars = kwargs.pop("configuration_env_vars", []) + ["E2E_TEMP", "E2E_SHARD_INDEX", "E2E_SHARD_TOTAL"]
|
||||
|
||||
env = kwargs.pop("env", {})
|
||||
toolchains = kwargs.pop("toolchains", [])
|
||||
|
||||
# The git toolchain + env
|
||||
env.update({"GIT_BIN": "$(GIT_BIN_PATH)"})
|
||||
toolchains = toolchains + ["@npm//@angular/build-tooling/bazel/git-toolchain:current_git_toolchain"]
|
||||
|
||||
# Chromium browser toolchain
|
||||
env.update({
|
||||
"CHROME_BIN": "$(CHROMIUM)",
|
||||
"CHROMEDRIVER_BIN": "$(CHROMEDRIVER)",
|
||||
})
|
||||
toolchains = toolchains + ["@npm//@angular/build-tooling/bazel/browsers/chromium:toolchain_alias"]
|
||||
data = data + ["@npm//@angular/build-tooling/bazel/browsers/chromium"]
|
||||
|
||||
nodejs_test(
|
||||
name = name,
|
||||
templated_args = args,
|
||||
data = data,
|
||||
entry_point = runner,
|
||||
env = env,
|
||||
configuration_env_vars = configuration_env_vars,
|
||||
tags = tags,
|
||||
toolchains = toolchains,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def _e2e_suite(name, runner, type, data):
|
||||
"""
|
||||
Setup a predefined test suite (yarn|esbuild|saucelabs|npm).
|
||||
"""
|
||||
args = []
|
||||
tests = None
|
||||
ignore = None
|
||||
|
||||
if type == "yarn":
|
||||
args.append("--yarn")
|
||||
tests = YARN_TESTS
|
||||
ignore = BROWSER_TESTS
|
||||
elif type == "esbuild":
|
||||
args.append("--esbuild")
|
||||
tests = ESBUILD_TESTS
|
||||
ignore = BROWSER_TESTS + ESBUILD_IGNORE_TESTS
|
||||
elif type == "saucelabs":
|
||||
tests = BROWSER_TESTS
|
||||
ignore = None
|
||||
elif type == "npm":
|
||||
tests = None
|
||||
ignore = BROWSER_TESTS
|
||||
|
||||
# Standard e2e tests
|
||||
_e2e_tests(
|
||||
name = "%s.%s" % (name, type),
|
||||
runner = runner,
|
||||
size = "enormous",
|
||||
data = data,
|
||||
shard_count = TEST_SHARD_COUNT,
|
||||
templated_args = [
|
||||
"--glob=%s" % _to_glob(tests) if tests else "",
|
||||
"--ignore=%s" % _to_glob(ignore) if ignore else "",
|
||||
],
|
||||
)
|
||||
|
||||
# e2e tests of snapshot builds
|
||||
_e2e_tests(
|
||||
name = "%s.snapshot.%s" % (name, type),
|
||||
runner = runner,
|
||||
size = "enormous",
|
||||
data = data,
|
||||
shard_count = TEST_SHARD_COUNT,
|
||||
templated_args = [
|
||||
"--ng-snapshots",
|
||||
"--glob=%s" % _to_glob(tests) if tests else "",
|
||||
"--ignore=%s" % _to_glob(ignore) if ignore else "",
|
||||
],
|
||||
)
|
@ -1,11 +1,7 @@
|
||||
load("//tools:defaults.bzl", "js_library")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
|
||||
js_library(
|
||||
copy_to_bin(
|
||||
name = "assets",
|
||||
srcs = glob(["**"]),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"@npm//jasmine-spec-reporter",
|
||||
"@npm//ts-node",
|
||||
],
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { join } from 'path';
|
||||
import yargsParser from 'yargs-parser';
|
||||
import { IS_BAZEL } from '../utils/bazel';
|
||||
import { getGlobalVariable } from '../utils/env';
|
||||
import { expectFileToExist } from '../utils/fs';
|
||||
import { gitClean } from '../utils/git';
|
||||
@ -23,11 +24,13 @@ export default async function () {
|
||||
|
||||
// Install puppeteer in the parent directory for use by the CLI within any test project.
|
||||
// Align the version with the primary project package.json.
|
||||
const puppeteerVersion = require('../../../../package.json').devDependencies.puppeteer.replace(
|
||||
/^[\^~]/,
|
||||
'',
|
||||
);
|
||||
await installPackage(`puppeteer@${puppeteerVersion}`);
|
||||
// Bazel has own browser toolchains
|
||||
// TODO(bazel): remove non-bazel
|
||||
if (!IS_BAZEL) {
|
||||
const puppeteerVersion =
|
||||
require('../../../../package.json').devDependencies.puppeteer.replace(/^[\^~]/, '');
|
||||
await installPackage(`puppeteer@${puppeteerVersion}`);
|
||||
}
|
||||
|
||||
await ng('new', 'test-project', '--skip-install');
|
||||
await expectFileToExist(join(process.cwd(), 'test-project'));
|
||||
|
@ -5,7 +5,7 @@ ts_library(
|
||||
testonly = True,
|
||||
srcs = glob(["**/*.ts"]),
|
||||
data = [
|
||||
"//:package.json",
|
||||
"//:config-files",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
|
@ -1,8 +1,7 @@
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
|
||||
|
||||
ts_library(
|
||||
copy_to_bin(
|
||||
name = "ng-snapshot",
|
||||
srcs = [],
|
||||
data = ["package.json"],
|
||||
srcs = ["package.json"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
@ -12,7 +12,7 @@ export default async function () {
|
||||
} else if (argv.tmpdir) {
|
||||
tempRoot = argv.tmpdir;
|
||||
} else {
|
||||
tempRoot = await mktempd('angular-cli-e2e-');
|
||||
tempRoot = await mktempd('angular-cli-e2e-', process.env.E2E_TEMP);
|
||||
}
|
||||
console.log(` Using "${tempRoot}" as temporary directory for a new project.`);
|
||||
setGlobalVariable('tmp-root', tempRoot);
|
||||
|
@ -24,6 +24,10 @@ export default async function () {
|
||||
process.env.NPM_CONFIG_PREFIX = npmModulesPrefix;
|
||||
process.env.YARN_CONFIG_PREFIX = yarnModulesPrefix;
|
||||
|
||||
// Put the npm+yarn caches in the temp dir
|
||||
process.env.NPM_CONFIG_CACHE = join(tempRoot, 'npm-cache');
|
||||
process.env.YARN_CACHE_FOLDER = join(tempRoot, 'yarn-cache');
|
||||
|
||||
// Snapshot builds may contain versions that are not yet released (e.g., RC phase main branch).
|
||||
// In this case peer dependency ranges may not resolve causing npm 7+ to fail during tests.
|
||||
// To support this case, legacy peer dependency mode is enabled for snapshot builds.
|
||||
|
@ -4,9 +4,11 @@ ts_library(
|
||||
name = "tests",
|
||||
testonly = True,
|
||||
srcs = glob(["**/*.ts"]),
|
||||
data = [
|
||||
"//tests/legacy-cli/e2e/ng-snapshot",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//tests/legacy-cli/e2e/ng-snapshot",
|
||||
"//tests/legacy-cli/e2e/utils",
|
||||
"@npm//@types/express",
|
||||
"@npm//@types/glob",
|
||||
|
@ -29,7 +29,18 @@ export default async function () {
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['ChromeHeadless'],
|
||||
browsers: ['ChromeHeadlessNoSandbox'],
|
||||
customLaunchers: {
|
||||
ChromeHeadlessNoSandbox: {
|
||||
base: 'ChromeHeadless',
|
||||
flags: [
|
||||
'--no-sandbox',
|
||||
'--headless',
|
||||
'--disable-gpu',
|
||||
'--disable-dev-shm-usage',
|
||||
],
|
||||
}
|
||||
},
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
|
@ -1,7 +1,13 @@
|
||||
import { join } from 'path';
|
||||
import { IS_BAZEL } from '../../utils/bazel';
|
||||
import { execWithEnv } from '../../utils/process';
|
||||
|
||||
export default async function () {
|
||||
// TODO(bazel): fails with bazel on windows
|
||||
if (IS_BAZEL && process.platform.startsWith('win')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the esbuild native binary path to a non-existent file to simulate a spawn error.
|
||||
// The build should still succeed by falling back to the WASM variant of esbuild.
|
||||
await execWithEnv('ng', ['build'], {
|
||||
|
@ -4,9 +4,11 @@ ts_library(
|
||||
name = "utils",
|
||||
testonly = True,
|
||||
srcs = glob(["**/*.ts"]),
|
||||
data = [
|
||||
"//tests/legacy-cli/e2e/ng-snapshot",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//tests/legacy-cli/e2e/ng-snapshot",
|
||||
"@npm//@types/glob",
|
||||
"@npm//@types/node-fetch",
|
||||
"@npm//@types/semver",
|
||||
@ -16,7 +18,6 @@ ts_library(
|
||||
"@npm//glob",
|
||||
"@npm//npm",
|
||||
"@npm//protractor",
|
||||
"@npm//puppeteer",
|
||||
"@npm//rxjs",
|
||||
"@npm//semver",
|
||||
"@npm//tar",
|
||||
|
3
tests/legacy-cli/e2e/utils/bazel.ts
Normal file
3
tests/legacy-cli/e2e/utils/bazel.ts
Normal file
@ -0,0 +1,3 @@
|
||||
// TODO(bazel): remove this along with any non-bazel specific logic using it.
|
||||
|
||||
export const IS_BAZEL = !!process.env.BAZEL_TARGET;
|
@ -7,6 +7,7 @@ import { getGlobalVariable, getGlobalVariablesEnv } from './env';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
import treeKill from 'tree-kill';
|
||||
import { delimiter, join, resolve } from 'path';
|
||||
import { IS_BAZEL } from './bazel';
|
||||
|
||||
interface ExecOptions {
|
||||
silent?: boolean;
|
||||
@ -167,7 +168,23 @@ export function extractNpmEnv() {
|
||||
|
||||
function extractCIEnv(): NodeJS.ProcessEnv {
|
||||
return Object.keys(process.env)
|
||||
.filter((v) => v.startsWith('SAUCE_') || v === 'CI' || v === 'CIRCLECI' || v === 'CHROME_BIN')
|
||||
.filter(
|
||||
(v) =>
|
||||
v.startsWith('SAUCE_') ||
|
||||
v === 'CI' ||
|
||||
v === 'CIRCLECI' ||
|
||||
v === 'CHROME_BIN' ||
|
||||
v === 'CHROMEDRIVER_BIN',
|
||||
)
|
||||
.reduce<NodeJS.ProcessEnv>((vars, n) => {
|
||||
vars[n] = process.env[n];
|
||||
return vars;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function extractNgEnv() {
|
||||
return Object.keys(process.env)
|
||||
.filter((v) => v.startsWith('NG_'))
|
||||
.reduce<NodeJS.ProcessEnv>((vars, n) => {
|
||||
vars[n] = process.env[n];
|
||||
return vars;
|
||||
@ -357,11 +374,11 @@ export function node(...args: string[]) {
|
||||
}
|
||||
|
||||
export function git(...args: string[]) {
|
||||
return _exec({}, 'git', args);
|
||||
return _exec({}, process.env.GIT_BIN || 'git', args);
|
||||
}
|
||||
|
||||
export function silentGit(...args: string[]) {
|
||||
return _exec({ silent: true }, 'git', args);
|
||||
return _exec({ silent: true }, process.env.GIT_BIN || 'git', args);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -372,24 +389,42 @@ export function silentGit(...args: string[]) {
|
||||
* registry (not the test runner or standard global node_modules).
|
||||
*/
|
||||
export async function launchTestProcess(entry: string, ...args: any[]): Promise<void> {
|
||||
// NOTE: do NOT use the bazel TEST_TMPDIR. When sandboxing is not enabled the
|
||||
// TEST_TMPDIR is not sandboxed and has symlinks into the src dir in a
|
||||
// parent directory. Symlinks into the src dir will include package.json,
|
||||
// .git and other files/folders that may effect e2e tests.
|
||||
|
||||
const tempRoot: string = getGlobalVariable('tmp-root');
|
||||
const TEMP = process.env.TEMP ?? process.env.TMPDIR ?? tempRoot;
|
||||
|
||||
// Extract explicit environment variables for the test process.
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
TEMP,
|
||||
TMPDIR: TEMP,
|
||||
HOME: TEMP,
|
||||
|
||||
// Use BAZEL_TARGET as a metadata variable to show it is a
|
||||
// process managed by bazel
|
||||
BAZEL_TARGET: process.env.BAZEL_TARGET,
|
||||
|
||||
...extractNpmEnv(),
|
||||
...extractCIEnv(),
|
||||
...extractNgEnv(),
|
||||
...getGlobalVariablesEnv(),
|
||||
};
|
||||
|
||||
// Modify the PATH environment variable...
|
||||
env.PATH = (env.PATH || process.env.PATH)
|
||||
?.split(delimiter)
|
||||
// Only include paths within the sandboxed test environment or external
|
||||
// non angular-cli paths such as /usr/bin for generic commands.
|
||||
.filter((p) => p.startsWith(tempRoot) || !p.includes('angular-cli'))
|
||||
// Only include paths within the sandboxed test environment or external
|
||||
// non angular-cli paths such as /usr/bin for generic commands.
|
||||
env.PATH = process.env
|
||||
.PATH!.split(delimiter)
|
||||
.filter((p) => p.startsWith(tempRoot) || p.startsWith(TEMP) || !p.includes('angular-cli'))
|
||||
.join(delimiter);
|
||||
|
||||
const testProcessArgs = [resolve(__dirname, 'run_test_process'), entry, ...args];
|
||||
const testProcessArgs = [
|
||||
resolve(__dirname, IS_BAZEL ? 'test_process' : 'run_test_process'),
|
||||
entry,
|
||||
...args,
|
||||
];
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
spawn(process.execPath, testProcessArgs, {
|
||||
|
@ -2,8 +2,9 @@ import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { prerelease, SemVer } from 'semver';
|
||||
import yargsParser from 'yargs-parser';
|
||||
import { IS_BAZEL } from './bazel';
|
||||
import { getGlobalVariable } from './env';
|
||||
import { prependToFile, readFile, replaceInFile, writeFile } from './fs';
|
||||
import { readFile, replaceInFile, writeFile } from './fs';
|
||||
import { gitCommit } from './git';
|
||||
import { findFreePort } from './network';
|
||||
import { installWorkspacePackages, PkgInfo } from './packages';
|
||||
@ -50,37 +51,41 @@ export async function prepareProjectForE2e(name: string) {
|
||||
await installWorkspacePackages();
|
||||
await ng('generate', 'e2e', '--related-app-name', name);
|
||||
|
||||
const protractorPath = require.resolve('protractor');
|
||||
const webdriverUpdatePath = require.resolve('webdriver-manager/selenium/update-config.json', {
|
||||
paths: [protractorPath],
|
||||
});
|
||||
const webdriverUpdate = JSON.parse(await readFile(webdriverUpdatePath)) as {
|
||||
chrome: { last: string };
|
||||
};
|
||||
// bazel will use its own sandboxed browser + webdriver
|
||||
// TODO(bazel): remove non-bazel
|
||||
if (!IS_BAZEL) {
|
||||
const protractorPath = require.resolve('protractor');
|
||||
const webdriverUpdatePath = require.resolve('webdriver-manager/selenium/update-config.json', {
|
||||
paths: [protractorPath],
|
||||
});
|
||||
const webdriverUpdate = JSON.parse(await readFile(webdriverUpdatePath)) as {
|
||||
chrome: { last: string };
|
||||
};
|
||||
|
||||
const chromeDriverVersion = webdriverUpdate.chrome.last.match(/chromedriver_([\d|\.]+)/)?.[1];
|
||||
if (!chromeDriverVersion) {
|
||||
throw new Error('Could not extract chrome webdriver version.');
|
||||
}
|
||||
const chromeDriverVersion = webdriverUpdate.chrome.last.match(/chromedriver_([\d|\.]+)/)?.[1];
|
||||
if (!chromeDriverVersion) {
|
||||
throw new Error('Could not extract chrome webdriver version.');
|
||||
}
|
||||
|
||||
// Initialize selenium webdriver.
|
||||
// Often fails the first time so attempt twice if necessary.
|
||||
const runWebdriverUpdate = () =>
|
||||
exec(
|
||||
process.execPath,
|
||||
'node_modules/protractor/bin/webdriver-manager',
|
||||
'update',
|
||||
'--standalone',
|
||||
'false',
|
||||
'--gecko',
|
||||
'false',
|
||||
'--versions.chrome',
|
||||
chromeDriverVersion,
|
||||
);
|
||||
try {
|
||||
await runWebdriverUpdate();
|
||||
} catch {
|
||||
await runWebdriverUpdate();
|
||||
// Initialize selenium webdriver.
|
||||
// Often fails the first time so attempt twice if necessary.
|
||||
const runWebdriverUpdate = () =>
|
||||
exec(
|
||||
process.execPath,
|
||||
'node_modules/protractor/bin/webdriver-manager',
|
||||
'update',
|
||||
'--standalone',
|
||||
'false',
|
||||
'--gecko',
|
||||
'false',
|
||||
'--versions.chrome',
|
||||
chromeDriverVersion,
|
||||
);
|
||||
try {
|
||||
await runWebdriverUpdate();
|
||||
} catch {
|
||||
await runWebdriverUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
await useCIChrome(name, 'e2e');
|
||||
@ -182,42 +187,96 @@ export function useCIDefaults(projectName = 'test-project'): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
const KARMA_CONF_DEFAULT = `
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
jasmine: {},
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
jasmineHtmlReporter: {
|
||||
suppressAll: true // removes the duplicated traces
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/$PROJECT_NAME$'),
|
||||
subdir: '.',
|
||||
reporters: [
|
||||
{ type: 'html' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
||||
`;
|
||||
|
||||
export async function useCIChrome(projectName: string, projectDir = ''): Promise<void> {
|
||||
const protractorConf = path.join(projectDir, 'protractor.conf.js');
|
||||
const chromePath = require('puppeteer').executablePath();
|
||||
|
||||
// Use Puppeteer in protractor if a config is found on the project.
|
||||
if (fs.existsSync(protractorConf)) {
|
||||
const protractorPath = require.resolve('protractor');
|
||||
const webdriverUpdatePath = require.resolve('webdriver-manager/selenium/update-config.json', {
|
||||
paths: [protractorPath],
|
||||
});
|
||||
const webdriverUpdate = JSON.parse(await readFile(webdriverUpdatePath)) as {
|
||||
chrome: { last: string };
|
||||
};
|
||||
const chromeDriverPath = webdriverUpdate.chrome.last;
|
||||
|
||||
await replaceInFile(
|
||||
protractorConf,
|
||||
`browserName: 'chrome'`,
|
||||
`browserName: 'chrome',
|
||||
chromeOptions: {
|
||||
args: ['--headless'],
|
||||
binary: String.raw\`${chromePath}\`,
|
||||
args: ['--headless', '--no-sandbox', '--disable-gpu', '--disable-dev-shm-usage'],
|
||||
binary: String.raw\`${process.env.CHROME_BIN}\`,
|
||||
}`,
|
||||
);
|
||||
await replaceInFile(
|
||||
protractorConf,
|
||||
'directConnect: true,',
|
||||
`directConnect: true, chromeDriver: String.raw\`${chromeDriverPath}\`,`,
|
||||
`directConnect: true, chromeDriver: String.raw\`${process.env.CHROMEDRIVER_BIN}\`,`,
|
||||
);
|
||||
}
|
||||
|
||||
// Use ChromeHeadless.
|
||||
const karmaConf = path.join(projectDir, 'karma.conf.js');
|
||||
|
||||
// Create one with default config if it doesn't exist
|
||||
if (!fs.existsSync(karmaConf)) {
|
||||
await writeFile(karmaConf, KARMA_CONF_DEFAULT.replace('$PROJECT_NAME$', projectName));
|
||||
}
|
||||
|
||||
// Update to use the headless sandboxed chrome
|
||||
await replaceInFile(
|
||||
karmaConf,
|
||||
/browsers:.*\]\s*,/,
|
||||
`
|
||||
browsers: ['ChromeHeadlessNoSandbox'],
|
||||
customLaunchers: {
|
||||
ChromeHeadlessNoSandbox: {
|
||||
base: 'ChromeHeadless',
|
||||
flags: [
|
||||
'--no-sandbox',
|
||||
'--headless',
|
||||
'--disable-gpu',
|
||||
'--disable-dev-shm-usage',
|
||||
],
|
||||
}
|
||||
},
|
||||
`,
|
||||
);
|
||||
|
||||
return updateJsonFile('angular.json', (workspaceJson) => {
|
||||
const project = workspaceJson.projects[projectName];
|
||||
const appTargets = project.targets || project.architect;
|
||||
appTargets.test.options.browsers = 'ChromeHeadless';
|
||||
appTargets.test.options.browsers = 'ChromeHeadlessNoSandbox';
|
||||
appTargets.test.options.karmaConfig = karmaConf;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,8 @@ export function wait(msecs: number): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
export async function mktempd(prefix: string): Promise<string> {
|
||||
return realpath(await mkdtemp(path.join(tmpdir(), prefix)));
|
||||
export async function mktempd(prefix: string, tempRoot?: string): Promise<string> {
|
||||
return realpath(await mkdtemp(path.join(tempRoot ?? tmpdir(), prefix)));
|
||||
}
|
||||
|
||||
export async function mockHome(cb: (home: string) => Promise<void>): Promise<void> {
|
||||
|
@ -8,10 +8,11 @@ import { getGlobalVariable, setGlobalVariable } from './e2e/utils/env';
|
||||
import { gitClean } from './e2e/utils/git';
|
||||
import { createNpmRegistry } from './e2e/utils/registry';
|
||||
import { launchTestProcess } from './e2e/utils/process';
|
||||
import { join } from 'path';
|
||||
import { delimiter, dirname, join } from 'path';
|
||||
import { IS_BAZEL } from './e2e/utils/bazel';
|
||||
import { findFreePort } from './e2e/utils/network';
|
||||
import { extractFile } from './e2e/utils/tar';
|
||||
import { realpathSync } from 'fs';
|
||||
import { readFileSync, realpathSync } from 'fs';
|
||||
import { PkgInfo } from './e2e/utils/packages';
|
||||
|
||||
Error.stackTraceLimit = Infinity;
|
||||
@ -61,6 +62,16 @@ const argv = yargsParser(process.argv.slice(2), {
|
||||
},
|
||||
default: {
|
||||
'package': ['./dist/_*.tgz'],
|
||||
|
||||
'debug': !!process.env.BUILD_WORKSPACE_DIRECTORY,
|
||||
'glob': process.env.TESTBRIDGE_TEST_ONLY,
|
||||
'nb-shards':
|
||||
Number(process.env.E2E_SHARD_TOTAL ?? 1) * Number(process.env.TEST_TOTAL_SHARDS ?? 1) || 1,
|
||||
'shard':
|
||||
process.env.E2E_SHARD_INDEX === undefined && process.env.TEST_SHARD_INDEX === undefined
|
||||
? undefined
|
||||
: Number(process.env.E2E_SHARD_INDEX ?? 0) * Number(process.env.TEST_TOTAL_SHARDS ?? 1) +
|
||||
Number(process.env.TEST_SHARD_INDEX ?? 0),
|
||||
},
|
||||
});
|
||||
|
||||
@ -80,6 +91,20 @@ process.exitCode = 255;
|
||||
*/
|
||||
process.env.LEGACY_CLI_RUNNER = '1';
|
||||
|
||||
/**
|
||||
* Add external git toolchain onto PATH
|
||||
*/
|
||||
if (process.env.GIT_BIN) {
|
||||
process.env.PATH = process.env.PATH! + delimiter + dirname(process.env.GIT_BIN!);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add external browser toolchains onto PATH
|
||||
*/
|
||||
if (process.env.CHROME_BIN) {
|
||||
process.env.PATH = process.env.PATH! + delimiter + dirname(process.env.CHROME_BIN!);
|
||||
}
|
||||
|
||||
const logger = createConsoleLogger(argv.verbose, process.stdout, process.stderr, {
|
||||
info: (s) => s,
|
||||
debug: (s) => s,
|
||||
@ -93,17 +118,27 @@ function lastLogger() {
|
||||
return logStack[logStack.length - 1];
|
||||
}
|
||||
|
||||
const testGlob = argv.glob || 'tests/**/*.ts';
|
||||
// Under bazel the compiled file (.js) and types (.d.ts) are available.
|
||||
// Outside bazel the source .ts files are available.
|
||||
const SRC_FILE_EXT = IS_BAZEL ? 'js' : 'ts';
|
||||
const SRC_FILE_EXT_RE = new RegExp(`\.${SRC_FILE_EXT}$`);
|
||||
|
||||
const testGlob = argv.glob || `tests/**/*.${SRC_FILE_EXT}`;
|
||||
|
||||
const e2eRoot = path.join(__dirname, 'e2e');
|
||||
const allSetups = glob.sync('setup/**/*.ts', { nodir: true, cwd: e2eRoot }).sort();
|
||||
const allInitializers = glob.sync('initialize/**/*.ts', { nodir: true, cwd: e2eRoot }).sort();
|
||||
const allSetups = glob.sync(`setup/**/*.${SRC_FILE_EXT}`, { nodir: true, cwd: e2eRoot }).sort();
|
||||
const allInitializers = glob
|
||||
.sync(`initialize/**/*.${SRC_FILE_EXT}`, { nodir: true, cwd: e2eRoot })
|
||||
.sort();
|
||||
const allTests = glob
|
||||
.sync(testGlob, { nodir: true, cwd: e2eRoot, ignore: argv.ignore })
|
||||
// Replace windows slashes.
|
||||
.map((name) => name.replace(/\\/g, '/'))
|
||||
.filter((name) => {
|
||||
if (name.endsWith('/setup.ts')) {
|
||||
if (name.endsWith(`/setup.${SRC_FILE_EXT}`)) {
|
||||
return false;
|
||||
}
|
||||
if (!SRC_FILE_EXT_RE.test(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -122,8 +157,8 @@ const allTests = glob
|
||||
})
|
||||
.sort();
|
||||
|
||||
const shardId = 'shard' in argv ? argv['shard'] : null;
|
||||
const nbShards = (shardId === null ? 1 : argv['nb-shards']) || 2;
|
||||
const shardId = argv['shard'] !== undefined ? Number(argv['shard']) : null;
|
||||
const nbShards = shardId === null ? 1 : Number(argv['nb-shards']);
|
||||
const tests = allTests.filter((name) => {
|
||||
// Check for naming tests on command line.
|
||||
if (argv._.length == 0) {
|
||||
@ -134,7 +169,7 @@ const tests = allTests.filter((name) => {
|
||||
return (
|
||||
path.join(process.cwd(), argName + '') == path.join(__dirname, 'e2e', name) ||
|
||||
argName == name ||
|
||||
argName == name.replace(/\.ts$/, '')
|
||||
argName == name.replace(SRC_FILE_EXT_RE, '')
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -143,7 +178,7 @@ const tests = allTests.filter((name) => {
|
||||
const testsToRun = tests.filter((name, i) => shardId === null || i % nbShards == shardId);
|
||||
|
||||
if (testsToRun.length === 0) {
|
||||
if (shardId !== null && tests.length >= shardId ? 1 : 0) {
|
||||
if (shardId !== null && tests.length <= shardId) {
|
||||
console.log(`No tests to run on shard ${shardId}, exiting.`);
|
||||
process.exit(0);
|
||||
} else {
|
||||
@ -170,9 +205,28 @@ console.log(['Tests:', ...testsToRun].join('\n '));
|
||||
|
||||
setGlobalVariable('argv', argv);
|
||||
setGlobalVariable('package-manager', argv.yarn ? 'yarn' : 'npm');
|
||||
// This is needed by karma-chrome-launcher
|
||||
|
||||
// Use the chrome supplied by bazel or the puppeteer chrome and webdriver-manager driver outside.
|
||||
// This is needed by karma-chrome-launcher, protractor etc.
|
||||
// https://github.com/karma-runner/karma-chrome-launcher#headless-chromium-with-puppeteer
|
||||
process.env['CHROME_BIN'] = require('puppeteer').executablePath();
|
||||
//
|
||||
// Resolve from relative paths to absolute paths within the bazel runfiles tree
|
||||
// so subprocesses spawned in a different working directory can still find them.
|
||||
process.env.CHROME_BIN = IS_BAZEL
|
||||
? path.resolve(process.env.CHROME_BIN!)
|
||||
: require('puppeteer').executablePath();
|
||||
process.env.CHROMEDRIVER_BIN = IS_BAZEL
|
||||
? path.resolve(process.env.CHROMEDRIVER_BIN!)
|
||||
: (function () {
|
||||
const protractorPath = require.resolve('protractor');
|
||||
const webdriverUpdatePath = require.resolve('webdriver-manager/selenium/update-config.json', {
|
||||
paths: [protractorPath],
|
||||
});
|
||||
const webdriverUpdate = JSON.parse(readFileSync(webdriverUpdatePath).toString()) as {
|
||||
chrome: { last: string };
|
||||
};
|
||||
return webdriverUpdate.chrome.last;
|
||||
})();
|
||||
|
||||
Promise.all([findFreePort(), findFreePort(), findPackageTars()])
|
||||
.then(async ([httpPort, httpsPort, packageTars]) => {
|
||||
@ -237,12 +291,12 @@ async function runSteps(
|
||||
|
||||
for (const [stepIndex, relativeName] of steps.entries()) {
|
||||
// Make sure this is a windows compatible path.
|
||||
let absoluteName = path.join(e2eRoot, relativeName).replace(/\.ts$/, '');
|
||||
let absoluteName = path.join(e2eRoot, relativeName).replace(SRC_FILE_EXT_RE, '');
|
||||
if (/^win/.test(process.platform)) {
|
||||
absoluteName = absoluteName.replace(/\\/g, path.posix.sep);
|
||||
}
|
||||
|
||||
const name = relativeName.replace(/\.ts$/, '');
|
||||
const name = relativeName.replace(SRC_FILE_EXT_RE, '');
|
||||
const start = Date.now();
|
||||
|
||||
printHeader(relativeName, stepIndex, steps.length, type);
|
||||
@ -297,7 +351,7 @@ function printHeader(
|
||||
type: 'setup' | 'initializer' | 'test',
|
||||
) {
|
||||
const text = `${testIndex + 1} of ${count}`;
|
||||
const fullIndex = testIndex * nbShards + shardId + 1;
|
||||
const fullIndex = testIndex * nbShards + (shardId ?? 0) + 1;
|
||||
const shard =
|
||||
shardId === null || type !== 'test'
|
||||
? ''
|
||||
@ -328,7 +382,16 @@ async function findPackageTars(): Promise<{ [pkg: string]: PkgInfo }> {
|
||||
glob.sync(p, { realpath: true }),
|
||||
);
|
||||
|
||||
const pkgJsons = await Promise.all(pkgs.map((pkg) => extractFile(pkg, './package/package.json')));
|
||||
const pkgJsons = await Promise.all(
|
||||
pkgs.map(async (pkg) => {
|
||||
try {
|
||||
return await extractFile(pkg, './package/package.json');
|
||||
} catch (e) {
|
||||
// TODO(bazel): currently the bazel npm packaging does not contain the standard npm ./package directory
|
||||
return await extractFile(pkg, './package.json');
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return pkgs.reduce((all, pkg, i) => {
|
||||
const json = pkgJsons[i].toString('utf8');
|
||||
|
@ -1,6 +1,6 @@
|
||||
"""Re-export of some bazel rules with repository-wide defaults."""
|
||||
|
||||
load("@npm//@bazel/concatjs/internal:build_defs.bzl", _ts_library = "ts_library_macro")
|
||||
load("@npm//@bazel/concatjs:index.bzl", _ts_library = "ts_library")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin", _js_library = "js_library", _pkg_npm = "pkg_npm")
|
||||
load("@rules_pkg//:pkg.bzl", "pkg_tar")
|
||||
load("@npm//@angular/build-tooling/bazel:extract_js_module_output.bzl", "extract_js_module_output")
|
||||
|
Loading…
x
Reference in New Issue
Block a user