GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Inconsistent coverage information when loaders used · Issue #41387 · nodejs/node

Inconsistent coverage information when loaders used #41387

New issue
Copy link
New issue
Copy link
Closed as not planned
Closed as not planned
Inconsistent coverage information when loaders used#41387
Copy link
Labels
coverageIssues and PRs related to Node.js code coverage support.Issues and PRs related to Node.js code coverage support.loadersIssues and PRs related to ES module loaders.Issues and PRs related to ES module loaders.staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.

Description

@coderaiser
coderaiser
opened on Jan 3, 2022
Issue body actions

Version

v14, v16, v17 latest

Platform

Linux, Darwin

Subsystem

No response

What steps will reproduce the bug?

🐛 What is bug related to?

The bug is related to coverage tool c8 it used to build coverage report for projects that are tested using mock-import.

Loaders

mock-import is a library built on top of loaders, it supports both versions of API. I know that this is experimental technology, anyways I'm using it on my projects, it works amazing and I'm ready for any API changes. By the way second version is better of Loaders API and it is much simpler, BUT would be great if both versions can co-exist without the need of passing NODE_OPTIONS. You don't need to support both versions, but please give ability for userland modules to smooth this differences, and have ability to write polyfil for it.

Why use loaders to mock imports?

Because it feats very well for using mocks in tests in the same way we used mock-require in good old days we had only CommonJS, since we don't have access to cache of EcmaScript Modules. So it's:

  • ✅ ESM friendly;
  • ✅ has ability to by-pass cache using query suffix: ?mock-import-count=x;
  • ✅ changes ImportDeclaration to VariableDeclaration to get mocked code from predefined storage

To get transformations working 🐊Putout code transformer used, it based on Babel.

What is problem with transforming files on-a-fly using Loaders?

The coverage is the problem with mocked files transformed by loading. Since c8 uses NODE_V8_COVERAGE to put coverage on screen.

132669108-53525a81-6bb5-4a72-aa07-81360ce1b5c5

More low level details

You can see here all the story. The thing is for similar code fragments generated different coverage information.

So for code fragment with no transformation:

import {
    readFile,
} from 'fs/promises';

import {
    execSync,
} from 'child_process';

export default (a, b, c) => {
    if (a)
        return readFile();

      if (c)
          return execSync();

      return 'd';
};

With mocked first import:

const {
    readFile: readFile
} = global.__mockImportCache.get('fs/promises');

import {
    execSync,
} from 'child_process';

export default (a, b, c) => {
    if (a)
        return readFile();

      if (c)
          return execSync();

      return 'd';
}

And with mocking second-one

import {
    readFile,
} from 'fs/promises';

const {
    execSync: execSync
} = global.__mockImportCache.get('child_process');

export default (a, b, c) => {
    if (a)
        return readFile();

      if (c)
          return execSync();

      return 'd';
};

I have such coverage results that c8 get from coverage directory generated by node:
ranges for functionNam=default is different: two positions, three and three. This is conditions, third-one is absent in first report. Why is so?

