199 lines
7.3 KiB
Python
199 lines
7.3 KiB
Python
|
"""Npm integration testing
|
||
|
"""
|
||
|
|
||
|
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
|
||
|
|
||
|
# Returns the manifest path of a file: `workspace/path/to/file`
|
||
|
def _to_manifest_path(ctx, file):
|
||
|
if file.short_path.startswith("../"):
|
||
|
# Strip the ../ from short_path to external repository
|
||
|
return file.short_path[3:]
|
||
|
else:
|
||
|
# Add the repository name for short_path to local repository
|
||
|
return ctx.workspace_name + "/" + file.short_path
|
||
|
|
||
|
def _npm_integration_test_config_impl(ctx):
|
||
|
if len(ctx.files.test_files) == 0:
|
||
|
fail("No files were found to run under integration testing.")
|
||
|
|
||
|
if ctx.attr.debug:
|
||
|
for f in ctx.files.test_files:
|
||
|
if f.is_directory:
|
||
|
fail("In debug mode, directory test_files labels not supported.")
|
||
|
|
||
|
commands = []
|
||
|
for c in ctx.attr.commands:
|
||
|
commands.append(ctx.expand_location(c, targets = ctx.attr.data))
|
||
|
|
||
|
# pass --define vars to test; these are added to the environment using process.env().
|
||
|
env_vars = {}
|
||
|
for k in ctx.attr.configuration_env_vars:
|
||
|
if k in ctx.var.keys():
|
||
|
env_vars[k] = ctx.var[k]
|
||
|
|
||
|
# Serialize configuration file for test runner
|
||
|
ctx.actions.write(
|
||
|
output = ctx.outputs.config,
|
||
|
content = """// npm_integration_test runner config generated by npm_integration_test rule
|
||
|
module.exports = {{
|
||
|
testFiles: [ {TMPL_test_files} ],
|
||
|
commands: [ {TMPL_commands} ],
|
||
|
npmPackages: {{ {TMPL_npm_packages} }},
|
||
|
checkNpmPackages: [ {TMPL_check_npm_packages} ],
|
||
|
envVars: {{ {TMPL_env_vars} }},
|
||
|
debug: {TMPL_debug},
|
||
|
}};
|
||
|
""".format(
|
||
|
TMPL_test_files = ", ".join(["'%s'" % f.short_path for f in ctx.files.test_files]),
|
||
|
TMPL_commands = ", ".join(["'%s'" % s for s in commands]),
|
||
|
TMPL_npm_packages = ", ".join(["'%s': '%s'" % (ctx.attr.npm_packages[n], n.files.to_list()[0].short_path) for n in ctx.attr.npm_packages]),
|
||
|
TMPL_check_npm_packages = ", ".join(["'%s'" % s for s in ctx.attr.check_npm_packages]),
|
||
|
TMPL_env_vars = ", ".join(["'%s': '%s'" % (k, env_vars[k]) for k in env_vars]),
|
||
|
TMPL_debug = "true" if ctx.attr.debug else "false",
|
||
|
),
|
||
|
)
|
||
|
|
||
|
runfiles = [ctx.outputs.config] + ctx.files.test_files + ctx.files.npm_packages
|
||
|
|
||
|
return [DefaultInfo(runfiles = ctx.runfiles(files = runfiles))]
|
||
|
|
||
|
_NPM_INTEGRATION_TEST_CONFIG_ATTRS = {
|
||
|
"commands": attr.string_list(
|
||
|
default = [],
|
||
|
mandatory = True,
|
||
|
doc = """The list of test commands to run. Defaults to `[]`.""",
|
||
|
),
|
||
|
"configuration_env_vars": attr.string_list(
|
||
|
doc = """Pass these configuration environment variables to the resulting test.
|
||
|
Chooses a subset of the configuration environment variables (taken from `ctx.var`), which also
|
||
|
includes anything specified via the --define flag.
|
||
|
Note, this can lead to different results for the test.""",
|
||
|
default = [],
|
||
|
),
|
||
|
"check_npm_packages": attr.string_list(
|
||
|
doc = """A list of npm packages that should be replaced in this test.
|
||
|
|
||
|
This attribute checks that none of the npm packages lists is found in the workspace-under-test's
|
||
|
package.json file unlinked to a generated npm package.
|
||
|
|
||
|
This can be used to verify that all npm package artifacts that need to be tested against are indeed
|
||
|
replaced in all integration tests. For example,
|
||
|
```
|
||
|
check_npm_packages = [
|
||
|
"@angular/common",
|
||
|
"@angular/compiler",
|
||
|
"@angular/compiler-cli",
|
||
|
"@angular/core",
|
||
|
],
|
||
|
```
|
||
|
If an `npm_packages` replacement on any package listed is missed then the test will fail. Since listing all
|
||
|
npm packages in `npm_packages` is expensive as any change will result in all integration tests re-running,
|
||
|
this attribute allows a fine grained `npm_packages` per integration test with the added safety that none
|
||
|
are missed for any one test.
|
||
|
""",
|
||
|
),
|
||
|
"data": attr.label_list(
|
||
|
doc = """Data dependencies for test.""",
|
||
|
allow_files = True,
|
||
|
),
|
||
|
"debug": attr.bool(
|
||
|
doc = """Setup the test for debugging.
|
||
|
|
||
|
If set to true then the package.json replacement are done in-place instead of a tmp folder
|
||
|
and the test is not run. This is used to configure the test folder for local testing and debugging.
|
||
|
""",
|
||
|
default = False,
|
||
|
),
|
||
|
"npm_packages": attr.label_keyed_string_dict(
|
||
|
doc = """A label keyed string dictionary of npm package replacements to make in the workspace-under-test's
|
||
|
package.json with npm package targets. The targets should be pkg_tar tar.gz archives.
|
||
|
|
||
|
For example,
|
||
|
```
|
||
|
npm_packages = {
|
||
|
"//packages/common:npm_package_archive": "@angular/common",
|
||
|
"//packages/compiler:npm_package_archive": "@angular/compiler",
|
||
|
"//packages/compiler-cli:npm_package_archive": "@angular/compiler-cli",
|
||
|
"//packages/core:npm_package_archive": "@angular/core",
|
||
|
}
|
||
|
```""",
|
||
|
allow_files = True,
|
||
|
),
|
||
|
"test_files": attr.label(
|
||
|
doc = """A filegroup of all files necessary to run the test.""",
|
||
|
allow_files = True,
|
||
|
),
|
||
|
}
|
||
|
|
||
|
_npm_integration_test_config = rule(
|
||
|
implementation = _npm_integration_test_config_impl,
|
||
|
doc = """Generates an npm_integration_test config.""",
|
||
|
attrs = _NPM_INTEGRATION_TEST_CONFIG_ATTRS,
|
||
|
outputs = {
|
||
|
"config": "%{name}.js",
|
||
|
},
|
||
|
)
|
||
|
|
||
|
def npm_integration_test(name, **kwargs):
|
||
|
"""Runs an npm integration test.
|
||
|
|
||
|
See _NPM_INTEGRATION_TEST_CONFIG_ATTRS above for configuration arguments.
|
||
|
"""
|
||
|
commands = kwargs.pop("commands", [])
|
||
|
configuration_env_vars = kwargs.pop("configuration_env_vars", [])
|
||
|
check_npm_packages = kwargs.pop("check_npm_packages", [])
|
||
|
npm_packages = kwargs.pop("npm_packages", {})
|
||
|
test_files = kwargs.pop("test_files", [])
|
||
|
data = kwargs.pop("data", [])
|
||
|
|
||
|
_npm_integration_test_config(
|
||
|
name = name + ".config",
|
||
|
commands = commands,
|
||
|
configuration_env_vars = configuration_env_vars,
|
||
|
check_npm_packages = check_npm_packages,
|
||
|
data = data,
|
||
|
npm_packages = npm_packages,
|
||
|
test_files = test_files,
|
||
|
visibility = ["//visibility:private"],
|
||
|
tags = ["manual"],
|
||
|
testonly = True,
|
||
|
)
|
||
|
|
||
|
# Config for debug target below
|
||
|
_npm_integration_test_config(
|
||
|
name = name + ".debug.config",
|
||
|
commands = commands,
|
||
|
configuration_env_vars = configuration_env_vars,
|
||
|
check_npm_packages = check_npm_packages,
|
||
|
data = data,
|
||
|
npm_packages = npm_packages,
|
||
|
test_files = test_files,
|
||
|
debug = True,
|
||
|
visibility = ["//visibility:private"],
|
||
|
tags = ["manual"],
|
||
|
testonly = True,
|
||
|
)
|
||
|
|
||
|
tags = kwargs.pop("tags", [])
|
||
|
npm_deps = ["@npm//tmp"]
|
||
|
|
||
|
nodejs_test(
|
||
|
name = name,
|
||
|
data = data + npm_deps + [":%s.config" % name, ":%s.config.js" % name],
|
||
|
tags = tags,
|
||
|
templated_args = ["$(location :%s.config.js)" % name],
|
||
|
entry_point = "//tools/npm_integration_test:test_runner.js",
|
||
|
**kwargs
|
||
|
)
|
||
|
|
||
|
# Setup a .debug target that sets the debug attribute to True.
|
||
|
# This target must be run with `bazel run` so it is tagged manual.
|
||
|
nodejs_test(
|
||
|
name = name + ".debug",
|
||
|
data = data + npm_deps + [":%s.debug.config" % name, ":%s.debug.config.js" % name],
|
||
|
tags = tags + ["manual", "local"],
|
||
|
templated_args = ["$(location :%s.debug.config.js)" % name],
|
||
|
entry_point = "//tools/npm_integration_test:test_runner.js",
|
||
|
**kwargs
|
||
|
)
|