Skip to content

Commit 00b65fa

Browse files
feat(rules): added rule for prefer-to-have-class (#118)
* feat(rules): added rule prefer-to-have-class * more tests * fixed typeo * covg * Apply suggestions from code review Co-authored-by: Anton Niklasson <[email protected]> * classList Co-authored-by: Anton Niklasson <[email protected]>
1 parent 043e7bf commit 00b65fa

File tree

5 files changed

+430
-1
lines changed

5 files changed

+430
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ module.exports = {
110110
| [prefer-in-document](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-in-document.md) | 👍 | 🔧 | Prefer .toBeInTheDocument() for asserting the existence of a DOM node |
111111
| [prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | 👍 | 🔧 | prefer toBeRequired over checking properties |
112112
| [prefer-to-have-attribute](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-to-have-attribute.md) | 👍 | 🔧 | prefer toHaveAttribute over checking getAttribute/hasAttribute |
113+
| [prefer-to-have-class](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-to-have-class.md) | 👍 | 🔧 | prefer toHaveClass over checking element className |
113114
| [prefer-to-have-style](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-to-have-style.md) | 👍 | 🔧 | prefer toHaveStyle over checking element style |
114115
| [prefer-to-have-text-content](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-to-have-text-content.md) | 👍 | 🔧 | Prefer toHaveTextContent over checking element.textContent |
115116
| [prefer-to-have-value](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-to-have-value.md) | 👍 | 🔧 | prefer toHaveValue over checking element.value |

docs/rules/prefer-to-have-class.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# prefer toHaveClass over checking element.class (prefer-to-have-class)
2+
3+
This rule is an autofixable rule that reports usages of checking element className or classList in expect statements in preference of using the jest-dom
4+
`toHaveClass` matcher.
5+
6+
## Rule Details
7+
8+
Examples of **incorrect** code for this rule:
9+
10+
```js
11+
expect(el.className).toBe("bar");
12+
expect(el.className).not.toBe("bar");
13+
expect(el.className).toHaveProperty("class", "foo");
14+
expect(screen.getByTestId("foo").className).toBe("foo");
15+
expect(el.className).toContain("bar");
16+
expect(el.className).not.toContain("baz");
17+
expect(el).toHaveAttribute("class", "qux");
18+
19+
expect(el.classList[0]).toBe("foo");
20+
expect(el.classList[0]).toBe("bar");
21+
```
22+
23+
Examples of **correct** code for this rule:
24+
25+
```js
26+
expect(el).toHaveClass("bar");
27+
expect(el).toHaveStyle({ foo: "bar" });
28+
expect(el.class).toMatchSnapshot();
29+
expect(el.class).toEqual(foo);
30+
```
31+
32+
## When Not To Use It
33+
34+
If you don't care about using built in matchers for checking class on dom
35+
elements.
36+
37+
## Further Reading
38+
39+
- [jest-dom toHaveStyle](https://github.com/testing-library/jest-dom#tohaveclass)
40+
- [ElementCSSInlineStyle.class](https://developer.mozilla.org/en-US/docs/Web/API/ElementCSSInlineStyle/class)

docs/rules/prefer-to-have-style.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# prefer toHaveProperty over checking element.style (prefer-to-have-style)
1+
# prefer toHaveStyle over checking element.style (prefer-to-have-style)
22

33
This rule is an autofixable rule that reports usages of checking element.style in expect statements in preference of using the jest-dom
44
`toHaveStyle` matcher.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { RuleTester } from "eslint";
2+
import * as rule from "../../../rules/prefer-to-have-class";
3+
4+
const errors = [{ messageId: "use-to-have-class" }];
5+
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } });
6+
ruleTester.run("prefer-to-have-class", rule, {
7+
valid: [
8+
`expect(el).toHaveClass("bar")`,
9+
`expect(el.class).toEqual(foo)`,
10+
`expect(el).toHaveAttribute("class")`,
11+
`expect(el).toHaveAttribute("className", "bar")`,
12+
`expect(el).toHaveAttribute("clazz", "bar")`,
13+
`expect(el).not.toHaveAttribute("clazz", "bar")`,
14+
`expect(el).not.toHaveAttribute("clazz", expect.stringContaining("bar"))`,
15+
`expect(el).toHaveAttribute("clazz", expect.stringContaining("bar"))`,
16+
`expect(el).toHaveProperty("class", "foo")`,
17+
`expect(el).toHaveProperty("clazz", "foo")`,
18+
`expect(el).not.toHaveProperty("clazz", "foo")`,
19+
`expect(el).toHaveProperty("clazz", expect.stringContaining("bar"))`,
20+
`expect(el).not.toHaveProperty("clazz", expect.stringContaining("bar"))`,
21+
`expect(closeButton).toHaveAttribute("class", expect.stringMatching("bar"));`,
22+
],
23+
invalid: [
24+
{
25+
code: `expect(screen.getByRole("button").className).toBe("foo")`,
26+
errors,
27+
output: `expect(screen.getByRole("button")).toHaveClass("foo", { exact: true })`,
28+
},
29+
{
30+
code: `expect(screen.getByRole("button").className).not.toBe("foo")`,
31+
errors,
32+
output: `expect(screen.getByRole("button")).not.toHaveClass("foo", { exact: true })`,
33+
},
34+
{
35+
code: `expect(el).toHaveProperty("className", "foo")`,
36+
errors,
37+
output: `expect(el).toHaveClass("foo", { exact: true })`,
38+
},
39+
{
40+
code: `expect(el).toHaveAttribute("class", "foo")`,
41+
errors,
42+
output: `expect(el).toHaveClass("foo", { exact: true })`,
43+
},
44+
{
45+
code: `expect(el).toHaveAttribute(\`class\`, "foo")`,
46+
errors,
47+
output: `expect(el).toHaveClass("foo", { exact: true })`,
48+
},
49+
{
50+
code: `expect(el).toHaveAttribute("class", expect.stringContaining("bar"))`,
51+
errors,
52+
output: `expect(el).toHaveClass("bar")`,
53+
},
54+
{
55+
code: `expect(el).toHaveAttribute(\`class\`, expect.stringContaining("bar"))`,
56+
errors,
57+
output: `expect(el).toHaveClass("bar")`,
58+
},
59+
{
60+
code: `expect(el).not.toHaveProperty("className", "foo")`,
61+
errors,
62+
output: `expect(el).not.toHaveClass("foo", { exact: true })`,
63+
},
64+
{
65+
code: `expect(el).not.toHaveAttribute("class", "foo")`,
66+
errors,
67+
output: `expect(el).not.toHaveClass("foo", { exact: true })`,
68+
},
69+
{
70+
code: `expect(el.className).toContain("foo")`,
71+
errors,
72+
output: `expect(el).toHaveClass("foo")`,
73+
},
74+
{
75+
code: `expect(el.className).not.toContain("foo")`,
76+
errors,
77+
output: `expect(el).not.toHaveClass("foo")`,
78+
},
79+
{
80+
code: `expect(el.className).toBe("foo")`,
81+
errors,
82+
output: `expect(el).toHaveClass("foo", { exact: true })`,
83+
},
84+
{
85+
code: `expect(el.className).toEqual("foo")`,
86+
errors,
87+
output: `expect(el).toHaveClass("foo", { exact: true })`,
88+
},
89+
{
90+
code: `expect(el.className).toStrictEqual("foo")`,
91+
errors,
92+
output: `expect(el).toHaveClass("foo", { exact: true })`,
93+
},
94+
{
95+
code: `expect(el.className).toEqual(expect.stringContaining("foo"))`,
96+
errors,
97+
output: `expect(el).toHaveClass("foo")`,
98+
},
99+
{
100+
code: `expect(el.className).toEqual(expect.stringContaining(\`foo\`))`,
101+
errors,
102+
output: `expect(el).toHaveClass(\`foo\`)`,
103+
},
104+
{
105+
code: `expect(el.className).toStrictEqual(expect.stringContaining("foo"))`,
106+
errors,
107+
output: `expect(el).toHaveClass("foo")`,
108+
},
109+
{
110+
code: `expect(el.className).toEqual(expect.stringContaining("bar"))`,
111+
errors,
112+
output: `expect(el).toHaveClass("bar")`,
113+
},
114+
{
115+
code: `expect(el.classList).toContain("bar")`,
116+
errors,
117+
output: `expect(el).toHaveClass("bar")`,
118+
},
119+
{
120+
code: `expect(el.classList).toBe("bar")`,
121+
errors,
122+
},
123+
{
124+
code: `expect(el.classList[0]).toBe("bar")`,
125+
errors,
126+
output: `expect(el).toHaveClass("bar")`,
127+
},
128+
{
129+
code: `expect(el.classList[0]).not.toBe("bar")`,
130+
errors,
131+
},
132+
{
133+
code: `expect(el.classList[0]).toContain(("fo"))`,
134+
errors,
135+
},
136+
],
137+
});

0 commit comments

Comments
 (0)