{
    "result": [
        {
            "scriptId": "0",
            "url": "file:///Users/coderaiser/c8-reproduce/lib/changelog.js?mock-import-count=1",
            "functions": [
                {
                    "functionName": "",
                    "ranges": [
                        {
                            "startOffset": 0,
                            "endOffset": 1824,
                            "count": 1
                        }
                    ],
                    "isBlockCoverage": true
                },
                {
                    "functionName": "default",
                    "ranges": [
                        {
                            "startOffset": 144,
                            "endOffset": 271,
                            "count": 1
                        },
                        {
                            "startOffset": 196,
                            "endOffset": 270,
                            "count": 0
                        }
                    ],
                    "isBlockCoverage": true
                }
            ]
        },
        {
            "scriptId": "1",
            "url": "file:///Users/coderaiser/c8-reproduce/lib/changelog.js?mock-import-count=2",
            "functions": [
                {
                    "functionName": "",
                    "ranges": [
                        {
                            "startOffset": 0,
                            "endOffset": 1820,
                            "count": 1
                        }
                    ],
                    "isBlockCoverage": true
                },
                {
                    "functionName": "default",
                    "ranges": [
                        {
                            "startOffset": 144,
                            "endOffset": 271,
                            "count": 1
                        },
                        {
                            "startOffset": 178,
                            "endOffset": 196,
                            "count": 0
                        },
                        {
                            "startOffset": 244,
                            "endOffset": 270,
                            "count": 0
                        }
                    ],
                    "isBlockCoverage": true
                }
            ]
        },
        {
            "scriptId": "2",
            "url": "file:///Users/coderaiser/c8-reproduce/lib/changelog.js?mock-import-count=3",
            "functions": [
                {
                    "functionName": "",
                    "ranges": [
                        {
                            "startOffset": 0,
                            "endOffset": 1929,
                            "count": 1
                        }
                    ],
                    "isBlockCoverage": true
                },
                {
                    "functionName": "default",
                    "ranges": [
                        {
                            "startOffset": 109,
                            "endOffset": 236,
                            "count": 1
                        },
                        {
                            "startOffset": 143,
                            "endOffset": 161,
                            "count": 0
                        },
                        {
                            "startOffset": 191,
                            "endOffset": 209,
                            "count": 0
                        }
                    ],
                    "isBlockCoverage": true
                }
            ]
        }]
}

Looks like this is the reason why c8 shows that lines are not covered. But they are.

To reproduce bug clone repository with

git clone https://github.com/coderaiser/c8-reproduce
cd c8-reproduce
npm install
npm run coverage

What is the bug?

The bug is different coverage information for the same file content.

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior?

Would be great if coverage information was the same for the similar type of content.

What do you see instead?

I see that coverage is missing information about code running code parts when Loaders are used to transform the source.

Additional information

Happy Holidays 🎄! And thank you for the hard work you are doing, node.js is the greatest platform 🎉 !

Reacted by John Hoffer, Jake Bailey and Alexey Kryazhev

Activity

  1. aduh95 commented on Jan 3, 2022

    @aduh95
    aduh95
    on Jan 3, 2022
    Contributor
    More actions

    @nodejs/loaders

    Reacted by John Hoffer
  2. aduh95
    added
    coverageIssues and PRs related to Node.js code coverage support.Issues and PRs related to Node.js code coverage support.
    loadersIssues and PRs related to ES module loaders.Issues and PRs related to ES module loaders.
    on Jan 3, 2022
  3. simlu commented on Dec 21, 2023

    @simlu
    simlu
    on Dec 21, 2023
    More actions

    Maintainer of test library here. Also running into this when hot-reloading for individual tests.

    Would be great to get this looked at!

  4. GeoffreyBooth commented on Dec 21, 2023

    @GeoffreyBooth
    GeoffreyBooth
    on Dec 21, 2023
    Member
    More actions

    Would be great to get this looked at!

    Pull requests are welcome!

  5. simlu commented on Dec 21, 2023

    @simlu
    simlu
    on Dec 21, 2023
    More actions

    Would be great to get this looked at!

    Pull requests are welcome!

    I would love to! But while I can reproduce the issue, I have not the faintest idea where the problem really is. It seems to be something pretty low level if I read these tickets correctly

  6. github-actions commented on Jun 25, 2026

    @github-actions
    github-actionsBot
    on Jun 25, 2026 – with GitHub Actions
    Contributor
    More actions

    This issue has been marked as stale due to 210 days of inactivity.
    It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.

  7. github-actions
    added
    staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.
    on Jun 25, 2026
  8. github-actions commented on Jul 26, 2026

    @github-actions
    github-actionsBot
    on Jul 26, 2026 – with GitHub Actions
    Contributor
    More actions

    This issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 120 days).
    If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.

  9. github-actions
    closed this as not plannedon Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    coverageIssues and PRs related to Node.js code coverage support.Issues and PRs related to Node.js code coverage support.loadersIssues and PRs related to ES module loaders.Issues and PRs related to ES module loaders.staleIssues and PRs marked stale due to inactivity and scheduled for automatic closure.Issues and PRs marked stale due to inactivity and scheduled for automatic closure.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.