This repro shows how methods defined on a class with the arrow =>
syntax break the coverage report in WTR in certain situations.
For issues modernweb-dev/web#689 and istanbuljs/v8-to-istanbul#121
To reproduce run npm install
then npm test
, and open coverage/lcov-report/bad.js.html
.
Instead of coverage for the affected file, one will see:
Cannot read property 'decl' of undefined
TypeError: Cannot read property 'decl' of undefined
at /Users/xxxx/wtr-coverage-repro/node_modules/istanbul-reports/lib/html/annotator.js:89:31
at Array.forEach ()
at annotateFunctions (/Users/xxxx/wtr-coverage-repro/node_modules/istanbul-reports/lib/html/annotator.js:86:29)
at annotateSourceCode (/Users/xxxx/wtr-coverage-repro/node_modules/istanbul-reports/lib/html/annotator.js:234:9)
at HtmlReport.onDetail (/Users/xxxx/wtr-coverage-repro/node_modules/istanbul-reports/lib/html/index.js:409:33)
at LcovReport. [as onDetail] (/Users/xxxx/wtr-coverage-repro/node_modules/istanbul-reports/lib/lcov/index.js:28:23)
at Visitor.value (/Users/xxxx/wtr-coverage-repro/node_modules/istanbul-lib-report/lib/tree.js:38:38)
at ReportNode.visit (/Users/xxxx/wtr-coverage-repro/node_modules/istanbul-lib-report/lib/tree.js:88:21)
at /Users/xxxx/wtr-coverage-repro/node_modules/istanbul-lib-report/lib/tree.js:92:19
at Array.forEach ()
The suspected cause of this bug is:
- Each test runs in its own context, and coverage is collected for all files which are loaded in each test run
- The metadata for functions in a file is stored from the first run that included that file
- The coverage is combined from all test runs to produce the final coverage numbers
- Methods authored with the arrow syntax
=>
are only defined at runtime when the constructor is executed, and if in point 2. the constructor in a file isn't executed, the metadata for those methods won't exist.
In this repro:
1-test.js
loadsGood
throughindex.js
which also includesBad.js
.Bad.js
is executed and so gains some coverage information, butBad
's constructor is never executed, so point 4. above never occurs.- The coverage information is collected, but metadata about
Bad.method
doesn't exist, because that function never did exist in this test run
2-test.js
runs, and this does executeBad
's constructor and so now there is coverage information forBad.method
- When the coverage details are generated, and the coverage of
Bad.method
is collated the metadata forBad.method
does not exist, because the metadata was only stored from the first run of1-test.js
. This is what results in the above stack trace.