blob: cec19c0541199b3fd9bd21d5a19650200acdb170 [file] [log] [blame]
"""Helper macros for running jasmine specs via karma"""
# Inspirect by:
# rules_nodejs concatjs: https://github.com/bazelbuild/rules_nodejs/blob/3.3.0/packages/concatjs/web_test/karma.conf.js
# esbuild: https://gist.github.com/mattem/f6e85437b0dbcca661013a19247889a9
load("@io_bazel_rules_webtesting//web:web.bzl", _web_test_suite = "web_test_suite")
load("@npm//@bazel/esbuild:index.bzl", _esbuild = "esbuild")
load("@npm//karma:index.bzl", _karma = "karma")
KARMA_PEER_DEPS = [
"@npm//karma-chrome-launcher",
"@npm//karma-firefox-launcher",
"@npm//karma-jasmine",
"@npm//karma-sourcemap-loader",
"@npm//karma-junit-reporter",
]
# https://github.com/bazelbuild/rules_nodejs/blob/3.3.0/packages/concatjs/web_test/karma_web_test.bzl#L94-L99
# Avoid using non-normalized paths (workspace/../other_workspace/path)
def _to_manifest_path(ctx, file):
if file.short_path.startswith("../"):
return file.short_path[3:]
else:
return ctx.workspace_name + "/" + file.short_path.replace(".ts", ".js")
# Generate a karma.config.js file to:
# - run the given bundle containing specs
# - serve the given assets via http
# - bootstrap a set of js files before the bundle
def _generate_karma_config_impl(ctx):
configuration = ctx.outputs.configuration
# root-relative (runfiles) path to the directory containing karma.conf
config_segments = len(configuration.short_path.split("/"))
# Extract the bundle directory out of the bundle target files
bundle_dir = [f for f in ctx.attr.bundle[DefaultInfo].files.to_list() if f.is_directory][0]
ctx.actions.expand_template(
template = ctx.file._conf_tmpl,
output = configuration,
substitutions = {
"TMPL_bootstrap_files": "\n ".join(["'%s'," % _to_manifest_path(ctx, e) for e in ctx.files.bootstrap]),
"TMPL_runfiles_path": "/".join([".."] * config_segments),
"TMPL_static_files": "\n ".join(["'%s'," % _to_manifest_path(ctx, e) for e in ctx.files.static_files]),
"TMPL_test_bundle_dir": _to_manifest_path(ctx, bundle_dir),
},
)
_generate_karma_config = rule(
implementation = _generate_karma_config_impl,
attrs = {
# https://github.com/bazelbuild/rules_nodejs/blob/3.3.0/packages/concatjs/web_test/karma_web_test.bzl#L34-L39
"bootstrap": attr.label_list(
doc = """JavaScript files to load via <script> *before* the specs""",
allow_files = [".js"],
),
"bundle": attr.label(
doc = """The label producing the bundle directory containing the specs""",
mandatory = True,
),
# https://github.com/bazelbuild/rules_nodejs/blob/3.3.0/packages/concatjs/web_test/karma_web_test.bzl#L81-L87
"static_files": attr.label_list(
doc = """Arbitrary files which are available to be served on request""",
allow_files = True,
),
# https://github.com/bazelbuild/rules_nodejs/blob/3.3.0/packages/concatjs/web_test/karma_web_test.bzl#L88-L91
"_conf_tmpl": attr.label(
doc = """the karma config template""",
cfg = "host",
allow_single_file = True,
default = Label("//tools:karma.conf.js"),
),
},
outputs = {
"configuration": "%{name}.js",
},
)
# Macro to convert a set of files into a web_test_suite
def karma_web_test_suite(name, browsers, specs, deps = [], bootstrap = [], static_files = []):
"""Run the given specs.
Args:
name: primary karma target rule name
browsers: browsers to test
specs: spec files containing tests
deps: dependencies of the specs
bootstrap: files loaded in <script> tags up front
static_files: files available to download
"""
bundle_name = "%s.bundle" % name
suite_name = "%s.suite" % name
karma_config_name = "%s.conf" % name
karma_name = name
# Bundle the spec files
_esbuild(
name = bundle_name,
entry_points = [spec.replace(".ts", ".js") for spec in specs],
output_dir = True,
splitting = True,
deps = deps,
testonly = 1,
)
_generate_karma_config(
name = karma_config_name,
bundle = ":%s" % bundle_name,
bootstrap = bootstrap,
static_files = static_files,
testonly = 1,
)
_karma(
name = karma_name,
testonly = 1,
data = KARMA_PEER_DEPS + bootstrap + static_files + [
# generated config + specs-bundle
":%s" % karma_config_name,
":%s" % bundle_name,
],
templated_args = [
"start",
"$(rootpath %s)" % karma_config_name,
],
)
# Create a rules_webtesting web_test_suite wrapping the karma runner
_web_test_suite(
name = suite_name,
test = ":" + karma_name,
launcher = ":" + karma_name,
testonly = 1,
tags = ["native"],
browsers = browsers,
)