Skip to content

Commit 5d1b7a7

Browse files
authored
fix(prefer-spy-on): improve autofix (#1308)
1 parent f33b19e commit 5d1b7a7

File tree

2 files changed

+62
-7
lines changed

2 files changed

+62
-7
lines changed

src/rules/__tests__/prefer-spy-on.test.ts

+33
Original file line numberDiff line numberDiff line change
@@ -106,5 +106,38 @@ ruleTester.run('prefer-spy-on', rule, {
106106
},
107107
],
108108
},
109+
{
110+
// https://github.com/jest-community/eslint-plugin-jest/issues/1304
111+
code: 'foo[bar] = jest.fn().mockReturnValue(undefined)',
112+
output:
113+
'jest.spyOn(foo, bar).mockImplementation().mockReturnValue(undefined)',
114+
errors: [
115+
{
116+
messageId: 'useJestSpyOn',
117+
type: AST_NODE_TYPES.AssignmentExpression,
118+
},
119+
],
120+
},
121+
{
122+
// https://github.com/jest-community/eslint-plugin-jest/issues/1307
123+
code: `
124+
foo.bar = jest.fn().mockImplementation(baz => baz)
125+
foo.bar = jest.fn(a => b).mockImplementation(baz => baz)
126+
`,
127+
output: `
128+
jest.spyOn(foo, 'bar').mockImplementation(baz => baz)
129+
jest.spyOn(foo, 'bar').mockImplementation(baz => baz)
130+
`,
131+
errors: [
132+
{
133+
messageId: 'useJestSpyOn',
134+
type: AST_NODE_TYPES.AssignmentExpression,
135+
},
136+
{
137+
messageId: 'useJestSpyOn',
138+
type: AST_NODE_TYPES.AssignmentExpression,
139+
},
140+
],
141+
},
109142
],
110143
});

src/rules/prefer-spy-on.ts

+29-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
1+
import { AST_NODE_TYPES, TSESLint, TSESTree } from '@typescript-eslint/utils';
22
import { createRule, getNodeName } from './utils';
33

44
const findNodeObject = (
@@ -39,6 +39,27 @@ const getJestFnCall = (node: TSESTree.Node): TSESTree.CallExpression | null => {
3939
return getJestFnCall(obj);
4040
};
4141

42+
const getAutoFixMockImplementation = (
43+
jestFnCall: TSESTree.CallExpression,
44+
context: TSESLint.RuleContext<'useJestSpyOn', unknown[]>,
45+
): string => {
46+
const hasMockImplementationAlready =
47+
jestFnCall.parent?.type === AST_NODE_TYPES.MemberExpression &&
48+
jestFnCall.parent.property.type === AST_NODE_TYPES.Identifier &&
49+
jestFnCall.parent.property.name === 'mockImplementation';
50+
51+
if (hasMockImplementationAlready) {
52+
return '';
53+
}
54+
55+
const [arg] = jestFnCall.arguments;
56+
const argSource = arg && context.getSourceCode().getText(arg);
57+
58+
return argSource
59+
? `.mockImplementation(${argSource})`
60+
: '.mockImplementation()';
61+
};
62+
4263
export default createRule({
4364
name: __filename,
4465
meta: {
@@ -71,12 +92,13 @@ export default createRule({
7192
messageId: 'useJestSpyOn',
7293
fix(fixer) {
7394
const leftPropQuote =
74-
left.property.type === AST_NODE_TYPES.Identifier ? "'" : '';
75-
const [arg] = jestFnCall.arguments;
76-
const argSource = arg && context.getSourceCode().getText(arg);
77-
const mockImplementation = argSource
78-
? `.mockImplementation(${argSource})`
79-
: '.mockImplementation()';
95+
left.property.type === AST_NODE_TYPES.Identifier && !left.computed
96+
? "'"
97+
: '';
98+
const mockImplementation = getAutoFixMockImplementation(
99+
jestFnCall,
100+
context,
101+
);
80102

81103
return [
82104
fixer.insertTextBefore(left, `jest.spyOn(`),

0 commit comments

Comments
 (0)