Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/rules/prefer-called-with.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

## Rule Details

This rule aims to enforce the use of `toBeCalledWith()` or `toHaveBeenCalledWith()` over `toBeCalled()` or `toHaveBeenCalled()`.
This rule aims to enforce the use of `toBeCalledWith()` or `toHaveBeenCalledWith()` over `toBeCalled()` or `toHaveBeenCalled()`, and `toHaveBeenCalledExactlyOnceWith()` over `toHaveBeenCalledOnce()`.

Examples of **incorrect** code for this rule:

Expand All @@ -20,6 +20,7 @@ test('foo', () => {
mock('foo')
expect(mock).toBeCalled()
expect(mock).toHaveBeenCalled()
expect(mock).toHaveBeenCalledOnce()
})
```

Expand All @@ -31,5 +32,6 @@ test('foo', () => {
mock('foo')
expect(mock).toBeCalledWith('foo')
expect(mock).toHaveBeenCalledWith('foo')
expect(mock).toHaveBeenCalledExactlyOnceWith('foo')
})
```
39 changes: 25 additions & 14 deletions src/rules/prefer-called-with.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import { createEslintRule, getAccessorValue } from '../utils'
import {
createEslintRule,
getAccessorValue,
replaceAccessorFixer,
} from '../utils'
import { parseVitestFnCall } from '../utils/parse-vitest-fn-call'

const RULE_NAME = 'prefer-called-with'
type MESSAGE_IDS = 'preferCalledWith'
type Options = []

const PREFERRED_MATCHERS = {
toBeCalled: 'toBeCalledWith',
toHaveBeenCalled: 'toHaveBeenCalledWith',
toHaveBeenCalledOnce: 'toHaveBeenCalledExactlyOnceWith',
} as const

export default createEslintRule<Options, MESSAGE_IDS>({
name: RULE_NAME,
meta: {
Expand All @@ -14,7 +24,7 @@ export default createEslintRule<Options, MESSAGE_IDS>({
recommended: false,
},
messages: {
preferCalledWith: 'Prefer {{ matcherName }}With(/* expected args */)',
preferCalledWith: 'Prefer {{ matcherName }}(/* expected args */)',
},
type: 'suggestion',
fixable: 'code',
Expand All @@ -37,18 +47,19 @@ export default createEslintRule<Options, MESSAGE_IDS>({
const { matcher } = vitestFnCall
const matcherName = getAccessorValue(matcher)

if (
['toBeCalled', 'toHaveBeenCalled', 'toHaveBeenCalledOnce'].includes(
matcherName,
)
) {
context.report({
data: { matcherName },
messageId: 'preferCalledWith',
node: matcher,
fix: (fixer) => [fixer.replaceText(matcher, `${matcherName}With`)],
})
}
if (!Object.hasOwn(PREFERRED_MATCHERS, matcherName)) return

const preferredMatcher =
PREFERRED_MATCHERS[matcherName as keyof typeof PREFERRED_MATCHERS]

context.report({
data: { matcherName: preferredMatcher },
messageId: 'preferCalledWith',
node: matcher,
fix: (fixer) => [
replaceAccessorFixer(fixer, matcher, preferredMatcher),
],
})
},
}
},
Expand Down
10 changes: 5 additions & 5 deletions tests/prefer-called-with.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ ruleTester.run(rule.name, rule, {
errors: [
{
messageId: 'preferCalledWith',
data: { matcherName: 'toBeCalled' },
data: { matcherName: 'toBeCalledWith' },
column: 12,
line: 1,
},
Expand All @@ -36,7 +36,7 @@ ruleTester.run(rule.name, rule, {
errors: [
{
messageId: 'preferCalledWith',
data: { matcherName: 'toBeCalled' },
data: { matcherName: 'toBeCalledWith' },
column: 21,
line: 1,
},
Expand All @@ -48,7 +48,7 @@ ruleTester.run(rule.name, rule, {
errors: [
{
messageId: 'preferCalledWith',
data: { matcherName: 'toHaveBeenCalled' },
data: { matcherName: 'toHaveBeenCalledWith' },
column: 12,
line: 1,
},
Expand All @@ -60,13 +60,13 @@ ruleTester.run(rule.name, rule, {
errors: [
{
messageId: 'preferCalledWith',
data: { matcherName: 'toHaveBeenCalledOnce' },
data: { matcherName: 'toHaveBeenCalledExactlyOnceWith' },
column: 40,
line: 1,
},
],
output:
'it("some test", () => {expect(mockApi).toHaveBeenCalledOnceWith();});',
'it("some test", () => {expect(mockApi).toHaveBeenCalledExactlyOnceWith();});',
},
],
})
Loading