diff --git a/packages/vitest/src/runtime/moduleRunner/moduleEvaluator.ts b/packages/vitest/src/runtime/moduleRunner/moduleEvaluator.ts index f5caccd70..c70319a40 100644 --- a/packages/vitest/src/runtime/moduleRunner/moduleEvaluator.ts +++ b/packages/vitest/src/runtime/moduleRunner/moduleEvaluator.ts @@ -330,6 +330,15 @@ export class VitestModuleEvaluator implements ModuleEvaluator { // this will always be 1 element because it's cached after load const importer = module.importers.values().next().value + + // Initialize execution info in case worker exited before module evaluation finished + this.options.moduleExecutionInfo?.set(options.filename, { + duration: 0, + selfTime: 0, + startOffset: codeDefinition.length, + importer, + }) + const finishModuleExecutionInfo = this.debug.startCalculateModuleExecutionInfo(options.filename, { startOffset: codeDefinition.length, importer, diff --git a/test/coverage-test/fixtures/src/slow-module-imported.ts b/test/coverage-test/fixtures/src/slow-module-imported.ts new file mode 100644 index 000000000..8c55a27b0 --- /dev/null +++ b/test/coverage-test/fixtures/src/slow-module-imported.ts @@ -0,0 +1,17 @@ +import { response } from "./slow-module"; + +export function uncovered() { + throw new Error("uncovered"); +} + +export function uncovered2() { + throw new Error("uncovered"); +} + +export function covered(value: number) { + if(!response.ok) { + throw new Error("response not ok"); + } + + return value + 100; +} diff --git a/test/coverage-test/fixtures/src/slow-module.ts b/test/coverage-test/fixtures/src/slow-module.ts new file mode 100644 index 000000000..f6df5a6aa --- /dev/null +++ b/test/coverage-test/fixtures/src/slow-module.ts @@ -0,0 +1,9 @@ +import { setTimeout } from "node:timers/promises"; + +const delay = parseInt(process.env.DELAY ?? "100", 10); + +if (delay > 0) { + await setTimeout(delay); +} + +export const response = { ok: true }; diff --git a/test/coverage-test/fixtures/test/slow-module-import-awaited.test.ts b/test/coverage-test/fixtures/test/slow-module-import-awaited.test.ts new file mode 100644 index 000000000..12c937524 --- /dev/null +++ b/test/coverage-test/fixtures/test/slow-module-import-awaited.test.ts @@ -0,0 +1,6 @@ +import { expect, test } from "vitest"; +import { covered } from "../src/slow-module-imported"; + +test("covers covered()", () => { + expect(covered(2)).toBe(102); +}); diff --git a/test/coverage-test/fixtures/test/slow-module-import-pending.test.ts b/test/coverage-test/fixtures/test/slow-module-import-pending.test.ts new file mode 100644 index 000000000..5f1875a74 --- /dev/null +++ b/test/coverage-test/fixtures/test/slow-module-import-pending.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from "vitest"; + +process.env.DELAY = "10000"; + +test("module import pending", async () => { + const promise = import("../src/slow-module-imported"); + + await new Promise((resolve) => setTimeout(resolve, 10)); + + expect(promise).toBeTruthy(); +}); diff --git a/test/coverage-test/test/module-import-pending.v8.test.ts b/test/coverage-test/test/module-import-pending.v8.test.ts new file mode 100644 index 000000000..54af6e05f --- /dev/null +++ b/test/coverage-test/test/module-import-pending.v8.test.ts @@ -0,0 +1,35 @@ +import { expect } from 'vitest' +import { StableTestFileOrderSorter } from '../../test-utils' +import { readCoverageMap, runVitest, test } from '../utils' + +test('module offset is set correctly when module import is pending (#10581)', async () => { + await runVitest({ + include: [ + 'fixtures/test/slow-module-import-awaited.test.ts', + 'fixtures/test/slow-module-import-pending.test.ts', + ], + fileParallelism: false, + sequence: { sequencer: StableTestFileOrderSorter }, + coverage: { reporter: 'json' }, + }) + + const coverageMap = await readCoverageMap() + expect(coverageMap.files()).toMatchInlineSnapshot(` + [ + "/fixtures/src/slow-module-imported.ts", + "/fixtures/src/slow-module.ts", + ] + `) + + const fileCoverage = coverageMap.fileCoverageFor('/fixtures/src/slow-module-imported.ts') + + /** {@link file://./../fixtures/src/slow-module-imported.ts} */ + const lineCoverage = fileCoverage.getLineCoverage() + + expect.soft(lineCoverage['4']).toBe(0) + expect.soft(lineCoverage['8']).toBe(0) + + expect.soft(lineCoverage['12']).toBe(1) + expect.soft(lineCoverage['13']).toBe(0) + expect.soft(lineCoverage['16']).toBe(1) +})