Skip to content

health: exclude mocked module edges from static test reachability #2031

Description

@BartWaardenburg

Problem

Static coverage reachability follows an import into a module that Vitest replaces with vi.mock().
The mocked module and its exports are therefore reported as test-covered even though the real module
is never executed by that test.

This also changes coverage-derived health severity when a wrapper test is added, which can make
stable health identities regress unexpectedly.

Minimal reproduction

// src/dependency.ts
export const renderDependency = (): string => "real dependency";

// src/wrapper.ts
import { renderDependency } from "./dependency";

export const renderWrapper = (): string => renderDependency();

// src/wrapper.test.ts
import { describe, expect, it, vi } from "vitest";
import { renderWrapper } from "./wrapper";

vi.mock("./dependency", () => ({
  renderDependency: vi.fn<() => string>(() => "mocked dependency"),
}));

describe("renderWrapper", () => {
  it("uses the mock", () => {
    expect(renderWrapper()).toBe("mocked dependency");
  });
});

With src/entry.ts as the package entry, run:

fallow health --coverage-gaps --format json --quiet --no-cache

Fallow 3.9.1 reports three runtime files, two covered files, and only src/entry.ts as untested.
The two covered files are src/wrapper.ts and src/dependency.ts.

Expected

The static coverage graph should treat the literal target of vi.mock("./dependency") as a mocked
edge for that test root. src/wrapper.ts is test-reachable, but src/dependency.ts is not covered
by this test.

The same likely applies to jest.mock() and vi.doMock() where the target is a static string.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions