Source Map issues with Browserify and Webpack
See original GitHub issueLink to bug demonstration repository
agilgur5/physijs-webpack#coverage
Relevant files are browserify.js and webpack.js as well as their respective tests browserify.spec.js and webpack.spec.js which are all like 5-10 LoC each. package.json scripts and nyc.config.js for config.
(vendored files are physi.js, physijs_worker.js, and vendor/ammo.js, which are mostly ignorable)
For context, my library is an integration for bundlers, including out-of-the-box support for webpack and browserify, so my tests are literally to ensure that the integration itself works (and not that physijs works). An important aspect of this is WebWorker support for both bundlers.
This means that I have to test the bundled code, and not the source files themselves. The source code is all ES5, so no transpilation needed (though the test code is not necessarily). The code can be bundled for both bundlers with npm run build: test.
It seemed like nyc’s source map support would handle this use case, but I ran into some issues with both bundlers.
Expected Behavior
- I expect the output of
npx nyc ava browserify.spec.jsto be:
-----------------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
browserify: | 100 | 100 | 100 | 100 | |
browserify.js | 100 | 100 | 100 | 100 | |
----------------------------|----------|----------|----------|----------|-------------------|
- I expect the output of
npx nyc ava webpack.spec.jsto be:
-----------------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
webpack: | 100 | 100 | 100 | 100 | |
webpack.js | 100 | 100 | 100 | 100 | |
----------------------------|----------|----------|----------|----------|-------------------|
Observed Behavior
There are 2 different, but potentially related bugs, I’m encountering:
- For
browserify, I have source maps output to a separate.mapfile withexorcist, but none of the bundle itself or the source code ends up being output in the coverage. The output ofnpx nyc ava browserify.spec.jsis:
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 0 | 0 | 0 | 0 | |
----------|----------|----------|----------|----------|-------------------|
I don’t really know why the code in build/ and the source mapped code isn’t included. The file I’m looking to be included without source maps is browserify.bundle.js and with source maps the files are browserify.js (and maybe physijs_worker.js and/or physi.js for further testing). Why are those not included?
- For
webpack, which runs virtually identical code (just a different bundler andworker-loaderinstead ofwebworkify), the output does coverwebpack.bundle.jsand the source mapped files,webpack.js,physi.js, andphysijs_worker.jsare shown in the coverage report. The output ofnpx nyc ava webpack.spec.jsis:
-----------------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------------------------|----------|----------|----------|----------|-------------------|
All files | 23.64 | 3.46 | 8.51 | 23.82 | |
webpack: | 23.42 | 3.46 | 8.51 | 23.59 | |
physi.js | 22.73 | 3.46 | 7.53 | 22.9 |... 1394,1395,1396 |
physijs_worker.js | 100 | 100 | 100 | 100 | |
webpack.js | 100 | 100 | 100 | 100 | |
webpack:/test-utils/webpack | 100 | 100 | 100 | 100 | |
_export-to-window.js | 100 | 100 | 100 | 100 | |
-----------------------------|----------|----------|----------|----------|-------------------|
The exclude is set to ignore test-utils/**, physi.js, and physijs_worker.js, but they still show up in the reported coverage through the source maps. (I’m also pretty sure the 100% coverage of physijs_worker.js is incorrect, but that’s probably unrelated?). The code in test-utils that’s imported directly (not source mapped) is correctly excluded/hidden, but the source mapped code is incorrectly shown. How do I exclude/hide these source mapped files?
There doesn’t seem to be much documentation for testing source-mapped bundles. nyc seems to try to handle it automatically and there is the babel preset for babel instrumentation, but I’m not transpiling any code, just bundling it.
I also have both webpack and browserify set to output source maps to a separate .map file, but I’m not sure if that’s necessary. ~The README says inline source maps are supported, but using cheap-eval-source-map for webpack causes the source maps to not work~ EDIT: it should be inline-cheap-source-map, woops.
Troubleshooting steps
- still occurring when I put
cache: falsein my nyc config
Environment Information
System:
OS: macOS High Sierra 10.13.6
CPU: (4) x64 Intel(R) Core(TM) i5-4278U CPU @ 2.60GHz
Memory: 64.03 MB / 8.00 GB
Binaries:
Node: 8.4.0 - /usr/local/bin/node
npm: 6.9.0 - /usr/local/bin/npm
npmPackages:
nyc: ^14.1.1 => 14.1.1
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (1 by maintainers)

Top Related StackOverflow Question
Hey @coreyfarrell,
Thanks for your detailed writeup. This is gonna be in response to WebWorkers and I just realized that this comment maybe belongs in a diff repo or issue, but here we go…
So, in a browser-testing setup, Istanbul’s transpiled code is running in the browser, while coverage results are sent back over the wire to Node so that NYC can consume and process the results. NYC is still node-side, but because it wraps + kicks off Istanbul, I need to be able to pass in certain options to a given instrumenter. Can you help me figure out how to configure Istanbul’s options through NYC?
I need to either:
globalThisinstead ofthisorwindow).https://github.com/istanbuljs/istanbuljs/blob/2b747cfc636a6e9b991d30fe5d25fec3667ff151/packages/istanbul-lib-instrument/src/instrumenter.js#L100-L102
So if I hardcode Istanbul’s
coverageGlobalScopeto useglobalThisinstead ofthis(window), then my browser tests run fine and coverage works for WebWorkers… but I can only do it with patch-package orpnpm patchbecause I don’t know how to setcoverageGlobalScope😅 .Workaround patch here for
istanbul-lib-instrument:How can I pass through
coverageGlobalScopefrom NYC =>istanbul-lib-instrument?I noticed your are using nyc 14, there were some source-map fixes which went into nyc 15 (particularly related to bundled code), please give this a try to see if it improves the ability to ignore parts of the bundle. You should be able to tell istanbul to exclude
src/some-file.js. This would still produce coverage counters inside the bundle but whennyc reportsees that exclude it would drop the coverage associated by source-maps tosrc/some-file.jsfrom the report. This was done in nyc 15 only as it is a breaking change - I’ve gotten bug reports for 15 due to people not realizing the change effected their project. Note upgrading from nyc 14 to 15 may require upgrading 3rd party components to ensure the onlyistanbul-*modules are those versions installed by nyc 15.With regard to browser web workers this is completely out of scope for nyc as nyc does not run in the browser. If you create a simple
file.jsthen runnyc instrument --compact=false file.jsyou will see the code we generate. The code generated by istanbul initializes a global__coverage__variable. nyc has hooks into node.js which intercept process exit and writeJSON.stringify(global.__coverage__)to a file in.nyc_output. When you run code in the browser it is the responsibility of the browser automation library to handle this upon each JS global context exit. For most code this means the browser automation library will hook page navigation and grab the variable. I’m not sure if they can do the same for web worker threads (which each have their own isolated JS global context). This would be a question for cypress and ultimately it would require that the browser provide necessary hooks for cypress to detect “this web worker is about to exit”.Sorry this issue has sat for so long without response, istanbul maintainers are spread very thin and integration issues require an additional level of knowledge. I’ve blocked stale bot from touching this issue in the future. My hope is that someone in the community with knowledge of webpack / browserify can provide some insights. Please understand nyc is designed to test coverage in node.js. nyc does not directly support any other platform, though the instrumented code it generates does try to support running on as many JS platforms as possible. Please be aware source-map handling is probably the most difficult part of istanbul, it’s a minefield. That’s not completely a reflection of our code but source-maps are just difficult.