@@ -22,6 +22,41 @@ export const meta = {
22
22
} ;
23
23
24
24
export const create = ( context ) => ( {
25
+ //expect(el.classList.contains("foo")).toBe(true)
26
+ [ `CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.callee.object.property.name=classList][callee.object.arguments.0.callee.property.name=contains][callee.property.name=/toBe(Truthy|Falsy)?|to(Strict)?Equal/]` ] (
27
+ node
28
+ ) {
29
+ const classValue = node . callee . object . arguments [ 0 ] . arguments [ 0 ] ;
30
+ const checkedProp = node . callee . object . arguments [ 0 ] . callee . object . object ;
31
+ const matcher = node . callee . property ;
32
+ const [ matcherArg ] = node . arguments ;
33
+ const [ expectArg ] = node . callee . object . arguments ;
34
+ const isTruthy =
35
+ ( matcher . name === "toBe" && matcherArg . value === true ) ||
36
+ matcher . name === "toBeTruthy" ;
37
+
38
+ context . report ( {
39
+ node : matcher ,
40
+ messageId,
41
+ fix ( fixer ) {
42
+ return [
43
+ fixer . removeRange ( [ checkedProp . range [ 1 ] , expectArg . range [ 1 ] ] ) ,
44
+
45
+ fixer . replaceText ( matcher , `${ isTruthy ? "" : "not." } toHaveClass` ) ,
46
+ matcherArg
47
+ ? fixer . replaceText (
48
+ matcherArg ,
49
+ context . getSourceCode ( ) . getText ( classValue )
50
+ )
51
+ : fixer . insertTextBeforeRange (
52
+ [ node . range [ 1 ] - 1 , node . range [ 1 ] - 1 ] ,
53
+ context . getSourceCode ( ) . getText ( classValue )
54
+ ) ,
55
+ ] ;
56
+ } ,
57
+ } ) ;
58
+ } ,
59
+
25
60
//expect(el.classList[0]).toBe("bar")
26
61
[ `CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.object.property.name=classList][callee.property.name=/toBe$|to(Strict)?Equal|toContain/][arguments.0.type=/Literal$/]` ] (
27
62
node
@@ -62,15 +97,23 @@ export const create = (context) => ({
62
97
messageId,
63
98
} ) ;
64
99
} ,
65
- //expect(el.className).toBe("bar") / toStrict?Equal / toContain
66
- [ `CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.property.name=/class(Name|List)/][callee.property.name=/toBe$|to(Strict)?Equal|toContain/][arguments.0.type=/Literal$/] ` ] (
100
+ //expect(el.className | el.classList ).toBe("bar") / toStrict?Equal / toContain
101
+ [ `CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.property.name=/class(Name|List)/][callee.property.name=/toBe$|to(Strict)?Equal|toContain/]` ] (
67
102
node
68
103
) {
69
104
const checkedProp = node . callee . object . arguments [ 0 ] . property ;
70
105
const [ classValue ] = node . arguments ;
71
106
const matcher = node . callee . property ;
72
107
const classNameProp = node . callee . object . arguments [ 0 ] . object ;
73
108
109
+ // don't report here if using `expect.foo()`
110
+
111
+ if (
112
+ classValue . type === "CallExpression" &&
113
+ classValue . callee . type === "MemberExpression" &&
114
+ classValue . callee . object . name === "expect"
115
+ )
116
+ return ;
74
117
context . report ( {
75
118
node : matcher ,
76
119
messageId,
@@ -91,19 +134,21 @@ export const create = (context) => ({
91
134
} ) ;
92
135
} ,
93
136
94
- //expect(el.className).toEqual(expect.stringContaining("foo")) / toStrictEqual
95
- [ `CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.property.name=className ][callee.property.name=/to(Strict)?Equal/][arguments.0.callee.object.name=expect][arguments.0.callee.property.name=stringContaining ]` ] (
137
+ //expect(el.className | el.classList ).toEqual(expect.stringContaining("foo") | objectContaining ) / toStrictEqual
138
+ [ `CallExpression[callee.object.callee.name=expect][callee.object.arguments.0.property.name=/class(Name|List)/ ][callee.property.name=/to(Strict)?Equal/][arguments.0.callee.object.name=expect]` ] (
96
139
node
97
140
) {
98
141
const className = node . callee . object . arguments [ 0 ] . property ;
99
142
const [ classValue ] = node . arguments [ 0 ] . arguments ;
100
143
const matcher = node . callee . property ;
101
144
const classNameProp = node . callee . object . arguments [ 0 ] . object ;
145
+ const matcherArg = node . arguments [ 0 ] . callee . property ;
102
146
103
147
context . report ( {
104
148
node : matcher ,
105
149
messageId,
106
150
fix ( fixer ) {
151
+ if ( matcherArg . name !== "stringContaining" ) return ;
107
152
return [
108
153
fixer . removeRange ( [ classNameProp . range [ 1 ] , className . range [ 1 ] ] ) ,
109
154
fixer . replaceText ( matcher , "toHaveClass" ) ,
@@ -116,11 +161,10 @@ export const create = (context) => ({
116
161
} ) ;
117
162
} ,
118
163
119
- //expect(screen.getByRole("button").className).not.toBe("foo"); / toStrict?Equal / toContain
120
- [ `CallExpression[callee.object.object.callee.name=expect][callee.object.object.arguments.0.property.name=className ][callee.object.property.name=not][callee.property.name=/toBe$|to(Strict)?Equal|toContain/][arguments.0.type=/Literal$ /]` ] (
164
+ //expect(screen.getByRole("button").className | classList ).not.toBe("foo"); / toStrict?Equal / toContain
165
+ [ `CallExpression[callee.object.object.callee.name=expect][callee.object.object.arguments.0.property.name=/class(Name|List)/ ][callee.object.property.name=not][callee.property.name=/toBe$|to(Strict)?Equal|toContain/]` ] (
121
166
node
122
167
) {
123
- //[callee.object.arguments.0.property.name=className][callee.property.name=/toBe$|to(Strict)?Equal|toContain/][arguments.0.type=/Literal$/]
124
168
const className = node . callee . object . object . arguments [ 0 ] . property ;
125
169
const [ classValue ] = node . arguments ;
126
170
const matcher = node . callee . property ;
@@ -130,6 +174,9 @@ export const create = (context) => ({
130
174
node : matcher ,
131
175
messageId,
132
176
fix ( fixer ) {
177
+ if ( className . name === "classList" && matcher . name !== "toContain" )
178
+ return ;
179
+
133
180
return [
134
181
fixer . removeRange ( [ classNameProp . range [ 1 ] , className . range [ 1 ] ] ) ,
135
182
fixer . replaceText ( matcher , "toHaveClass" ) ,
0 commit comments