oxc-project/oxc · warning
Prefer `toHaveBeenCalledTimes()` over `toHaveLength()` when
Error message
Prefer `toHaveBeenCalledTimes()` over `toHaveLength()` when asserting mock call counts
What it means
Warning from the oxlint `jest/prefer-to-have-been-called-times` rule (source: crates/oxc_linter/src/rules/shared/jest_vitest/prefer_to_have_been_called_times.rs:16). The check fires only when the expect argument is exactly a `...mock.calls` member expression (verified by `is_expect_argument_mock_calls` in the source) and the matcher is `toHaveLength`; it suggests `toHaveBeenCalledTimes()` and registers an automatic fix that rewrites the whole call expression, preserving modifiers like `not`.
Source
Thrown at crates/oxc_linter/src/rules/shared/jest_vitest/prefer_to_have_been_called_times.rs:16
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, Span};
use crate::{
context::LintContext,
fixer::RuleFixer,
utils::{ParsedExpectFnCall, PossibleJestNode, parse_expect_jest_fn_call},
};
use oxc_ast::{
AstKind,
ast::{CallExpression, Expression, MemberExpression},
match_member_expression,
};
fn prefer_to_have_been_called_times_diagnostic(span: Span) -> OxcDiagnostic {
OxcDiagnostic::warn(
"Prefer `toHaveBeenCalledTimes()` over `toHaveLength()` when asserting mock call counts",
)
.with_help(
"Use `toHaveBeenCalledTimes()` to assert the number of times a mock function was called",
)
.with_label(span)
}
pub const DOCUMENTATION: &str = r"### What it does
In order to have a better failure message, [`toHaveBeenCalledTimes` should be used
instead of directly checking the length of `mock.calls`](https://github.com/jest-community/eslint-plugin-jest/blob/v29.5.0/docs/rules/prefer-to-have-been-called-times.md).
### Why is this bad?
This rule triggers a warning if `toHaveLength` is used to assert the number of times a mock is called.
### ExamplesView on GitHub (pinned to e1e7af627c)
Solutions
- Accept the autofix: run `oxlint --fix` (the rule's fixer rewrites `expect(fn.mock.calls).toHaveLength(n)` to `expect(fn).toHaveBeenCalledTimes(n)` including `not` modifiers).
- Or edit manually: move the mock function itself into `expect` and swap the matcher - `expect(fn).toHaveBeenCalledTimes(n)`.
- For zero-call assertions also consider `expect(fn).not.toHaveBeenCalled()`.
- Suppress with `// oxlint-disable-next-line jest/prefer-to-have-been-called-times` when asserting on `.mock.calls` as data is intentional.
Example fix
// before expect(someFunction.mock.calls).toHaveLength(1); // after expect(someFunction).toHaveBeenCalledTimes(1);
Defensive patterns
Strategy: validation
Validate before calling
// rg -n "\.mock\.calls\)\.toHaveLength\(" tests/ -t ts -t js Prevention
- Assert call counts with toHaveBeenCalledTimes in new code
- Run `oxlint --fix` once to convert the whole repo; the rule's fixer preserves not-modifiers
When it happens
Trigger: `expect(fn.mock.calls).toHaveLength(1)`, `expect(fn.mock.calls).toHaveLength(0)`, or `expect(fn.mock.calls).not.toHaveLength(1)`. It does NOT fire for `fn.mock.calls[0][0]` argument assertions - the source requires the final member to be `calls` on a `mock` member.
Common situations: Mock call-count assertions written before authors learned `toHaveBeenCalledTimes`; vitest suites that copied jest patterns; enabling this rule repo-wide and hitting dozens of occurrences in older spec files.
Related errors
- Unexpected alias {name:?}
- Suggest using the built-in equality matchers.
- Suggest using `jest.spyOn()` or `vi.spyOn()`.
- Expect must have a corresponding matcher call.
- Matchers must be called to assert.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/d4f083d14c7dbfe6.
Report an issue: GitHub.