Skip to content

Commit c397bd1

Browse files
authored
fix(rules): fixed bugs in prefer-to-have-style & prefer-in-document (#115)
* fix(prefer-in-document): more fixes to prefer-in-document * handle typescript parsing * fixes issues in to-have-style * covg * handle allBy * add DTL to repos * fix for template literals in style checks * covg * another case * covg
1 parent a030ec5 commit c397bd1

File tree

5 files changed

+497
-263
lines changed

5 files changed

+497
-263
lines changed

smoke-test/repositories.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@
248248
"Twistbioscience/DesignerComponents",
249249
"bopen/react-jsonschema-form-field-geolocation",
250250
"chuntley/dom-testing-extended",
251+
"testing-library/dom-testing-library",
251252
"frankieyan/custom-meta-input",
252253
"villeheikkila/fullstackopen",
253254
"kentcdodds/learn-react",

src/__tests__/lib/rules/prefer-in-document.js

Lines changed: 180 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -46,51 +46,158 @@ const valid = [
4646
expect(foo).toHaveLength(1);`,
4747
`expect(screen.notAQuery('foo-bar')).toHaveLength(1)`,
4848
`expect(screen.getAllByText('foo-bar')).toHaveLength(2)`,
49+
`import foo from "./foo";
50+
it('should be defined', () => {
51+
expect(useBoolean).toBeDefined();
52+
})`,
53+
`const span = foo('foo') as HTMLSpanElement`,
54+
`const rtl = render()
55+
const stars = rtl.container.querySelector('div').children
56+
57+
expect(rtl.container.children).toHaveLength(1)
58+
expect(stars).toHaveLength(5)`,
59+
` let content = container.querySelector('p')
60+
61+
expect(content).not.toBeNull()
62+
63+
fireEvent.click(closeButton)
64+
65+
await waitExpect(
66+
() => {
67+
content = container.querySelector('p')
68+
expect(content).toBeNull()
69+
}
70+
)`,
4971
];
5072
const invalid = [
5173
// Invalid cases that applies to all variants
52-
...["getByText", "getAllByRole"].map((q) => [
53-
invalidCase(
54-
`expect(screen.${q}('foo')).toHaveLength(1)`,
55-
`expect(screen.${q}('foo')).toBeInTheDocument()`
56-
),
57-
invalidCase(
58-
`expect(${q}('foo')).toHaveLength(1)`,
59-
`expect(${q}('foo')).toBeInTheDocument()`
60-
),
61-
invalidCase(
62-
`expect(wrapper.${q}('foo')).toHaveLength(1)`,
63-
`expect(wrapper.${q}('foo')).toBeInTheDocument()`
64-
),
65-
invalidCase(
66-
`const foo = screen.${q}('foo');
67-
expect(foo).toHaveLength(1);`,
68-
`const foo = screen.${q}('foo');
69-
expect(foo).toBeInTheDocument();`
70-
),
71-
invalidCase(
72-
`const foo = ${q}('foo');
73-
expect(foo).toHaveLength(1);`,
74-
`const foo = ${q}('foo');
75-
expect(foo).toBeInTheDocument();`
76-
),
77-
invalidCase(
78-
`let foo;
79-
foo = ${q}('foo');
80-
expect(foo).toHaveLength(1);`,
81-
`let foo;
82-
foo = ${q}('foo');
83-
expect(foo).toBeInTheDocument();`
84-
),
85-
invalidCase(
86-
`let foo;
87-
foo = screen.${q}('foo');
88-
expect(foo).toHaveLength(1);`,
89-
`let foo;
90-
foo = screen.${q}('foo');
91-
expect(foo).toBeInTheDocument();`
92-
),
93-
]),
74+
75+
invalidCase(
76+
`expect(screen.getByText('foo')).toHaveLength(1)`,
77+
`expect(screen.getByText('foo')).toBeInTheDocument()`
78+
),
79+
invalidCase(
80+
`expect(getByText('foo')).toHaveLength(1)`,
81+
`expect(getByText('foo')).toBeInTheDocument()`
82+
),
83+
invalidCase(
84+
`expect(wrapper.getByText('foo')).toHaveLength(1)`,
85+
`expect(wrapper.getByText('foo')).toBeInTheDocument()`
86+
),
87+
invalidCase(
88+
`const foo = screen.getByText('foo');
89+
expect(foo).toHaveLength(1);`,
90+
`const foo = screen.getByText('foo');
91+
expect(foo).toBeInTheDocument();`
92+
),
93+
invalidCase(
94+
`const foo = getByText('foo');
95+
expect(foo).toHaveLength(1);`,
96+
`const foo = getByText('foo');
97+
expect(foo).toBeInTheDocument();`
98+
),
99+
invalidCase(
100+
`let foo;
101+
foo = getByText('foo');
102+
expect(foo).toHaveLength(1);`,
103+
`let foo;
104+
foo = getByText('foo');
105+
expect(foo).toBeInTheDocument();`
106+
),
107+
invalidCase(
108+
`let foo;
109+
foo = screen.getByText('foo');
110+
expect(foo).toHaveLength(1);`,
111+
`let foo;
112+
foo = screen.getByText('foo');
113+
expect(foo).toBeInTheDocument();`
114+
),
115+
invalidCase(
116+
`expect(screen.getAllByRole('foo')).toHaveLength(1)`,
117+
`expect(screen.getByRole('foo')).toBeInTheDocument()`
118+
),
119+
invalidCase(
120+
`expect(await screen.findAllByRole('foo')).toHaveLength(1)`,
121+
`expect(await screen.findByRole('foo')).toBeInTheDocument()`
122+
),
123+
invalidCase(
124+
`expect(getAllByRole('foo')).toHaveLength(1)`,
125+
`expect(getByRole('foo')).toBeInTheDocument()`
126+
),
127+
invalidCase(
128+
`expect(wrapper.getAllByRole('foo')).toHaveLength(1)`,
129+
`expect(wrapper.getByRole('foo')).toBeInTheDocument()`
130+
),
131+
invalidCase(
132+
`const foo = screen.getAllByRole('foo');
133+
expect(foo).toHaveLength(1);`,
134+
`const foo = screen.getByRole('foo');
135+
expect(foo).toBeInTheDocument();`
136+
),
137+
invalidCase(
138+
`const foo = getAllByRole('foo');
139+
expect(foo).toHaveLength(1);`,
140+
`const foo = getByRole('foo');
141+
expect(foo).toBeInTheDocument();`
142+
),
143+
invalidCase(
144+
`let foo;
145+
foo = getAllByRole('foo');
146+
expect(foo).toHaveLength(1);`,
147+
`let foo;
148+
foo = getByRole('foo');
149+
expect(foo).toBeInTheDocument();`
150+
),
151+
invalidCase(
152+
`let foo;
153+
foo = screen.getAllByRole('foo');
154+
expect(foo).toHaveLength(1);`,
155+
`let foo;
156+
foo = screen.getByRole('foo');
157+
expect(foo).toBeInTheDocument();`
158+
),
159+
160+
invalidCase(
161+
`expect(screen.getByText('foo')).toHaveLength(1)`,
162+
`expect(screen.getByText('foo')).toBeInTheDocument()`
163+
),
164+
invalidCase(
165+
`expect(getByText('foo')).toHaveLength(1)`,
166+
`expect(getByText('foo')).toBeInTheDocument()`
167+
),
168+
invalidCase(
169+
`expect(wrapper.getByText('foo')).toHaveLength(1)`,
170+
`expect(wrapper.getByText('foo')).toBeInTheDocument()`
171+
),
172+
invalidCase(
173+
`const foo = screen.getByText('foo');
174+
expect(foo).toHaveLength(1);`,
175+
`const foo = screen.getByText('foo');
176+
expect(foo).toBeInTheDocument();`
177+
),
178+
invalidCase(
179+
`const foo = getByText('foo');
180+
expect(foo).toHaveLength(1);`,
181+
`const foo = getByText('foo');
182+
expect(foo).toBeInTheDocument();`
183+
),
184+
invalidCase(
185+
`let foo;
186+
foo = getByText('foo');
187+
expect(foo).toHaveLength(1);`,
188+
`let foo;
189+
foo = getByText('foo');
190+
expect(foo).toBeInTheDocument();`
191+
),
192+
invalidCase(
193+
`let foo;
194+
foo = screen.getByText('foo');
195+
expect(foo).toHaveLength(1);`,
196+
`let foo;
197+
foo = screen.getByText('foo');
198+
expect(foo).toBeInTheDocument();`
199+
),
200+
94201
// Invalid cases that applies to queryBy* and queryAllBy*
95202
...["queryByText", "queryAllByText"].map((q) => [
96203
invalidCase(
@@ -172,6 +279,7 @@ const invalid = [
172279
expect(await screen.findByText(/Compressing video/)).not.toBeInTheDocument();
173280
})`
174281
),
282+
175283
invalidCase(
176284
`it("foo", async () => {
177285
const compressingFeedback = await screen.findByText(/Compressing video/);
@@ -216,9 +324,38 @@ const invalid = [
216324
expect(compressingFeedback).not.toBeInTheDocument();
217325
});`
218326
),
327+
invalidCase(
328+
`const span = getByText('foo') as HTMLSpanElement
329+
expect(span).not.toBeNull()`,
330+
`const span = getByText('foo') as HTMLSpanElement
331+
expect(span).toBeInTheDocument()`
332+
),
333+
invalidCase(
334+
`const span = await findByText('foo') as HTMLSpanElement
335+
expect(span).not.toBeNull()`,
336+
`const span = await findByText('foo') as HTMLSpanElement
337+
expect(span).toBeInTheDocument()`
338+
),
339+
invalidCase(
340+
`let span;
341+
span = getByText('foo') as HTMLSpanElement
342+
expect(span).not.toBeNull()`,
343+
`let span;
344+
span = getByText('foo') as HTMLSpanElement
345+
expect(span).toBeInTheDocument()`
346+
),
347+
invalidCase(
348+
`const things = screen.getAllByText("foo");
349+
expect(things).toHaveLength(1);`,
350+
`const things = screen.getByText("foo");
351+
expect(things).toBeInTheDocument();`
352+
),
219353
];
220354

