"""Rule for running test suites with Bun.""" load("//internal:js_library.bzl", "BunSourcesInfo") def _shell_quote(value): return "'" + value.replace("'", "'\"'\"'") + "'" def _bun_test_impl(ctx): toolchain = ctx.toolchains["//bun:toolchain_type"] bun_bin = toolchain.bun.bun_bin src_args = " ".join([_shell_quote(src.short_path) for src in ctx.files.srcs]) launcher = ctx.actions.declare_file(ctx.label.name) ctx.actions.write( output = launcher, is_executable = True, content = """#!/usr/bin/env bash set -euo pipefail runfiles_dir="${{RUNFILES_DIR:-$0.runfiles}}" bun_bin="${{runfiles_dir}}/_main/{bun_short_path}" cd "${{runfiles_dir}}/_main" if [[ -n "${{TESTBRIDGE_TEST_ONLY:-}}" && -n "${{COVERAGE_DIR:-}}" ]]; then exec "${{bun_bin}}" --bun test {src_args} --test-name-pattern "${{TESTBRIDGE_TEST_ONLY}}" --coverage "$@" fi if [[ -n "${{TESTBRIDGE_TEST_ONLY:-}}" ]]; then exec "${{bun_bin}}" --bun test {src_args} --test-name-pattern "${{TESTBRIDGE_TEST_ONLY}}" "$@" fi if [[ -n "${{COVERAGE_DIR:-}}" ]]; then exec "${{bun_bin}}" --bun test {src_args} --coverage "$@" fi exec "${{bun_bin}}" --bun test {src_args} "$@" """.format( bun_short_path = bun_bin.short_path, src_args = src_args, ), ) transitive_files = [] if ctx.attr.node_modules: transitive_files.append(ctx.attr.node_modules[DefaultInfo].files) for dep in ctx.attr.deps: if BunSourcesInfo in dep: transitive_files.append(dep[BunSourcesInfo].transitive_sources) else: transitive_files.append(dep[DefaultInfo].files) runfiles = ctx.runfiles( files = [bun_bin] + ctx.files.srcs + ctx.files.data, transitive_files = depset(transitive = transitive_files), ) return [ DefaultInfo( executable = launcher, runfiles = runfiles, ), ] bun_test = rule( implementation = _bun_test_impl, doc = """Runs Bun tests as a Bazel test target. Supports Bazel test filtering (`--test_filter`) and coverage integration. """, attrs = { "srcs": attr.label_list( mandatory = True, allow_files = [".js", ".ts", ".jsx", ".tsx", ".mjs", ".cjs"], doc = "Test source files passed to `bun test`.", ), "node_modules": attr.label( doc = "Optional label providing Bun/npm package files in runfiles.", ), "deps": attr.label_list( doc = "Library dependencies required by test sources.", ), "data": attr.label_list( allow_files = True, doc = "Additional runtime files needed by tests.", ), }, test = True, toolchains = ["//bun:toolchain_type"], )