vitest-dev / vitest

Next generation testing framework powered by Vite.
https://vitest.dev
MIT License
12.3k stars 1.09k forks source link

Use `useDefineForClassFields` with `coverage-v8` and vitest workspace cause error #5329

Open colinaaa opened 4 months ago

colinaaa commented 4 months ago

Describe the bug

I'm using vitest and a coverage error showed up after I added a static class field:

TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
 ❯ RangeTree.fromSortedRanges node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/range-tree.js:27:39
 ❯ normalizeFunctionCov node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/normalize.js:74:41
 ❯ Object.deepNormalizeScriptCov node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/normalize.js:59:9
 ❯ mergeScriptCovs node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/merge.js:59:21
 ❯ mergeProcessCovs node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/merge.js:34:21
 ❯ node_modules/.pnpm/@vitest+coverage-v8@1.3.1_vitest@1.3.1/node_modules/@vitest/coverage-v8/dist/provider.js:265:22
 ❯ V8CoverageProvider.reportCoverage node_modules/.pnpm/@vitest+coverage-v8@1.3.1_vitest@1.3.1/node_modules/@vitest/coverage-v8/dist/provider.js:262:11
 ❯ Vitest.reportCoverage node_modules/.pnpm/vitest@1.3.1_@types+node@20.11.24/node_modules/vitest/dist/vendor/cac.wWT9ELdg.js:11918:7
 ❯ async node_modules/.pnpm/vitest@1.3.1_@types+node@20.11.24/node_modules/vitest/dist/vendor/cac.wWT9ELdg.js:11709:7

I tried to minimize the reproduction demo and it seems like it is related to useDefineForClassFields. See the Reproduction section for details.

Reproduction

A minimal reproduction repo is created at: https://github.com/colinaaa/vitest-v8-repro

Just run

to reproduce the issue.

Note that any of these will eliminate the error:

System Info

System:
    OS: macOS 14.0
    CPU: (12) arm64 Apple M2 Max
    Memory: 14.89 GB / 96.00 GB
    Shell: 3.7.0 - /opt/homebrew/bin/fish
  Binaries:
    Node: 20.11.1 - ~/Library/Caches/fnm_multishells/77527_1709530742451/bin/node
    Yarn: 1.22.19 - ~/Library/Caches/fnm_multishells/77527_1709530742451/bin/yarn
    npm: 10.2.4 - ~/Library/Caches/fnm_multishells/77527_1709530742451/bin/npm
    pnpm: 7.33.6 - ~/Library/Caches/fnm_multishells/77527_1709530742451/bin/pnpm
  Browsers:
    Chrome: 122.0.6261.94
    Firefox Nightly: 115.0
    Safari: 17.0
  npmPackages:
    @vitest/coverage-v8: ^1.3.1 => 1.3.1 
    vitest: ^1.3.1 => 1.3.1 

Used Package Manager

pnpm

Validations

AriPerkkio commented 4 months ago

This looks like a bug in @bcoe/v8-coverage (👋 @bcoe). Here's minimal reproduction without Vitest in pure Javascript https://github.com/AriPerkkio/reproductions/tree/v8-merge.

import { mergeProcessCovs } from "@bcoe/v8-coverage";
import { writeFileSync } from "node:fs";
import inspector from "node:inspector";

writeFileSync(
  "./source-file.js",
  `
export class Foo {
  static Baz = process.env["NODE_ENV"] === "test" ? "some" : "thing";

  // Remove this will not cause error
  static Bar = {};
}
`.trim(),
  "utf8"
);

const session = new inspector.Session();
session.connect();
session.post("Profiler.enable");
session.post("Profiler.startPreciseCoverage", {
  callCount: true,
  detailed: true,
});

await import("./source-file.js");

const coverage = await collectCoverage("source-file.js");
console.log(JSON.stringify(coverage, null, 2));

mergeProcessCovs([coverage]);

async function collectCoverage(filename) {
  return new Promise((resolve, reject) => {
    session.post("Profiler.takePreciseCoverage", async (error, coverage) => {
      if (error) return reject(error);

      const result = coverage.result.filter((entry) =>
        entry.url.includes(filename)
      );

      resolve({ result });
    });
  });
}
$ node index.mjs 
{
  "result": [
    {
      "scriptId": "499",
      "url": "file:///<root>/reproductions/source-file.js",
      "functions": [
        {
          "functionName": "",
          "ranges": [
            {
              "startOffset": 0,
              "endOffset": 148,
              "count": 1
            }
          ],
          "isBlockCoverage": true
        },
        {
          "functionName": "<static_initializer>",
          "ranges": [
            {
              "startOffset": 130,
              "endOffset": 145,
              "count": 1
            },
            {
              "startOffset": 69,
              "endOffset": 77,
              "count": 0
            }
          ],
          "isBlockCoverage": true
        }
      ]
    }
  ]
}
/<root>/reproductions/node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/range-tree.js:27
                [parent, parentCount] = stack[stack.length - 1];
                                      ^

TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
    at RangeTree.fromSortedRanges (/<root>/reproductions/node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/range-tree.js:27:39)
    at normalizeFunctionCov (/<root>/reproductions/node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/normalize.js:74:41)
    at Object.deepNormalizeScriptCov (/<root>/reproductions/node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/normalize.js:59:9)
    at mergeScriptCovs (/<root>/reproductions/node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/merge.js:59:21)
    at mergeProcessCovs (/<root>/reproductions/node_modules/.pnpm/@bcoe+v8-coverage@0.2.3/node_modules/@bcoe/v8-coverage/dist/lib/merge.js:34:21)
    at file:///<root>/reproductions/index.mjs:32:1

Node.js v18.17.1