| 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", |
| ) |