blob: 27fc5f531ba11c41dbaf3aa7c6049d8aa71d40a5 [file]
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
load("@bazel_skylib//rules:write_file.bzl", "write_file")
load(":defs.bzl", "my_nodejs")
not_windows = select({
# There isn't a published rosetta binary for windows as of Feb 2024
"@platforms//os:windows": ["@platforms//:incompatible"],
"//conditions:default": [],
})
not_silicon = select({
# There isn't a published arm64 binary for Node 15
"@platforms//cpu:arm64": ["@platforms//:incompatible"],
"//conditions:default": [],
})
# 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 un-configured analysis (bazel query for example)
# 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": "@nodejs_darwin_arm64//:node_bin",
# "@bazel_tools//src/conditions:darwin_x86_64": "@nodejs_darwin_amd64//:node_bin",
# "@bazel_tools//src/conditions:linux_aarch64": "@nodejs_linux_arm64//:node_bin",
# "@bazel_tools//src/conditions:linux_s390x": "@nodejs_linux_s390x//:node_bin",
# "@bazel_tools//src/conditions:linux_x86_64": "@nodejs_linux_amd64//:node_bin",
# "@bazel_tools//src/conditions:linux_ppc64le": "@nodejs_linux_ppc64le//:node_bin",
# "@bazel_tools//src/conditions:windows": "@nodejs_windows_amd64//:node_bin",
# "//conditions:default": "@nodejs_linux_amd64//:node_bin",
# }),
# )
# genrule(
# name = "use_node_bin",
# srcs = ["some.js"],
# outs = ["thing1"],
# cmd = "$(execpath :node_bin) $(execpath some.js) $@",
# tools = [":node_bin"],
# )
# Ensure genrule()s at least build due to diff_test()s being disabled on windows.
build_test(
name = "test_build",
targets = [
":call_acorn",
":require_acorn",
":use_nodejs_toolchain",
],
)
# 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_nodejs_toolchain",
srcs = ["some.js"],
outs = ["actual1"],
cmd = "$(NODE_PATH) $(execpath some.js) $@",
toolchains = ["@nodejs_toolchains//:resolved_toolchain"],
)
diff_test(
name = "test_genrule",
file1 = "expected",
file2 = "actual1",
# diff_test has line endings issues on Windows
target_compatible_with = not_windows,
)
# 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 = ["@nodejs_toolchains//:resolved_toolchain"],
tools = [
"@nodejs_toolchains//:resolved_toolchain",
"@npm_acorn-8.5.0",
],
)
diff_test(
name = "test_acorn",
file1 = "actual2",
file2 = "expected_ast.json",
# diff_test has line endings issues on Windows
target_compatible_with = not_windows,
)
################################################
# 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')",
"const parsed = JSON.stringify(acorn.parse('1', {ecmaVersion: 2020}))",
"fs.writeFileSync(process.argv[2], parsed + '\\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 = ["@nodejs_toolchains//:resolved_toolchain"],
tools = [
"@nodejs_toolchains//:resolved_toolchain",
"@npm_acorn-8.5.0",
],
)
diff_test(
name = "test_require_acorn",
file1 = "actual3",
file2 = "expected_ast.json",
# diff_test has line endings issues on Windows
target_compatible_with = not_windows,
)
genrule(
name = "npm_help",
outs = ["help.txt"],
cmd = "$(NPM_PATH) --help > $@ || true",
toolchains = ["@nodejs_toolchains//:resolved_toolchain"],
tools = ["@nodejs_toolchains//:resolved_toolchain"],
)
################################################
# 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_17",
out = "expected_node_17",
content = ["v17.9.1"],
)
write_file(
name = "write_node_version_16",
out = "expected_node_16",
content = ["v16.5.0"],
)
write_file(
name = "write_node_version_24",
out = "expected_node_24",
content = ["v24.12.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_17",
out = "thing_toolchain_17",
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": "@node17_linux_amd64//:toolchain",
"@bazel_tools//src/conditions:linux_aarch64": "@node17_linux_arm64//:toolchain",
"@bazel_tools//src/conditions:darwin_x86_64": "@node17_darwin_amd64//:toolchain",
"@bazel_tools//src/conditions:darwin_arm64": "@node17_darwin_arm64//:toolchain",
"@bazel_tools//src/conditions:windows": "@node17_windows_amd64//:toolchain",
}),
)
# Section of test the verify the toolchain work as expected matching node version used with expected
diff_test(
name = "test_node_version_17",
file1 = "write_node_version_17",
file2 = "thing_toolchain_17",
)
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": "@nodejs_linux_amd64//:toolchain",
"@bazel_tools//src/conditions:linux_aarch64": "@nodejs_linux_arm64//:toolchain",
"@bazel_tools//src/conditions:darwin_x86_64": "@nodejs_darwin_amd64//:toolchain",
"@bazel_tools//src/conditions:darwin_arm64": "@nodejs_darwin_arm64//:toolchain",
"@bazel_tools//src/conditions:windows": "@nodejs_windows_amd64//:toolchain",
}),
)
diff_test(
name = "test_node_version_16",
file1 = "write_node_version_16",
file2 = "thing_toolchain_16",
)
my_nodejs(
name = "run_15",
out = "thing_toolchain_15",
entry_point = "version.js",
target_compatible_with = not_silicon,
# 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//:toolchain",
"@bazel_tools//src/conditions:darwin_x86_64": "@node15_darwin_amd64//:toolchain",
"@bazel_tools//src/conditions:windows": "@node15_windows_amd64//:toolchain",
}),
)
diff_test(
name = "test_node_version_15",
file1 = "write_node_version_15",
file2 = "thing_toolchain_15",
)
my_nodejs(
name = "run_24",
out = "thing_toolchain_24",
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": "@node24_linux_amd64//:toolchain",
"@bazel_tools//src/conditions:linux_aarch64": "@node24_linux_arm64//:toolchain",
"@bazel_tools//src/conditions:darwin_x86_64": "@node24_darwin_amd64//:toolchain",
"@bazel_tools//src/conditions:darwin_arm64": "@node24_darwin_arm64//:toolchain",
"@bazel_tools//src/conditions:windows": "@node24_windows_amd64//:toolchain",
}),
)
diff_test(
name = "test_node_version_24",
file1 = "write_node_version_24",
file2 = "thing_toolchain_24",
)