bcoe / bcoe/c8

Incorrect branch coverage when loaders used

Open
#325 20 comments 2 reactions 0 assignees View on GitHub
bug help wanted
Dominant language
JavaScript
Stars
2.1k
Forks
99
PR merge metrics
No merged PRs in 30d

Description

`c8` shows uncovered lines, but the whole file is covered.

![image](https://user-images.githubusercontent.com/1573141/132669108-53525a81-6bb5-4a72-aa07-81360ce1b5c5.png)

Version: output of `node -v` 16.9.0
Platform: output of `uname -a` Darwin

* **Version**: latest
* **Platform**: mac os

Repository https://github.com/coderaiser/c8-reproduce

When I'm using [loaders](https://nodejs.org/api/esm.html#esm_transformsource_source_context_defaulttransformsource) to mock `imports` the coverage I see is broken.

Code:

```js
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';
};
```

Tests:

```js
import {createMockImport} from 'mock-import';
import {
test,
stub,
} from 'supertape';

const {mockImport, reImport, stopAll} = createMockImport(import.meta.url);

test('changelog: a', async (t) => {
mockImport('fs/promises', {
readFile: stub().returns('a'),
});
const fn = await reImport('./changelog.js');
stopAll();

t.equal(fn.default(1), 'a');
});

test('changelog: c', async (t) => {
mockImport('child_process', {
execSync: stub().returns('c'),
});

const fn = await reImport('./changelog.js');
stopAll();

t.equal(fn.default(0, 0, 1), 'c');
});

test('changelog: d', async (t) => {
const fn = await import('./changelog.js?count=4');

t.equal(fn.default(0, 0, 0, 1), 'd');
});
```

What [mock-import](https://github.com/coderaiser/mock-import) does is converts source to:

```js
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 `imports` it as `./changelog.js?count=1` on first test, then on second test:

```js
import {
readFile
} from 'fs/promises'

const {
execSync,
} = global.__mockImportCache.get('fs/promises');

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

if (c)
return execSync();

return 'd';
};
```

File `imported` as `./changelog.js?count=2`, and then on third assertion code isn't changed.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.