221-
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2017 } });
355+
const ruleTester = new RuleTester({
356+
parser: require.resolve("@typescript-eslint/parser"),
357+
parserOptions: { ecmaVersion: 2020, sourceType: "module" },
358+
});
222359
ruleTester.run("prefer-in-document", rule, {
223360
valid: [].concat(...valid),
224361
invalid: [].concat(...invalid),

src/__tests__/lib/rules/prefer-to-have-style.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,26 @@ ruleTester.run("prefer-to-have-style", rule, {
1616
document.body.setAttribute("style", "foo");
1717
}
1818
}, [foo]);`,
19+
`expect(collapse.style).not.toContain(
20+
expect.objectContaining({
21+
display: 'none',
22+
height: '0px',
23+
})
24+
)`,
1925
],
2026
invalid: [
2127
{
2228
code: `expect(a.style).toHaveProperty('transform')`,
2329
errors,
2430
},
31+
{
32+
code: `expect(a.style).not.toHaveProperty('transform')`,
33+
errors,
34+
},
35+
{
36+
code: `expect(a.style).not.toHaveProperty(\`\${foo}\`)`,
37+
errors,
38+
},
2539
{
2640
code: `expect(el.style.foo).toBe("bar")`,
2741
errors,
@@ -72,6 +86,16 @@ ruleTester.run("prefer-to-have-style", rule, {
7286
errors,
7387
output: `expect(el).toHaveStyle({backgroundColor: expect.anything()})`,
7488
},
89+
{
90+
code: `expect(el.style).toContain(\`background-color\`)`,
91+
errors,
92+
output: `expect(el).toHaveStyle(\`background-color\`)`,
93+
},
94+
{
95+
code: `expect(el.style).not.toContain(\`background-color\`)`,
96+
errors,
97+
output: `expect(el).not.toHaveStyle(\`background-color\`)`,
98+
},
7599
{
76100
code: `expect(el.style).not.toContain("background-color")`,
77101
errors,
@@ -82,5 +106,30 @@ ruleTester.run("prefer-to-have-style", rule, {
82106
errors,
83107
output: `expect(el).toHaveStyle("background-color: green; border-width: 10px; color: blue;")`,
84108
},
109+
{
110+
code: `expect(imageElement.style[\`box-shadow\`]).toBe(\`inset 0px 0px 0px 400px \${c}\`)`,
111+
errors,
112+
output: `expect(imageElement).toHaveStyle(\`box-shadow: inset 0px 0px 0px 400px \${c}\`)`,
113+
},
114+
{
115+
code: `expect(imageElement.style[\`box-shadow\` ]).toBe( \`inset 0px 0px 0px 400px \${c}\`)`,
116+
errors,
117+
output: `expect(imageElement).toHaveStyle( \`box-shadow: inset 0px 0px 0px 400px \${c}\`)`,
118+
},
119+
{
120+
code: `expect(imageElement.style[\`box-\${shadow}\`]).toBe("inset 0px 0px 0px 400px 40px")`,
121+
errors,
122+
output: `expect(imageElement).toHaveStyle(\`box-\${shadow}: inset 0px 0px 0px 400px 40px\`)`,
123+
},
124+
{
125+
code: `expect(imageElement.style[\`box-shadow\`]).not.toBe(\`inset 0px 0px 0px 400px \${c}\`)`,
126+
errors,
127+
output: `expect(imageElement).not.toHaveStyle(\`box-shadow: inset 0px 0px 0px 400px \${c}\`)`,
128+
},
129+
{
130+
code: `expect(imageElement.style[\`box-shadow\`]).not.toBe("inset 0px 0px 0px 400px 40px")`,
131+
errors,
132+
output: `expect(imageElement).not.toHaveStyle(\`box-shadow: inset 0px 0px 0px 400px 40px\`)`,
133+
},
85134
],
86135
});

0 commit comments

Comments
 (0)