Skip to content

Commit 30cbe7b

Browse files
benmonroBen Monro
and
Ben Monro
authored
feat: Added prefer-to-have-text-content (#37)
* add .vscode to git ignore * formatting * added toHaveTextContent rule * added toHaveTextContent rule * formatting * -u * handling not * handling not * whitespace * updated readme Co-authored-by: Ben Monro <[email protected]>
1 parent a2c0f9e commit 30cbe7b

25 files changed

+714
-441
lines changed

.eslintrc.json

+3-4
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,16 @@
66
"commonjs": true,
77
"es6": true,
88
"node": true
9-
// "jest/globals": true
109
},
1110
"plugins": [
1211
"eslint-plugin",
1312
"prettier"
1413
],
1514
"extends": [
16-
"plugin:eslint-plugin/recommended"
15+
"plugin:eslint-plugin/recommended",
16+
"prettier"
1717
],
1818
"rules": {
19-
"prettier/prettier": "error",
2019
"no-var": "error"
2120
}
22-
}
21+
}

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules
22
coverage
33
yarn.lock
44
package-lock.json
5+
.vscode

.prettierrc.json

-4
This file was deleted.

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ Name | ✔️ | 🛠 | Description
7474
[prefer-focus](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-focus.md) | ✔️ | 🛠 | prefer toHaveFocus over checking document.activeElement
7575
[prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | ✔️ | 🛠 | prefer toBeRequired over checking properties
7676
[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
77+
[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
7778
<!-- __END AUTOGENERATED TABLE__ -->
7879

7980
## Contributors ✨

build/generate-readme-table.js

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
'use strict';
1+
"use strict";
22

3-
const fs = require('fs');
4-
const path = require('path');
5-
const rules = require('..').rules;
3+
const fs = require("fs");
4+
const path = require("path");
5+
const rules = require("..").rules;
66

7-
const README_LOCATION = path.resolve(__dirname, '..', 'README.md');
8-
const BEGIN_TABLE_MARKER = '<!-- __BEGIN AUTOGENERATED TABLE__ -->\n';
9-
const END_TABLE_MARKER = '\n<!-- __END AUTOGENERATED TABLE__ -->';
7+
const README_LOCATION = path.resolve(__dirname, "..", "README.md");
8+
const BEGIN_TABLE_MARKER = "<!-- __BEGIN AUTOGENERATED TABLE__ -->\n";
9+
const END_TABLE_MARKER = "\n<!-- __END AUTOGENERATED TABLE__ -->";
1010

1111
const expectedTableLines = Object.keys(rules)
1212
.sort()
@@ -17,19 +17,19 @@ const expectedTableLines = Object.keys(rules)
1717
lines.push(
1818
[
1919
`[${ruleId}](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/${ruleId}.md)`,
20-
rule.meta.docs.recommended ? '✔️' : '',
21-
rule.meta.fixable ? '🛠' : '',
22-
rule.meta.docs.description,
23-
].join(' | ')
20+
rule.meta.docs.recommended ? "✔️" : "",
21+
rule.meta.fixable ? "🛠" : "",
22+
rule.meta.docs.description
23+
].join(" | ")
2424
);
2525

2626
return lines;
2727
},
28-
['Name | ✔️ | 🛠 | Description', '----- | ----- | ----- | -----']
28+
["Name | ✔️ | 🛠 | Description", "----- | ----- | ----- | -----"]
2929
)
30-
.join('\n');
30+
.join("\n");
3131

32-
const readmeContents = fs.readFileSync(README_LOCATION, 'utf8');
32+
const readmeContents = fs.readFileSync(README_LOCATION, "utf8");
3333

