Skip to content

@effect/vitest support compatibliity with oxlint's vitest rules #23567

Description

@destroyer22719

Summary

The vitest/* plugin rules only fire when test functions (it, test, describe, expect, hooks, etc.) are imported from vitest (or aliased sources like vite-plus/test). They do not recognize @effect/vitest as a valid vitest import source, so 28 of the 35 rules I tested silently fail to fire on test files that import from it.

@effect/vitest is the official Effect testing integration: https://effect.website/docs/livesdk/testing/. It re-exports the entire vitest API (export * from "vitest") plus Effect-aware helpers (it.effect, it.live, layer(...), it.layer(...), it.effect.prop, etc.). It is the recommended way to test Effect code with Vitest, per the Effect testing guide.

Environment

  • oxlint: bundled via vite-plus (@oxlint/[email protected], @oxlint/[email protected])
  • Invoked via: vp lint (Vite+ CLI)
  • @effect/vitest: 4.0.0-beta.83
  • vitest: aliased to @voidzero-dev/vite-plus-test@latest via pnpm npm: override (a vitest fork) — same behavior reproduces with stock vitest

Reproduction

Two identical probe files, differing only in the import source:

// probe-effect.test.ts
import { describe, expect, it, test } from "@effect/vitest";

describe("probe", () => {
  test("mixed test and it usage", () => {}); // consistent-test-it should flag
  it("prefer-todo: empty body", () => {}); // prefer-todo + expect-expect should flag
  it("require-test-timeout: no timeout", () => {}); // require-test-timeout should flag
  it("prefer-strict-equal: uses toEqual", () => {
    // prefer-strict-equal should flag
    expect({ a: 1 }).toEqual({ a: 1 });
  });
  it.only("no-focused-tests: focused test", () => {}); // no-focused-tests should flag
  // ... plus cases for prefer-to-be, no-alias-methods, valid-expect, etc.
});
// probe-plain.test.ts  — identical body, different import
import { describe, expect, it, test } from "vitest";
// (same body as above)

Result

$ oxlint probe-effect.test.ts   # imports from @effect/vitest
Found 0 warnings and 0 errors.   # <- no vitest rules fire (only TS rules fire)

$ oxlint probe-plain.test.ts    # imports from vitest
Found 0 warnings and 102 errors. # <- 24 distinct vitest rules fire correctly

Rules affected

I tested 35 vitest rules with trigger cases. 28 silently fail to fire when the import source is @effect/vitest; 7 fire regardless of import source.

Silently broken on @effect/vitest (28)

These rules require resolving the import source to vitest and do not recognize @effect/vitest:

Rule Category
vitest/consistent-test-it style (test/it consistency)
vitest/expect-expect best-practice (test has no assertions)
vitest/max-expects best-practice (too many assertions)
vitest/no-alias-methods style (e.g. toBeCalledtoHaveBeenCalled)
vitest/no-conditional-expect best-practice
vitest/no-disabled-tests best-practice (it.skip)
vitest/no-duplicate-hooks best-practice
vitest/no-focused-tests best-practice (it.only)
vitest/no-hooks style
vitest/no-identical-title best-practice
vitest/prefer-called-once style
vitest/prefer-called-times style
vitest/prefer-called-with style
vitest/prefer-comparison-matcher style
vitest/prefer-expect-assertions best-practice
vitest/prefer-expect-type-of style
vitest/prefer-strict-equal style (toEqualtoStrictEqual)
vitest/prefer-to-be style (toEqualtoBe for primitives)
vitest/prefer-to-be-falsy style
vitest/prefer-to-be-truthy style
vitest/prefer-to-contain style
vitest/prefer-to-have-length style
vitest/prefer-todo style (empty body → it.todo)
vitest/require-awaited-expect-poll best-practice
vitest/require-test-timeout best-practice (missing timeout)
vitest/require-to-throw-message best-practice
vitest/require-top-level-describe style
vitest/valid-expect best-practice (expect(x) without matcher)

Work regardless of import source (7)

These appear to pattern-match on call syntax rather than resolving the import source, so they fire on both:

  • vitest/no-conditional-in-test
  • vitest/no-test-return-statement
  • vitest/prefer-hooks-in-order
  • vitest/prefer-mock-promise-shorthand
  • vitest/prefer-mock-return-shorthand
  • vitest/prefer-spy-on
  • vitest/require-mock-type-parameters

Suggested fix

Treat @effect/vitest as a recognized vitest import source. Two possible approaches:

  1. Hardcode @effect/vitest alongside vitest in the vitest plugin's import-source recognizer (smallest change).
  2. Make it configurable — add an option like vitestImportSources: ["vitest", "@effect/vitest", ...] to the plugin config so projects can register additional re-exporting packages (more flexible; also covers vite-plus/test, private wrappers, etc.).

Option 2 would also resolve the related false-positive on vitest/no-importing-vitest-globals (which flags @effect/vitest imports as "global vitest functions" because it doesn't recognize the package as a valid vitest source). That rule currently has to be disabled in Effect projects, which then loses its protection on plain-vitest files in the same repo.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Fields

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Effort

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions