Skip to content

Commit 043e7bf

Browse files
feat(to-have-value): added new rule prefer-to-have-value (#111)
* feat(to-have-value): added new rule prefer-to-have-value * formatting * create all config for smoke test * create all config for smoke test * create all config for smoke test * Apply suggestions from code review Co-authored-by: Anton Niklasson <[email protected]> * updated metas & docs * fixed test Co-authored-by: Anton Niklasson <[email protected]>
1 parent dfe85c0 commit 043e7bf

18 files changed

+279
-70
lines changed

README.md

+14-11
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,19 @@ module.exports = {
100100
🔧 indicates that a rule is fixable.
101101

102102
<!-- __BEGIN AUTOGENERATED TABLE__ -->
103-
Name | 👍 | 🔧 | Description
104-
----- | ----- | ----- | -----
105-
[prefer-checked](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-checked.md) | 👍 | 🔧 | prefer toBeChecked over checking attributes
106-
[prefer-empty](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-empty.md) | 👍 | 🔧 | Prefer toBeEmpty over checking innerHTML
107-
[prefer-enabled-disabled](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-enabled-disabled.md) | 👍 | 🔧 | prefer toBeDisabled or toBeEnabled over checking attributes
108-
[prefer-focus](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-focus.md) | 👍 | 🔧 | prefer toHaveFocus over checking document.activeElement
109-
[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
110-
[prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | 👍 | 🔧 | prefer toBeRequired over checking properties
111-
[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
112-
[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
113-
[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
103+
104+
| Name | 👍 | 🔧 | Description |
105+
| ---------------------------------------------------------------------------------------------------------------------------------------------- | --- | --- | --------------------------------------------------------------------- |
106+
| [prefer-checked](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-checked.md) | 👍 | 🔧 | prefer toBeChecked over checking attributes |
107+
| [prefer-empty](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-empty.md) | 👍 | 🔧 | Prefer toBeEmpty over checking innerHTML |
108+
| [prefer-enabled-disabled](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-enabled-disabled.md) | 👍 | 🔧 | prefer toBeDisabled or toBeEnabled over checking attributes |
109+
| [prefer-focus](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-focus.md) | 👍 | 🔧 | prefer toHaveFocus over checking document.activeElement |
110+
| [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 |
111+
| [prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | 👍 | 🔧 | prefer toBeRequired over checking properties |
112+
| [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-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 |
114+
| [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 |
115+
| [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 |
114116

115117
<!-- __END AUTOGENERATED TABLE__ -->
116118

@@ -160,6 +162,7 @@ Thanks goes to these people ([emoji key][emojis]):
160162

161163
<!-- markdownlint-enable -->
162164
<!-- prettier-ignore-end -->
165+
163166
<!-- ALL-CONTRIBUTORS-LIST:END -->
164167

165168
This project follows the [all-contributors][all-contributors] specification.

docs/rules/prefer-in-document.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const bar = screen.queryByText("bar");
4242
expect(bar).not.toBeDefined();
4343

4444
const baz = await screen.findByText("baz");
45-
expect(baz).toBeDefined()
45+
expect(baz).toBeDefined();
4646
```
4747

4848
## When Not To Use It

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

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# prefer toHaveAttribute over checking getAttribute/hasAttribute (prefer-to-have-attribute)
2+
3+
This rule is an autofixable rule that encourages the use of toHaveValue over checking the value attribute.
4+
5+
## Rule Details
6+
7+
This rule checks for usages of `.value` or `.toHaveAttribute("value")`.
8+
The only valid use case is when using greater/less than
9+
matchers since there isn't any equivalent use with `toHaveValue`
10+
11+
Examples of **incorrect** code for this rule:
12+
13+
```js
14+
expect(element).toHaveAttribute("value", "foo");
15+
expect(element).toHaveProperty("value", "foo");
16+
expect(element.value).toBe("foo");
17+
expect(element.value).not.toEqual("foo");
18+
expect(element.value).not.toStrictEqual("foo");
19+
```
20+
21+
Examples of **correct** code for this rule:
22+
23+
```js
24+
expect(element).toHaveValue("foo");
25+
expect(element.value).toBeGreaterThan(2);
26+
expect(element.value).toBeLessThan(2);
27+
```
28+
29+
## When Not To Use It
30+
31+
If you don't care about using built in matchers for checking attributes on dom
32+
elements.
33+
34+
## Further Reading
35+
36+
- [jest-dom toHaveAttribute](https://github.com/testing-library/jest-dom#tohaveattribute)
37+
- [getAttribute](https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute)
38+
- [hasAttribute](https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute)

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
],
3131
"scripts": {
3232
"build": "kcd-scripts build",
33+
"pregenerate-readme-table": "yarn build",
3334
"generate-readme-table": "node build/generate-readme-table.js",
3435
"lint": "kcd-scripts lint",
3536
"setup": "npm install && npm run validate -s",
+41-48
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,51 @@
11
module.exports = {
2-
/** Repositories to scan */
3-
repositories: require('./repositories.json'),
2+
/** Repositories to scan */
3+
repositories: require("./repositories.json"),
44

5-
/** Extensions of files under scanning */
6-
extensions: ['js', 'jsx', 'ts', 'tsx'],
5+
/** Extensions of files under scanning */
6+
extensions: ["js", "jsx", "ts", "tsx"],
77

8-
/** Optional pattern used to exclude paths */
9-
pathIgnorePattern: `(${[
10-
'node_modules',
11-
'\\/\\.', // Any file or directory starting with dot, e.g. ".git"
12-
'/dist/',
13-
'/build/',
8+
/** Optional pattern used to exclude paths */
9+
pathIgnorePattern: `(${[
10+
"node_modules",
11+
"\\/\\.", // Any file or directory starting with dot, e.g. ".git"
12+
"/dist/",
13+
"/build/",
1414
15-
// Common patterns for minified JS
16-
'babel\\.js',
17-
'vendor\\.js',
18-
'vendors\\.js',
19-
'chunk\\.js',
20-
'bundle\\.js',
21-
'react-dom\\.development\\.js',
22-
'\\.min\\.js', // Any *.min.js
23-
].join('|')})`,
15+
// Common patterns for minified JS
16+
"babel\\.js",
17+
"vendor\\.js",
18+
"vendors\\.js",
19+
"chunk\\.js",
20+
"bundle\\.js",
21+
"react-dom\\.development\\.js",
22+
"\\.min\\.js", // Any *.min.js
23+
].join("|")})`,
2424

25-
/** Empty array since we are only interested in linter crashes */
26-
rulesUnderTesting: [],
25+
/** Empty array since we are only interested in linter crashes */
26+
rulesUnderTesting: [],
2727

28-
/** Maximum amount of tasks ran concurrently */
29-
concurrentTasks: 2,
28+
/** Maximum amount of tasks ran concurrently */
29+
concurrentTasks: 2,
3030

31-
/** Optional boolean flag used to enable caching of cloned repositories. For CIs it's ideal to disable caching. Defauls to true. */
32-
cache: false,
31+
/** Optional boolean flag used to enable caching of cloned repositories. For CIs it's ideal to disable caching. Defauls to true. */
32+
cache: false,
3333

34-
/** ESLint configuration */
35-
eslintrc: {
36-
root: true,
37-
env: {
38-
es6: true,
39-
},
40-
parser: '@typescript-eslint/parser',
41-
parserOptions: {
42-
ecmaVersion: 2020,
43-
sourceType: 'module',
44-
ecmaFeatures: {
45-
jsx: true,
46-
},
47-
},
48-
plugins: [
49-
'jest-dom',
50-
],
51-
extends: [
52-
'plugin:jest-dom/recommended',
53-
],
54-
rules: {
55-
'jest-dom/prefer-in-document': 'error'
56-
},
34+
/** ESLint configuration */
35+
eslintrc: {
36+
root: true,
37+
env: {
38+
es6: true,
5739
},
40+
parser: "@typescript-eslint/parser",
41+
parserOptions: {
42+
ecmaVersion: 2020,
43+
sourceType: "module",
44+
ecmaFeatures: {
45+
jsx: true,
46+
},
47+
},
48+
plugins: ["jest-dom"],
49+
extends: ["plugin:jest-dom/all"],
50+
},
5851
};

src/__tests__/index.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ it.each(Object.keys(rules))("%s should export required fields", (ruleName) => {
99
const rule = rules[ruleName];
1010
expect(rule).toHaveProperty("create", expect.any(Function));
1111
expect(rule.meta.docs.url).not.toBeEmpty();
12-
expect(rule.meta.docs.category).toBe("jest-dom");
12+
expect(rule.meta.docs.category).toBe("Best Practices");
1313
expect(rule.meta.docs.description).not.toBeEmpty();
1414
});
1515

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* eslint-disable no-template-curly-in-string */
2+
/**
3+
* @fileoverview Prefer toBeEmptyDOMElement over checking innerHTML
4+
* @author Ben Monro
5+
*/
6+
7+
//------------------------------------------------------------------------------
8+
// Requirements
9+
//------------------------------------------------------------------------------
10+
11+
import { RuleTester } from "eslint";
12+
import * as rule from "../../../rules/prefer-to-have-value";
13+
14+
//------------------------------------------------------------------------------
15+
// Tests
16+
//------------------------------------------------------------------------------
17+
18+
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015 } });
19+
20+
const errors = [{ messageId: "use-to-have-value" }];
21+
ruleTester.run("prefer-empty", rule, {
22+
valid: [
23+
`expect(element).toHaveValue('foo')`,
24+
`expect(element.value).toBeGreaterThan(2);`,
25+
`expect(element.value).toBeLessThan(2);`,
26+
],
27+
invalid: [
28+
{
29+
code: `expect(element).toHaveAttribute('value', 'foo')`,
30+
errors,
31+
output: `expect(element).toHaveValue('foo')`,
32+
},
33+
{
34+
code: `expect(element).toHaveProperty("value", "foo")`,
35+
errors,
36+
output: `expect(element).toHaveValue("foo")`,
37+
},
38+
{
39+
code: `expect(element).not.toHaveAttribute('value', 'foo')`,
40+
errors,
41+
output: `expect(element).not.toHaveValue('foo')`,
42+
},
43+
{
44+
code: `expect(element).not.toHaveProperty("value", "foo")`,
45+
errors,
46+
output: `expect(element).not.toHaveValue("foo")`,
47+
},
48+
{
49+
code: `expect(element.value).toBe('foo')`,
50+
errors,
51+
output: `expect(element).toHaveValue('foo')`,
52+
},
53+
{
54+
code: `expect(element.value).toEqual('foo')`,
55+
errors,
56+
output: `expect(element).toHaveValue('foo')`,
57+
},
58+
{
59+
code: `expect(element.value).toStrictEqual('foo')`,
60+
errors,
61+
output: `expect(element).toHaveValue('foo')`,
62+
},
63+
{
64+
code: `expect(element.value).not.toBe('foo')`,
65+
errors,
66+
output: `expect(element).not.toHaveValue('foo')`,
67+
},
68+
{
69+
code: `expect(element.value).not.toEqual('foo')`,
70+
errors,
71+
output: `expect(element).not.toHaveValue('foo')`,
72+
},
73+
{
74+
code: `expect(element.value).not.toStrictEqual('foo')`,
75+
errors,
76+
output: `expect(element).not.toHaveValue('foo')`,
77+
},
78+
],
79+
});

src/index.js

+13
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,22 @@ export const generateRecommendedConfig = (allRules) =>
2525
{}
2626
);
2727

28+
export const generateAllRulesConfig = (allRules) =>
29+
Object.entries(allRules).reduce(
30+
(memo, [name]) => ({
31+
...memo,
32+
...{ [`jest-dom/${name}`]: "error" },
33+
}),
34+
{}
35+
);
36+
2837
export const configs = {
2938
recommended: {
3039
plugins: ["jest-dom"],
3140
rules: generateRecommendedConfig(rules),
3241
},
42+
all: {
43+
plugins: ["jest-dom"],
44+
rules: generateAllRulesConfig(rules),
45+
},
3346
};

src/rules/prefer-checked.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import createBannedAttributeRule from "../createBannedAttributeRule";
88
export const meta = {
99
docs: {
1010
description: "prefer toBeChecked over checking attributes",
11-
category: "jest-dom",
11+
category: "Best Practices",
1212
recommended: true,
1313
url: "prefer-checked",
1414
},

src/rules/prefer-empty.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
export const meta = {
77
docs: {
88
description: "Prefer toBeEmpty over checking innerHTML",
9-
category: "jest-dom",
9+
category: "Best Practices",
1010
recommended: true,
1111
url: "prefer-empty",
1212
},

src/rules/prefer-enabled-disabled.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import createBannedAttributeRule from "../createBannedAttributeRule";
88
export const meta = {
99
docs: {
1010
description: "prefer toBeDisabled or toBeEnabled over checking attributes",
11-
category: "jest-dom",
11+
category: "Best Practices",
1212
recommended: true,
1313
url: "prefer-enabled-disabled",
1414
},

src/rules/prefer-focus.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const meta = {
1616
docs: {
1717
url: "prefer-focus",
1818
description: "prefer toHaveFocus over checking document.activeElement",
19-
category: "jest-dom",
19+
category: "Best Practices",
2020
recommended: true,
2121
},
2222
fixable: "code",

src/rules/prefer-in-document.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { queries } from "../queries";
88
export const meta = {
99
type: "suggestion",
1010
docs: {
11-
category: "jest-dom",
11+
category: "Best Practices",
1212
description:
1313
"Prefer .toBeInTheDocument() for asserting the existence of a DOM node",
1414
url: "prefer-in-document",

src/rules/prefer-required.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import createBannedAttributeRule from "../createBannedAttributeRule";
88
export const meta = {
99
docs: {
1010
description: "prefer toBeRequired over checking properties",
11-
category: "jest-dom",
11+
category: "Best Practices",
1212
recommended: true,
1313
url: "prefer-required",
1414
},

src/rules/prefer-to-have-attribute.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
export const meta = {
1111
docs: {
12-
category: "jest-dom",
12+
category: "Best Practices",
1313
description:
1414
"prefer toHaveAttribute over checking getAttribute/hasAttribute ",
1515
url: "prefer-to-have-attribute",

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
const camelCase = (str) => str.replace(/-([a-z])/g, (c) => c[1].toUpperCase());
1010
export const meta = {
1111
docs: {
12-
category: "jest-dom",
12+
category: "Best Practices",
1313
url: "prefer-to-have-style",
1414
description: "prefer toHaveStyle over checking element style",
1515
recommended: true,

src/rules/prefer-to-have-text-content.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
export const meta = {
77
docs: {
8-
category: "jest-dom",
8+
category: "Best Practices",
99
url: "prefer-to-have-text-content",
1010
description: "Prefer toHaveTextContent over checking element.textContent",
1111
recommended: true,

0 commit comments

Comments
 (0)