-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathprefer-in-document.js
114 lines (99 loc) · 3.07 KB
/
prefer-in-document.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
/**
* @fileoverview prefer toBeInTheDocument over checking getAttribute/hasAttribute
* @author Anton Niklasson
*/
import { queries } from "../queries";
export const meta = {
type: "suggestion",
docs: {
category: "jest-dom",
description:
"Prefer .toBeInTheDocument() in favor of checking the length of the result using .toHaveLength(1)",
url: "prefer-in-document",
recommended: false,
},
fixable: "code",
messages: {
"use-document": `Prefer .toBeInTheDocument() in favor of .toHaveLength(1)`,
},
};
function isAntonymMatcher(matcherNode, matcherArguments) {
return (
matcherNode.name === "toBeNull" ||
(matcherNode.name === "toHaveLength" && matcherArguments[0].value === 0)
);
}
function check(
context,
// eslint-disable-next-line no-unused-vars
{ queryNode, matcherNode, matcherArguments, negatedMatcher }
) {
const query = queryNode.name || queryNode.property.name;
// toHaveLength should only be invalid if the argument is 1
if (matcherNode.name === "toHaveLength" && matcherArguments[0].value > 1) {
return;
}
if (queries.includes(query)) {
context.report({
node: matcherNode,
messageId: "use-document",
loc: matcherNode.loc,
fix(fixer) {
const operations = [];
// Flip the .not if neccessary
if (isAntonymMatcher(matcherNode, matcherArguments)) {
if (negatedMatcher) {
operations.push(
fixer.removeRange([
matcherNode.range[0] - 5,
matcherNode.range[0] - 1,
])
);
} else {
operations.push(fixer.insertTextBefore(matcherNode, "not."));
}
}
// Replace the actual matcher
operations.push(fixer.replaceText(matcherNode, "toBeInTheDocument"));
// Remove any arguments in the matcher
for (const argument of matcherArguments) {
operations.push(fixer.remove(argument));
}
return operations;
},
});
}
}
export const create = (context) => {
const alternativeMatchers = /(toHaveLength|toBeDefined|toBeNull)/;
return {
// Grabbing expect(<query>).not.<matcher>
[`CallExpression[callee.object.object.callee.name='expect'][callee.object.property.name='not'][callee.property.name=${alternativeMatchers}]`](
node
) {
const queryNode = node.callee.object.object.arguments[0].callee;
const matcherNode = node.callee.property;
const matcherArguments = node.arguments;
check(context, {
negatedMatcher: true,
queryNode,
matcherNode,
matcherArguments,
});
},
// Grabbing expect(<query>).<matcher>
[`CallExpression[callee.object.callee.name='expect'][callee.property.name=${alternativeMatchers}]`](
node
) {
const queryNode = node.callee.object.arguments[0].callee;
const matcherNode = node.callee.property;
const matcherArguments = node.arguments;
check(context, {
negatedMatcher: false,
queryNode,
matcherNode,
matcherArguments,
});
},
};
};