blob: cdae503ce332c1bea52f5a705767e802e2440905 [file] [log] [blame]
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
load(":defs.bzl", "my_nodejs")
# Trivial test fixture: a nodejs program that writes to a file
write_file(
name = "js",
out = "some.js",
content = ["require('fs').writeFileSync(process.argv[2], 'stuff')"],
)
write_file(
name = "write_expected",
out = "expected",
content = ["stuff"],
)
# This technique can be used to directly grab a node binary as a label, however it has the
# downside that analysis phase on this select() statement will cause an eager fetch of all
# the platforms and therefore download a bunch of node binaries.
# This is what toolchains solves, so we don't recommend doing this.
# alias(
# name = "node_bin",
# actual = select({
# "@bazel_tools//src/conditions:darwin_arm64": "@node16_darwin_arm64//:node_bin",
# "@bazel_tools//src/conditions:darwin_x86_64": "@node16_darwin_amd64//:node_bin",
# "@bazel_tools//src/conditions:linux_aarch64": "@node16_linux_arm64//:node_bin",
# "@bazel_tools//src/conditions:linux_s390x": "@node16_linux_s390x//:node_bin",
# "@bazel_tools//src/conditions:linux_x86_64": "@node16_linux_amd64//:node_bin",
# "@bazel_tools//src/conditions:linux_ppc64le": "@node16_linux_ppc64le//:node_bin",
# "@bazel_tools//src/conditions:windows": "@node16_windows_amd64//:node_bin",
# "//conditions:default": "@node16_linux_amd64//:node_bin",
# }),
# )
# genrule(
# name = "use_node_bin",
# srcs = ["some.js"],
# outs = ["thing1"],
# cmd = "$(execpath :node_bin) $(execpath some.js) $@",
# tools = [":node_bin"],
# )
# You can use the node toolchain together with a genrule().
# This gives you complete control over starting the interpreter, but you also have to
# manually handle module resolution.
genrule(
name = "use_node_toolchain",
srcs = ["some.js"],
outs = ["actual1"],
cmd = "$(NODE_PATH) $(execpath some.js) $@",
toolchains = ["@node16_toolchains//:resolved_toolchain"],
tools = ["@node16_toolchains//:resolved_toolchain"],
)
diff_test(
name = "test_genrule",
file1 = "expected",
file2 = "actual1",
)
# Here, my_nodejs is a fake for something like nodejs_binary or
# some other custom rule that runs node.
my_nodejs(
name = "run",
out = "thing",
entry_point = "some.js",
)
# Assert that the node program wrote the file we expect
diff_test(
name = "test_custom_rule",
file1 = "expected",
file2 = "thing",
)
##########################################################
# Call a program from npm to transform inputs to bazel-out
# For using acorn as our test fixture, this is
# the serialized AST for the JS program just containing a literal "1"
write_file(
name = "write_expected_ast",
out = "expected_ast.json",
content = [
"""{"type":"Program","start":0,"end":1,"body":[{"type":"ExpressionStatement","start":0,"end":1,"expression":{"type":"Literal","start":0,"end":1,"value":1,"raw":"1"}}],"sourceType":"script"}""",
"",
],
)
write_file(
name = "write_one",
out = "one.js",
content = ["1"],
)
genrule(
name = "call_acorn",
srcs = ["one.js"],
outs = ["actual2"],
cmd = """
$(NODE_PATH) \\
./$(execpath @npm_acorn-8.5.0)/bin/acorn \\
--compact \\
$(execpath one.js) \\
> $@""",
toolchains = ["@node16_toolchains//:resolved_toolchain"],
tools = [
"@node16_toolchains//:resolved_toolchain",
"@npm_acorn-8.5.0",
],
)
diff_test(
name = "test_acorn",
file1 = "actual2",
file2 = "expected_ast.json",
)
################################################
# Run a program that requires a package from npm
write_file(
name = "write_program",
out = "require_acorn.js",
content = [
"const fs = require('fs')",
"const acorn = require('acorn')",
"fs.writeFileSync(process.argv[2], JSON.stringify(acorn.parse('1', {ecmaVersion: 2020})) + '\\n')",
],
)
genrule(
name = "require_acorn",
srcs = ["require_acorn.js"],
outs = ["actual3"],
# Note: confusingly, node uses an environment variable NODE_PATH as a "global"
# location for module resolutions, but we used the same name for the Make
# variable exposed by the nodejs tooling.
# One is interpreted by the bash shell, while the other is interpreted by
# bazel, so it doesn't cause any problems.
# Note, the trailing "/.." on the NODE_PATH variable is because our target
# points to the output directory we wrote, named "acorn", but node needs
# to start its module search in a directory *containing" one called "acorn"
cmd = """
NODE_PATH=./$(execpath @npm_acorn-8.5.0)/.. \\
$(NODE_PATH) \\
./$(execpath require_acorn.js) \\
$@""",
toolchains = ["@node16_toolchains//:resolved_toolchain"],
tools = [
"@node16_toolchains//:resolved_toolchain",
"@npm_acorn-8.5.0",
],
)
diff_test(
name = "test_require_acorn",
file1 = "actual3",
file2 = "expected_ast.json",
)
################################################
# Tests and setup for the toolchain changes
# Create file for use in test cases later to get the version of node that is run
write_file(
name = "version",
out = "version.js",
content = ["require('fs').writeFileSync(process.argv[2], process.version)"],
)
# Used in nodejs_bianry later to help see which version of node is run
write_file(
name = "binary_version",
out = "binary_version.js",
content = ["console.log(process.version)"],
)
# Files used in test cases later that contain the correct nodejs version
# that is imported into the workspace.
write_file(
name = "write_node_version_15",
out = "expected_node_15",
content = ["v15.14.0"],
)
write_file(
name = "write_node_version_16",
out = "expected_node_16",
content = ["v16.5.0"],
)
# To see what nodejs version is used by default
my_nodejs(
name = "run_no_toolchain",
out = "thing_no_toolchain",
entry_point = "version.js",
)
# this tests to make sure that the first version imported in the workspace is used as default
diff_test(
name = "node_version_default_toolchain_test",
file1 = "write_node_version_16",
file2 = "thing_no_toolchain",
)
# Output contains the version number of node that is used.
# This is used in tests later to verify the toolchain specified is resolved correctly
my_nodejs(
name = "run_15",
out = "thing_toolchain_15",
entry_point = "version.js",
# using the select statement will download toolchains for all three platforms
# you can also just provide an individual toolchain if you don't want to download them all
toolchain = select({
"@bazel_tools//src/conditions:linux_x86_64": "@node15_linux_amd64//:node_toolchain",
"@bazel_tools//src/conditions:darwin": "@node15_darwin_amd64//:node_toolchain",
"@bazel_tools//src/conditions:windows": "@node15_windows_amd64//:node_toolchain",
}),
)
# Section of test the verify the toolchain work as expected matching node version used with expected
diff_test(
name = "test_node_version_15",
file1 = "write_node_version_15",
file2 = "thing_toolchain_15",
)
my_nodejs(
name = "run_16",
out = "thing_toolchain_16",
entry_point = "version.js",
# using the select statement will download toolchains for all three platforms
# you can also just provide an individual toolchain if you don't want to download them all
toolchain = select({
"@bazel_tools//src/conditions:linux_x86_64": "@node16_linux_amd64//:node_toolchain",
"@bazel_tools//src/conditions:darwin": "@node16_darwin_amd64//:node_toolchain",
"@bazel_tools//src/conditions:windows": "@node16_windows_amd64//:node_toolchain",
}),
)
diff_test(
name = "test_node_version_16",
file1 = "write_node_version_16",
file2 = "thing_toolchain_16",
)