3434
if (!readmeContents.includes(BEGIN_TABLE_MARKER)) {
3535
throw new Error(
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Prefer toHaveTextContent over checking element.textContent (prefer-to-have-text-content)
2+
3+
Please describe the origin of the rule here.
4+
5+
## Rule Details
6+
7+
This rule aims to prevent checking of the `textContent` DOM node attribute in tests and prefer `toHaveTextContent` instead.
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```js
12+
expect(element.textContent).toBe("foo")
13+
expect(container.firstChild.textContent).toBe("foo")
14+
expect(getByText('foo').textContent).toBe("foo")
15+
expect(screen.getByText('foo').textContent).toBe("foo")
16+
expect(element.textContent).toEqual("foo")
17+
expect(element.textContent).toContain("foo")
18+
expect(element.textContent).not.toBe("foo")
19+
expect(element.textContent).not.toContain("foo")
20+
21+
```
22+
23+
Examples of **correct** code for this rule:
24+
25+
```js
26+
27+
28+
expect(string).toBe("foo"),
29+
expect(element).toHaveTextContent("foo"),
30+
expect(container.lastNode).toBe("foo")
31+
32+
```
33+
34+
## When Not To Use It
35+
36+
Don't use this rule if you don't care about the added readability and improvements that `toHaveTextContent` offers to your expects.
37+
38+
## Further Reading
39+
40+
* [Docs on toHaveContent](https://github.com/testing-library/jest-dom#tohavetextcontent)

jest.config.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
module.exports = {
2-
testMatch: ['**/tests/**/*.js'],
2+
testMatch: ["**/tests/**/*.js"],
33
collectCoverage: true,
44
coverageThreshold: {
55
global: {
66
branches: 96.55,
77
functions: 100,
88
lines: 98.97,
9-
statements: 0,
10-
},
9+
statements: 0
10+
}
1111
},
12-
testPathIgnorePatterns: ['<rootDir>/tests/fixtures/'],
13-
collectCoverageFrom: ['lib/**/*.js', '!**/node_modules/**'],
12+
testPathIgnorePatterns: ["<rootDir>/tests/fixtures/"],
13+
collectCoverageFrom: ["lib/**/*.js", "!**/node_modules/**"]
1414
};

lib/createBannedAttributeRule.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
22
function getCorrectFunctionFor(node, negated = false) {
33
return (node.arguments.length === 1 ||
44
node.arguments[1].value === true ||
5-
node.arguments[1].value === '') &&
5+
node.arguments[1].value === "") &&
66
!negated
77
? preferred
88
: negatedPreferred;
@@ -15,7 +15,7 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
1515
[`CallExpression[callee.property.name=/${preferred}|${negatedPreferred}/][callee.object.property.name='not'][callee.object.object.callee.name='expect']`](
1616
node
1717
) {
18-
if (negatedPreferred.startsWith('toBe')) {
18+
if (negatedPreferred.startsWith("toBe")) {
1919
const incorrectFunction = node.callee.property.name;
2020

2121
const correctFunction =
@@ -28,7 +28,7 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
2828
[node.callee.object.property.range[0], node.range[1]],
2929
`${correctFunction}()`
3030
);
31-
},
31+
}
3232
});
3333
}
3434
},
@@ -37,14 +37,14 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
3737
node
3838
) {
3939
const {
40-
arguments: [{ property, property: { name } = {} }],
40+
arguments: [{ property, property: { name } = {} }]
4141
} = node.callee.object;
4242
const matcher = node.callee.property.name;
4343
const matcherArg = node.arguments.length && node.arguments[0].value;
4444
if (attributes.some(attr => attr === name)) {
4545
const isNegated =
46-
matcher.endsWith('Falsy') ||
47-
((matcher === 'toBe' || matcher === 'toEqual') &&
46+
matcher.endsWith("Falsy") ||
47+
((matcher === "toBe" || matcher === "toEqual") &&
4848
matcherArg !== true);
4949
const correctFunction = getCorrectFunctionFor(
5050
node.callee.object,
@@ -59,9 +59,9 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
5959
fixer.replaceTextRange(
6060
[node.callee.property.range[0], node.range[1]],
6161
`${correctFunction}()`
62-
),
62+
)
6363
];
64-
},
64+
}
6565
});
6666
}
6767
},
@@ -81,7 +81,7 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
8181
[node.callee.object.property.range[0], node.range[1]],
8282
`${correctFunction}()`
8383
);
84-
},
84+
}
8585
});
8686
}
8787
},
@@ -95,7 +95,7 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
9595

9696
const message = `Use ${correctFunction}() instead of ${incorrectFunction}(${node.arguments
9797
.map(({ raw }) => raw)
98-
.join(', ')})`;
98+
.join(", ")})`;
9999
context.report({
100100
node: node.callee.property,
101101
message,
@@ -104,11 +104,11 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
104104
fixer.replaceTextRange(
105105
[node.callee.property.range[0], node.range[1]],
106106
`${correctFunction}()`
107-
),
107+
)
108108
];
109-
},
109+
}
110110
});
111111
}
112-
},
112+
}
113113
};
114114
};

lib/index.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,34 @@
22
* @fileoverview lint rules for use with jest-dom
33
* @author Ben Monro
44
*/
5-
'use strict';
5+
"use strict";
66

77
//------------------------------------------------------------------------------
88
// Requirements
99
//------------------------------------------------------------------------------
1010

11-
let requireIndex = require('requireindex');
11+
let requireIndex = require("requireindex");
1212

1313
//------------------------------------------------------------------------------
1414
// Plugin Definition
1515
//------------------------------------------------------------------------------
1616

1717
// import all rules in lib/rules
18-
module.exports.rules = requireIndex(__dirname + '/rules');
18+
module.exports.rules = requireIndex(__dirname + "/rules");
1919

2020
module.exports.generateRecommendedConfig = rules => {
2121
return Object.entries(rules).reduce(
2222
(memo, [name, rule]) =>
2323
rule.meta.docs.recommended
24-
? { ...memo, [`jest-dom/${name}`]: 'error' }
24+
? { ...memo, [`jest-dom/${name}`]: "error" }
2525
: memo,
2626
{}
2727
);
2828
};
2929

3030
module.exports.configs = {
3131
recommended: {
32-
plugins: ['jest-dom'],
33-
rules: module.exports.generateRecommendedConfig(module.exports.rules),
34-
},
32+
plugins: ["jest-dom"],
33+
rules: module.exports.generateRecommendedConfig(module.exports.rules)
34+
}
3535
};

lib/rules/prefer-checked.js

+10-10
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@
22
* @fileoverview prefer toBeDisabled or toBeEnabled over attribute checks
33
* @author Ben Monro
44
*/
5-
'use strict';
5+
"use strict";
66

7-
const createBannedAttributeRule = require('../createBannedAttributeRule');
7+
const createBannedAttributeRule = require("../createBannedAttributeRule");
88

99
module.exports = {
1010
meta: {
1111
docs: {
12-
description: 'prefer toBeChecked over checking attributes',
13-
category: 'jest-dom',
12+
description: "prefer toBeChecked over checking attributes",
13+
category: "jest-dom",
1414
recommended: true,
15-
url: 'prefer-checked',
15+
url: "prefer-checked"
1616
},
17-
fixable: 'code',
17+
fixable: "code"
1818
},
1919

2020
create: createBannedAttributeRule({
21-
preferred: 'toBeChecked',
22-
negatedPreferred: 'not.toBeChecked',
23-
attributes: ['checked', 'aria-checked'],
24-
}),
21+
preferred: "toBeChecked",
22+
negatedPreferred: "not.toBeChecked",
23+
attributes: ["checked", "aria-checked"]
24+
})
2525
};

0 commit comments

Comments
 (0)