jestjs / jest

Delightful JavaScript Testing.
https://jestjs.io
MIT License
44.28k stars 6.47k forks source link

[Bug]: Untested files are missing when collecting coverage in multi-project configuration #15358

Open tbossi opened 3 weeks ago

tbossi commented 3 weeks ago

Version

29.7.0

Steps to reproduce

  1. Clone my repo https://github.com/tbossi/jest-bug-coverage-per-project The repo contains two folders coverage-global and coverage-per-project. They are the same codebase with the exact same code but different Jest configuration.
  2. In each of those folders run npm install then npm run test:coverage.
  3. You can see the files included in coverage report are different depending on which of the two main folder you look at.
  4. Additionally, enter in any of the packages (for example pack1) again in both folders coverage-global and coverage-per-project. Then run npm run test:coverage for that single package.
  5. You can see the files included in these coverage report are different.

Expected behavior

The files without tests (pack1/file-without-test-1.js and pack2/file-without-test-2.js) should always be present in the coverage report if collectCoverageFrom is set on each package (both when running jest from root and from each individual package).

Actual behavior

The files without tests (pack1/file-without-test-1.js and pack2/file-without-test-2.js) are present in the coverage report only if:

Additional context

The project shown in the repo is organized using npm workspaces. There is a global jest configuration file (jest.config.js) that maps workspaces to jest's projects setting. Individual packages each have their own configuration file, and share a common preset (jest.preset.js).

In this context, I want jest --coverage to also show me files without tests in each package. For this reason I used the collectCoverageFrom setting. However, this setting combined with the projects one seems to have unexpected results.

When setting collectCoverageFrom in the root jest.config.js (as it is in folder coverage-global) the files without tests are visible only when jest is run from the root, and not for a single package. That is kind of expected, since the jest.config.js of a single package has no setting collectCoverageFrom even in the preset.

What is not expected, is the other case (in folder coverage-per-project), where collectCoverageFrom is set in the preset and therefore shared by the jest.config.js of each single package. In this situation, which by the way is my go to configuration when dealing with jest combined with workspaces, if you run jest for a single package then the coverage of that package is correct. But if you run jest from the root then the files without coverage are missing. Also note that having collectCoverageFrom in a preset is just to simplify the problem, but each individual package could also have its own collectCoverageFrom with different values.

I also did a bit of research on my own to find the root cause, and it seems to boil down to the method _addUntestedFiles of CoverageReporter. In the for loop there is a call to context.hasteFS.matchFilesWithGlob passing the global config, but there is no call to the same function passing the config of the current context under iteration. Adding that missing piece seems to solve the issue, but I'm not sure if it's the right way to fix it.

Environment

System:
  OS: Windows 11 10.0.22631
  CPU: (12) x64 Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz
Binaries:
  Node: 20.13.0 - ~\AppData\Local\nvs\default\node.EXE
  npm: 10.5.2 - ~\AppData\Local\nvs\default\npm.CMD
npmPackages:
  jest: ^29.7.0 => 29.7.0