Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/vitest_test.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions e2e/case14.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail

# Case 14: generate a coverage report when the vitest config sets an explicit
# test.root. The covered source lives under the root, so include globs must
# resolve relative to it (no `..` prefix) and coverage must be produced.
bazel coverage //vitest/tests:case14 --instrument_test_targets

COVERAGE_FILE="bazel-testlogs/vitest/tests/case14/coverage.dat"

if [ ! -f "$COVERAGE_FILE" ]; then
echo "Missing coverage file $COVERAGE_FILE"
exit 1
fi

if ! grep -q "SF:vitest/tests/case14/src/case14.index.js" "$COVERAGE_FILE"; then
echo "Coverage file does not contain coverage for covered function"
exit 1
fi
5 changes: 5 additions & 0 deletions vitest/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ def vitest_test(
minus TypeScript since we this rule extends from the configuration. TypeScript vitest configs should be transpiled
before being passed to vitest_test with [rules_ts](https://github.com/aspect-build/rules_ts).

An explicit `test.root` in the config is honored; a relative value is resolved against the config
file's directory. When `test.root` is not set it defaults to the target's package directory. Coverage
`include` globs are resolved relative to `test.root`, so an explicit root must contain the source files
under test.

data: Runtime dependencies of the Vitest test.

This should include all test files, configuration files & files under test.
Expand Down
23 changes: 18 additions & 5 deletions vitest/private/vitest_config_template.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ const projectRoot = path.join(
);


// Glob pattern paths for which files to cover must be relative to this
// vitest config file in runfiles.
const vitestConfigDir = path.dirname(
_resolveRunfilesPath(generatedConfigShortPath),
);

// Directory of the user config file, used to resolve a relative explicit
// `test.root` the way Vitest would (relative to the config file).
const userConfigDir = userConfigShortPath
? path.dirname(_resolveRunfilesPath(userConfigShortPath))
: vitestConfigDir;

function _resolveRunfilesPath(rootpath) {
return path.join(projectRoot, rootpath);
}
Expand Down Expand Up @@ -67,7 +71,15 @@ if (userConfigShortPath) {
if (!config.test) {
config.test = {};
}
config.test.root = vitestConfigDir;

// Vitest defaults `test.root` to `process.cwd()`, which under Bazel is the
// output-tree root rather than the package, so a value must always be set.
// Default to the generated config's directory, but honor an explicit user
// `test.root` (a relative one resolved against the user config file, as
// Vitest would) instead of clobbering it.
config.test.root = config.test.root
? path.resolve(userConfigDir, config.test.root)
: vitestConfigDir;

if (autoConfTestSequencer) {
if (config.test.sequence) {
Expand Down Expand Up @@ -126,13 +138,14 @@ if (coverageEnabled) {
reporter: ["text", ["lcov", { file: coverageFile, projectRoot }]],
};

// Only generate coverage for files declared in the COVERAGE_MANIFEST
// Glob pattern paths for which files to cover must be relative to test.root,
// which Vitest resolves coverage include globs against.
config.test.coverage.include = fs
.readFileSync(process.env.COVERAGE_MANIFEST)
.toString("utf8")
.split("\n")
.filter((f) => f !== "")
.map((f) => path.relative(vitestConfigDir, path.join(projectRoot, f)));
.map((f) => path.relative(config.test.root, path.join(projectRoot, f)));
}

if (process.env.JS_BINARY__LOG_DEBUG) {
Expand Down
24 changes: 24 additions & 0 deletions vitest/tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,27 @@ vitest_test(
],
node_modules = "//:node_modules",
)

# Case 13: an explicit relative test.root must be honored and resolved against
# the config file's directory, not clobbered by the package directory.
vitest_test(
name = "case13",
config = "case13/case13.vitest.config.mjs",
data = [
"case13/case13.test.js",
"case13/src/case13.setup.js",
],
node_modules = "//:node_modules",
)

# Case 14: coverage with an explicit test.root (see e2e test); the covered
# source lives under the root, so include globs must resolve relative to it.
vitest_test(
name = "case14",
config = "case14/case14.vitest.config.mjs",
data = [
"case14/src/case14.index.js",
"case14/src/case14.test.js",
],
node_modules = "//:node_modules",
)
5 changes: 5 additions & 0 deletions vitest/tests/case13/case13.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { test, expect } from "vitest";

test("explicit relative test.root is honored", () => {
expect(globalThis.__CASE13_ROOT__).toBe("src");
});
11 changes: 11 additions & 0 deletions vitest/tests/case13/case13.vitest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig } from "vitest/config";

// Explicit relative test.root: must be honored and resolved against this config
// file's directory, so setupFiles below resolves under src/.
export default defineConfig({
test: {
environment: "node",
root: "./src",
setupFiles: ["./case13.setup.js"],
},
});
1 change: 1 addition & 0 deletions vitest/tests/case13/src/case13.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
globalThis.__CASE13_ROOT__ = "src";
10 changes: 10 additions & 0 deletions vitest/tests/case14/case14.vitest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from "vitest/config";

// Coverage combined with an explicit test.root: the covered source lives under
// the root, so include globs must resolve relative to it without a `..` prefix.
export default defineConfig({
test: {
environment: "node",
root: "./src",
},
});
5 changes: 5 additions & 0 deletions vitest/tests/case14/src/case14.index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function covered() {
return "covered";
}

exports.covered = covered;
6 changes: 6 additions & 0 deletions vitest/tests/case14/src/case14.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const { test, expect } = await import("vitest");
const { covered } = require("./case14.index.js");

test("covered", () => {
expect(covered()).toEqual("covered");
});