Skip to content

Commit

Permalink
feat: jest coverage output
Browse files Browse the repository at this point in the history
  • Loading branch information
kormide committed Dec 26, 2022
1 parent 6f9515c commit 0ac4b49
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 3 deletions.
17 changes: 17 additions & 0 deletions e2e/case6.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail

# Case 6: generate a coverage report
bazel coverage //jest/tests:case6 --instrument_test_targets

COVERAGE_FILE="bazel-testlogs/jest/tests/case6/coverage.dat"

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

if ! grep -q "foobar" "$COVERAGE_FILE"; then
echo "Coverage file does not contain coverage for foobar function"
exit 1
fi
6 changes: 6 additions & 0 deletions jest/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ bzl_library(
srcs = ["jest_test.bzl"],
visibility = ["//jest:__subpackages__"],
)

sh_binary(
name = "noop",
srcs = ["noop.sh"],
visibility = ["//visibility:public"],
)
23 changes: 22 additions & 1 deletion jest/private/jest_config_template.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// jest.config.js template for jest_test rule
import { existsSync } from "fs";
import { existsSync, readFileSync } from "fs";
import * as path from "path";

// isTest indicates if this is a test target or if this is a binary target generating reference output snapshots for the snapshot updater target
const isTest = !!process.env.TEST_TARGET;
const updateSnapshots = process.env.JEST_TEST__UPDATE_SNAPSHOTS;
const coverageEnabled = !!"{{COVERAGE_ENABLED}}";
const autoConfReporters = !!"{{AUTO_CONF_REPORTERS}}";
const autoConfTestSequencer = !!"{{AUTO_CONF_TEST_SEQUENCER}}";
const userConfigShortPath = "{{USER_CONFIG_SHORT_PATH}}";
Expand Down Expand Up @@ -138,6 +139,26 @@ if (updateSnapshots) {
config.snapshotResolver = bazelSnapshotResolverPath;
}

if (coverageEnabled) {
config.collectCoverage = true;
config.coverageDirectory = path.dirname(process.env.COVERAGE_OUTPUT_FILE);
config.coverageReporters = [
"text",
["lcovonly", { file: path.basename(process.env.COVERAGE_OUTPUT_FILE) }],
];

// Glob pattern paths for which files to cover must be relative to the user's
// jest config file.
const userConfigDir = path.dirname(_resolveRunfilesPath(userConfigShortPath));

// Only generate coverage for files declared in the COVERAGE_MANIFEST
config.collectCoverageFrom = readFileSync(process.env.COVERAGE_MANIFEST)
.toString('utf8')
.split('\n')
.filter((f) => f != '')
.map(f => path.relative(userConfigDir, f));
}

if (process.env.JS_BINARY__LOG_DEBUG) {
console.error(
"DEBUG: aspect_rules_jest[jest_test]: config:",
Expand Down
29 changes: 27 additions & 2 deletions jest/private/jest_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,17 @@ _attrs = dicts.add(js_binary_lib.attrs, {
allow_single_file = True,
default = Label("//jest/private:jest_config_template.mjs"),
),
# Earlier versions of Bazel expect this attribute to be present.
# We use a no-op because jest itself generates the coverage.
"_lcov_merger": attr.label(
executable = True,
default = Label("//jest/private:noop"),
cfg = "exec",
),
})

def _impl(ctx):
providers = []
generated_config = ctx.actions.declare_file("%s__jest.config.mjs" % ctx.label.name)
user_config = copy_file_to_bin_action(ctx, ctx.file.config) if ctx.attr.config else None

Expand All @@ -60,6 +68,7 @@ def _impl(ctx):
"{{BAZEL_SEQUENCER_SHORT_PATH}}": ctx.file.bazel_sequencer.short_path,
"{{BAZEL_SNAPSHOT_REPORTER_SHORT_PATH}}": ctx.file.bazel_snapshot_reporter.short_path,
"{{BAZEL_SNAPSHOT_RESOLVER_SHORT_PATH}}": ctx.file.bazel_snapshot_resolver.short_path,
"{{COVERAGE_ENABLED}}": "1" if ctx.coverage_instrumented() else "",
"{{JUNIT_REPORTER_SHORT_PATH}}": "../{jest_repository}/node_modules/jest-junit/index.js".format(jest_repository = ctx.attr.jest_repository),
"{{USER_CONFIG_SHORT_PATH}}": user_config.short_path if user_config else "",
"{{USER_CONFIG_PATH}}": user_config.path if user_config else "",
Expand Down Expand Up @@ -129,12 +138,28 @@ def _impl(ctx):
for target in ctx.attr.data
])

return [
if ctx.configuration.coverage_enabled:
providers.append(
coverage_common.instrumented_files_info(
ctx,
source_attributes = ["data"],
extensions = [
"mjs",
"cjs",
"js",
"jsx",
],
),
)

providers.append(
DefaultInfo(
executable = launcher.executable,
runfiles = runfiles,
),
]
)

return providers

lib = struct(
attrs = _attrs,
Expand Down
4 changes: 4 additions & 0 deletions jest/private/noop.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -o errexit -o nounset -o pipefail

exit 0
10 changes: 10 additions & 0 deletions jest/tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,13 @@ jest_test(
"case5.test.js",
],
)

# Case 6: Coverage reporting (see e2e test)
jest_test(
name = "case6",
config = "case6.jest.config.js",
data = [
"case6.index.js",
"case6.test.js",
],
)
5 changes: 5 additions & 0 deletions jest/tests/case6.index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function foobar() {
return "foobar";
}

exports.foobar = foobar;
Empty file added jest/tests/case6.jest.config.js
Empty file.
5 changes: 5 additions & 0 deletions jest/tests/case6.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const { foobar } = require("./case6.index.js");

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

0 comments on commit 0ac4b49

Please sign in to comment.