{"record":{"id":"d4f083d14c7dbfe6","repo":"oxc-project/oxc","slug":"prefer-tohavebeencalledtimes-over-tohavelengt","errorCode":null,"errorMessage":"Prefer `toHaveBeenCalledTimes()` over `toHaveLength()` when asserting mock call counts","messagePattern":"Prefer `toHaveBeenCalledTimes\\(\\)` over `toHaveLength\\(\\)` when asserting mock call counts","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/shared/jest_vitest/prefer_to_have_been_called_times.rs","lineNumber":16,"sourceCode":"use oxc_diagnostics::OxcDiagnostic;\nuse oxc_span::{GetSpan, Span};\n\nuse crate::{\n    context::LintContext,\n    fixer::RuleFixer,\n    utils::{ParsedExpectFnCall, PossibleJestNode, parse_expect_jest_fn_call},\n};\nuse oxc_ast::{\n    AstKind,\n    ast::{CallExpression, Expression, MemberExpression},\n    match_member_expression,\n};\n\nfn prefer_to_have_been_called_times_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\n        \"Prefer `toHaveBeenCalledTimes()` over `toHaveLength()` when asserting mock call counts\",\n    )\n    .with_help(\n        \"Use `toHaveBeenCalledTimes()` to assert the number of times a mock function was called\",\n    )\n    .with_label(span)\n}\n\npub const DOCUMENTATION: &str = r\"### What it does\n\nIn order to have a better failure message, [`toHaveBeenCalledTimes` should be used\ninstead 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).\n\n### Why is this bad?\n\nThis rule triggers a warning if `toHaveLength` is used to assert the number of times a mock is called.\n\n### Examples","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/shared/jest_vitest/prefer_to_have_been_called_times.rs#L1-L34","documentation":"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`.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before\nexpect(someFunction.mock.calls).toHaveLength(1);\n\n// after\nexpect(someFunction).toHaveBeenCalledTimes(1);","handlingStrategy":"validation","validationCode":"// rg -n \"\\.mock\\.calls\\)\\.toHaveLength\\(\" tests/ -t ts -t js","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assert call counts with toHaveBeenCalledTimes in new code","Run `oxlint --fix` once to convert the whole repo; the rule's fixer preserves not-modifiers"],"tags":["jest","vitest","oxlint","mock","autofix"],"backgroundTag":"jest-mock-call-count-assertion","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}