aspect-build / aspect-build/rules_jest

[Bug]: cannot test minimum coverage levels under `bazel test`

Open Beginner friendly
#374 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Starlark
Stars
24
Forks
31
PR merge metrics
No merged PRs in 30d

Description

### What happened?

- A `jest_test` with user config file setting `collectCoverage: true` reports no coverage under `bazel test` (0% or not reported).
- If the config file also has `coverageThreshold` then `bazel test` passes even if the coverage threshold would normally not be met.
- If the config file also has `coverageThreshold` then `bazel test` fails even if the coverage threshold would normally be met.

Expected: coverage is collected correctly under `bazel test` if `collectCoverage` is true, including correctly checking against `coverageThreshold`.

### Version

Development (host) and target OS/architectures:
- macOS 26.6.2 / arm64 (Darwin 25.6.0)
- linux/amd64 (self-hosted GitHub Actions runners in a Linux container)

Host and target are the same in both cases.

Output of bazel --version: bazel 9.2.0

Version of the Aspect rules:

- aspect_rules_jest 0.26.0
- aspect_rules_js 3.4.0
- aspect_rules_ts 3.10.0

Language(s) and/or frameworks involved: TypeScript compiled to CommonJS by ts_project (source maps on, so coverage remaps to src/*.ts), jest 30.0.4, jest-junit 16, Node 24.14.1.

However, the minimal repro below uses jest-cli 30.2.0 and rules_js 3.2.2 as pinned in the e2e/coverage fixture in this repo.

### How to reproduce

Minimal demo using the e2e/coverage fixture in this repo.

- Add `collectCoverage: true` to `e2e/coverage/jest.config.js`
- `cd e2e/coverage`

```
bazel test //:cov_jest --test_output=all --nocache_test_results
```

Expected: `foo.js | 100 | 50 | 100 | 100`

Actual: `All files | 0 | 0 | 0 | 0`

```
bazel coverage //:cov_jest --instrument_test_targets --nocache_test_results --test_output=all
```

Expected & Actual: `foo.js | 100 | 50 | 100 | 100`

Confirmed on main (0bbc22e) on macOS/arm64. Ran with bazel 9.2.0 rather than the pinned 7.7.1.

### Any other information?

### Cause

In `jest/private/jest_config_template.mjs`, there is a `symlinks: false` resolver wrapper. It was added in [aspect-build/rules_jest#366](https://github.com/aspect-build/rules_jest/pull/366). This is a workaround for
[aspect-build/rules_js#2901](https://github.com/aspect-build/rules_js/issues/2901).

This is guarded by `coverageEnabled`, which is set to `!!process.env.COVERAGE_DIR`. So it is only applied under `bazel coverage`. Under `bazel test` the workaround is disabled.

### Suggested fix

Apply the custom resolver unconditionally.

### Workarounds

For anyone else experiencing this issue.

#### Add a custom resolver

```
module.exports = (request, options) =>
request.startsWith('.')
? options.defaultResolver(request, { ...options, symlinks: false })
: options.defaultResolver(request, options);
```

#### Add the coverage env on the jest_test

```
env = {
"COVERAGE_DIR": "$${COVERAGE_DIR:-$$TEST_TMPDIR/cov}",
"COVERAGE_OUTPUT_FILE": "$${COVERAGE_OUTPUT_FILE:-$$TEST_TMPDIR/cov/coverage.dat}",
}
```

Contributor guide

Open the contributing guide

Research direction

Start in jest/private/jest_config_template.mjs, then inspect the e2e/coverage fixture and its jest.config.js. Run bazel test //:cov_jest --test_output=all --nocache_test_results from e2e/coverage and compare it with bazel coverage. Done means bazel test collects coverage and enforces coverageThreshold with the expected foo.js results.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, node.js, typescript
Domain
build-system, testing
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.