c8 icon indicating copy to clipboard operation
c8 copied to clipboard

bug: finally block in async function indicates incorrect missing block coverage

Open bcoe opened this issue 4 years ago • 10 comments

Observed Behavior

The following code:

async function abc() {
  try {
    return 'abc';
  } finally {
    console.log('in finally');
  } // this is a covered line but uncovered branch
}

abc()

Ends up having the following coverage output:

{
          "functionName": "abc",
          "ranges": [
            {
              "startOffset": 0,
              "endOffset": 146,
              "count": 1
            },
            {
              "startOffset": 97,
              "endOffset": 145,
              "count": 0
            }
          ],
          "isBlockCoverage": true
        }
}

This indicates that the following characters were tracked as an uncovered block:

// this is a covered line but uncovered branch\n

Expected behavior

Coverage should be 100% in the above example.

bcoe avatar Jun 19 '20 23:06 bcoe

I have created a tracking issue on v8 here:

https://bugs.chromium.org/p/v8/issues/detail?id=10628

bcoe avatar Jun 19 '20 23:06 bcoe

I'm not sure if it's related, but I think I hit this? I happened to be on c8 v7.4.0 when I encountered the failure in CI, but it reproduces in v7.5.0 when run on node v12.20.1.

The tests pass, it's just the mysterious coverage gap on an async function that fails in node v12. v14 is fine.

https://github.com/dendrochronologist/cli/commit/edd0aaf93026f85df1aef64cd51d48bb3d6c700f "fixes" it by ignoring the missed line. Not ideal, long-term.

However, if I avoid using the async keyword, it passes again:

diff --git a/src/api.ts b/src/api.ts
index 99472c5..69c22ef 100644
--- a/src/api.ts
+++ b/src/api.ts
@@ -9,7 +9,7 @@ interface RunOptions extends Partial<ParsedConfig> {
   logger?: MinimalLogger;
 }
 
-export async function run({
+export function run({
   logger = processLogger(),
   ...options
 }: RunOptions): Promise<Node> {
@@ -22,8 +22,5 @@ export async function run({
   const arb = new Arborist({
     path: cwd,
   });
-  const tree = await arb.loadVirtual().catch(() => arb.loadActual());
-
-  return tree;
-  /* c8 ignore next */
+  return arb.loadVirtual().catch(() => arb.loadActual());
 }

I validated this locally with

volta run --node 12 npm test

evocateur avatar Feb 03 '21 00:02 evocateur

To be clear, the node v14 I was passing with is v14.15.4. Which tracks, given the release of the linked back-porting. I have literally no idea if it could (or should?) be back-ported to v12, though it seems like a good candidate if someone has bandwidth?

evocateur avatar Feb 03 '21 00:02 evocateur

@evocateur there are some v8 bug fixes that have landed in v14/v15, that I don't think got backported to v12 unfortunately -- I'm pretty sure that v12 might be closed to extension at this point unfortunately.

bcoe avatar Feb 05 '21 18:02 bcoe

@bcoe Perfectly fair! Especially considering it's going into maintenance mode in like, 2 months? So I'll probably drop v12 before I even finish this wee babby of a tool, lol.

evocateur avatar Feb 06 '21 23:02 evocateur

Just ran into this one as well. Rough one to debug. Any update regarding a fix?

simlu avatar Mar 31 '22 16:03 simlu

I'm encountering something similar. My finally block has a coverage of 26, while the keyword finally has no coverage.

image

I'm using 5 finally statements in the entire solution, 4 of them are working as expected, only this one has no coverage. I have no idea how this is possible. I can send you a link to the code so you can see the problem yourself.

Update

Noticed that if you remove the throw statement in the catch block, that the finally is hit. However the amount of hits seems wrong.

image

milanholemans avatar Sep 15 '22 19:09 milanholemans

I'm also getting the same issue with a finally block. But this is not an async function.

image

Everything is 100% covered but the branch reports a 96.15% coverage

I just added an ignore comment for now image

xolott avatar Oct 13 '22 18:10 xolott

@xolott would you be able to provide a minimal breaking example, this would help in investigating the underlying cause.

bcoe avatar Nov 03 '22 18:11 bcoe

@bcoe I have run into a similar issue as reported by @xolott, where the generated output is showing the finally block as uncovered. If you are still interested in troubleshooting, here is a minimum example repro

EDIT: Just noticed that if you change the handler to finish without returning then the finally block is marked as covered: await orchestrator.activate()

archiehharris avatar Jun 14 '24 17:06 archiehharris