1 | 'use strict';
|
2 |
|
3 | const { getDocsUrl, getNodeName } = require('./util');
|
4 |
|
5 | const getJestFnCall = node => {
|
6 | if (
|
7 | (node.type !== 'CallExpression' && node.type !== 'MemberExpression') ||
|
8 | (node.callee && node.callee.type !== 'MemberExpression')
|
9 | ) {
|
10 | return null;
|
11 | }
|
12 |
|
13 | const obj = node.callee ? node.callee.object : node.object;
|
14 |
|
15 | if (obj.type === 'Identifier') {
|
16 | return node.type === 'CallExpression' &&
|
17 | getNodeName(node.callee) === 'jest.fn'
|
18 | ? node
|
19 | : null;
|
20 | }
|
21 |
|
22 | return getJestFnCall(obj);
|
23 | };
|
24 |
|
25 | module.exports = {
|
26 | meta: {
|
27 | docs: {
|
28 | url: getDocsUrl(__filename),
|
29 | },
|
30 | fixable: 'code',
|
31 | },
|
32 | create(context) {
|
33 | return {
|
34 | AssignmentExpression(node) {
|
35 | if (node.left.type !== 'MemberExpression') return;
|
36 |
|
37 | const jestFnCall = getJestFnCall(node.right);
|
38 |
|
39 | if (!jestFnCall) return;
|
40 |
|
41 | context.report({
|
42 | node,
|
43 | message: 'Use jest.spyOn() instead.',
|
44 | fix(fixer) {
|
45 | const leftPropQuote =
|
46 | node.left.property.type === 'Identifier' ? "'" : '';
|
47 | const [arg] = jestFnCall.arguments;
|
48 | const argSource = arg && context.getSourceCode().getText(arg);
|
49 | const mockImplementation = argSource
|
50 | ? `.mockImplementation(${argSource})`
|
51 | : '';
|
52 |
|
53 | return [
|
54 | fixer.insertTextBefore(node.left, `jest.spyOn(`),
|
55 | fixer.replaceTextRange(
|
56 | [node.left.object.range[1], node.left.property.range[0]],
|
57 | `, ${leftPropQuote}`
|
58 | ),
|
59 | fixer.replaceTextRange(
|
60 | [node.left.property.range[1], jestFnCall.range[1]],
|
61 | `${leftPropQuote})${mockImplementation}`
|
62 | ),
|
63 | ];
|
64 | },
|
65 | });
|
66 | },
|
67 | };
|
68 | },
|
69 | };
|