Skip to content

Commit 8813c11

Browse files
authored
feat: new rule prefer-focus (#19)
* feat: new rule prefer-focus * update prefer-focus.md * removed scaffolding * removed scaffolding
1 parent abf7cca commit 8813c11

File tree

5 files changed

+289
-0
lines changed

5 files changed

+289
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Name | ✔️ | 🛠 | Description
6969
----- | ----- | ----- | -----
7070
[prefer-checked](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-checked.md) | ✔️ | 🛠 | prefer toBeChecked over checking attributes
7171
[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
72+
[prefer-focus](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-focus.md) | ✔️ | 🛠 | prefer toHaveFocus over checking document.activeElement
7273
[prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | ✔️ | 🛠 | prefer toBeRequired over checking properties
7374
[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
7475
<!-- __END AUTOGENERATED TABLE__ -->

docs/rules/prefer-focus.md

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# prefer-focus
2+
3+
prefer toHaveFocus over checking document.activeElement (prefer-focus)
4+
5+
## Rule Details
6+
7+
This autofixable rule aims to improve readability & consistency of tests with the use of the jest-dom matcher `toHaveFocus` rather than checking document.activeElement.
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```js
12+
13+
expect(document.activeElement).toBe(foo)
14+
expect(window.document.activeElement).toBe(foo)
15+
expect(global.window.document.activeElement).toBe(foo)
16+
expect(global.document.activeElement).toBe(foo)
17+
expect(foo).toBe(global.document.activeElement)
18+
expect(foo).toBe(window.document.activeElement)
19+
expect(foo).toBe(global.window.document.activeElement)
20+
expect(foo).toBe(document.activeElement)
21+
expect(foo).toEqual(document.activeElement)
22+
23+
24+
expect(document.activeElement).not.toBe(foo)
25+
expect(window.document.activeElement).not.toBe(foo)
26+
expect(global.window.document.activeElement).not.toBe(foo)
27+
expect(global.document.activeElement).not.toBe(foo)
28+
expect(foo).not.toBe(global.document.activeElement)
29+
expect(foo).not.toBe(window.document.activeElement)
30+
expect(foo).not.toBe(global.window.document.activeElement)
31+
expect(foo).not.toBe(document.activeElement)
32+
expect(foo).not.toEqual(document.activeElement)
33+
34+
```
35+
36+
Examples of **correct** code for this rule:
37+
38+
```js
39+
40+
expect(document.activeElement).not.toBeNull()
41+
42+
expect(document.activeElement).toBeNull()
43+
44+
```
45+
46+
47+
## When Not To Use It
48+
49+
If you don't care if people use toHaveFocus

lib/rules/prefer-focus.js

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/**
2+
* @fileoverview prefer toHaveFocus over checking activeElementa
3+
* @author Ben Monro
4+
*/
5+
'use strict';
6+
7+
const variantsOfDoc = [
8+
// document:
9+
`[object.name=document]`,
10+
// window.document || global.document:
11+
`[object.object.name=/(global|window)$/][object.property.name=document]`,
12+
// global.window.document:
13+
`[object.object.object.name='global'][object.object.property.name='window'][object.property.name=document]`,
14+
];
15+
16+
module.exports = {
17+
meta: {
18+
docs: {
19+
description: 'prefer toHaveFocus over checking document.activeElement',
20+
category: 'jest-dom',
21+
recommended: true,
22+
},
23+
fixable: 'code',
24+
},
25+
26+
create: function(context) {
27+
return {
28+
[variantsOfDoc
29+
.map(
30+
variant =>
31+
`MemberExpression${variant}[property.name='activeElement'][parent.parent.object.callee.name='expect'][parent.parent.property.name='not'][parent.parent.parent.property.name=/to(Be|(Strict)?Equal)$/]`
32+
)
33+
.join(', ')](node) {
34+
const element =
35+
node.parent.parent.parent.parent.callee.parent.arguments[0];
36+
const matcher = node.parent.parent.parent.parent.callee.property;
37+
38+
context.report({
39+
node: node.parent,
40+
message: `Use toHaveFocus instead of checking activeElement`,
41+
fix(fixer) {
42+
return [
43+
fixer.replaceText(node, element.name),
44+
fixer.remove(element),
45+
fixer.replaceText(matcher, 'toHaveFocus'),
46+
];
47+
},
48+
});
49+
},
50+
[variantsOfDoc
51+
.map(
52+
variant =>
53+
`MemberExpression${variant}[property.name='activeElement'][parent.callee.object.object.callee.name='expect'][parent.callee.property.name=/to(Be|(Strict)?Equal)$/]`
54+
)
55+
.join(', ')](node) {
56+
const matcher = node.parent.callee.property;
57+
context.report({
58+
node: node.parent,
59+
message: `Use toHaveFocus instead of checking activeElement`,
60+
fix(fixer) {
61+
return [
62+
fixer.remove(node),
63+
fixer.replaceText(matcher, 'toHaveFocus'),
64+
];
65+
},
66+
});
67+
},
68+
[variantsOfDoc
69+
.map(
70+
variant =>
71+
`MemberExpression${variant}[property.name='activeElement'][parent.callee.name='expect'][parent.parent.property.name=/to(Be|(Strict)?Equal)$/]`
72+
)
73+
.join(', ')](node) {
74+
const element = node.parent.parent.parent.arguments[0];
75+
const matcher = node.parent.parent.property;
76+
context.report({
77+
node: node.parent,
78+
message: `Use toHaveFocus instead of checking activeElement`,
79+
fix(fixer) {
80+
return [
81+
fixer.replaceText(node, element.name),
82+
fixer.remove(element),
83+
fixer.replaceText(matcher, 'toHaveFocus'),
84+
];
85+
},
86+
});
87+
},
88+
[variantsOfDoc
89+
.map(
90+
variant =>
91+
`MemberExpression${variant}[property.name='activeElement'][parent.callee.object.callee.name='expect'][parent.callee.property.name=/to(Be|(Strict)?Equal)$/]`
92+
)
93+
.join(', ')](node) {
94+
const matcher = node.parent.callee.property;
95+
context.report({
96+
node: node.parent,
97+
message: `Use toHaveFocus instead of checking activeElement`,
98+
fix(fixer) {
99+
return [
100+
fixer.remove(node),
101+
fixer.replaceText(matcher, 'toHaveFocus'),
102+
];
103+
},
104+
});
105+
},
106+
};
107+
},
108+
};

tests/__snapshots__/index.test.js.snap

+11
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ Object {
2626
"fixable": "code",
2727
},
2828
},
29+
"prefer-focus": Object {
30+
"create": [Function],
31+
"meta": Object {
32+
"docs": Object {
33+
"category": "jest-dom",
34+
"description": "prefer toHaveFocus over checking document.activeElement",
35+
"recommended": true,
36+
},
37+
"fixable": "code",
38+
},
39+
},
2940
"prefer-required": Object {
3041
"create": [Function],
3142
"meta": Object {

tests/lib/rules/prefer-focus.js

+120
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* @fileoverview prefer toHaveFocus over checking document.activeElement
3+
* @author Ben Monro
4+
*/
5+
'use strict';
6+
7+
let rule = require('../../../lib/rules/prefer-focus'),
8+
RuleTester = require('eslint').RuleTester;
9+
10+
let ruleTester = new RuleTester();
11+
ruleTester.run('prefer-focus', rule, {
12+
valid: [
13+
`expect(document.activeElement).toBeNull()`,
14+
`expect(document.activeElement).not.toBeNull()`,
15+
],
16+
17+
invalid: [
18+
{
19+
code: 'expect(document.activeElement).toBe(foo)',
20+
errors: [
21+
{
22+
message: 'Use toHaveFocus instead of checking activeElement',
23+
},
24+
],
25+
output: 'expect(foo).toHaveFocus()',
26+
},
27+
{
28+
code: 'expect(document.activeElement).not.toBe(foo)',
29+
errors: [
30+
{
31+
message: 'Use toHaveFocus instead of checking activeElement',
32+
},
33+
],
34+
output: 'expect(foo).not.toHaveFocus()',
35+
},
36+
{
37+
code: 'expect(foo).not.toBe(document.activeElement)',
38+
errors: [
39+
{
40+
message: 'Use toHaveFocus instead of checking activeElement',
41+
},
42+
],
43+
output: 'expect(foo).not.toHaveFocus()',
44+
},
45+
{
46+
code: 'expect(window.document.activeElement).toBe(foo)',
47+
errors: [
48+
{
49+
message: 'Use toHaveFocus instead of checking activeElement',
50+
},
51+
],
52+
output: 'expect(foo).toHaveFocus()',
53+
},
54+
{
55+
code: 'expect(global.window.document.activeElement).toBe(foo)',
56+
errors: [
57+
{
58+
message: 'Use toHaveFocus instead of checking activeElement',
59+
},
60+
],
61+
output: 'expect(foo).toHaveFocus()',
62+
},
63+
{
64+
code: 'expect(global.document.activeElement).toBe(foo)',
65+
errors: [
66+
{
67+
message: 'Use toHaveFocus instead of checking activeElement',
68+
},
69+
],
70+
output: 'expect(foo).toHaveFocus()',
71+
},
72+
{
73+
code: 'expect(foo).toBe(global.document.activeElement)',
74+
errors: [
75+
{
76+
message: 'Use toHaveFocus instead of checking activeElement',
77+
},
78+
],
79+
output: 'expect(foo).toHaveFocus()',
80+
},
81+
{
82+
code: 'expect(foo).toBe(window.document.activeElement)',
83+
errors: [
84+
{
85+
message: 'Use toHaveFocus instead of checking activeElement',
86+
},
87+
],
88+
output: 'expect(foo).toHaveFocus()',
89+
},
90+
91+
{
92+
code: 'expect(foo).toBe(global.window.document.activeElement)',
93+
errors: [
94+
{
95+
message: 'Use toHaveFocus instead of checking activeElement',
96+
},
97+
],
98+
output: 'expect(foo).toHaveFocus()',
99+
},
100+
{
101+
code: 'expect(foo).toBe(document.activeElement)',
102+
errors: [
103+
{
104+
message: 'Use toHaveFocus instead of checking activeElement',
105+
},
106+
],
107+
output: 'expect(foo).toHaveFocus()',
108+
},
109+
110+
{
111+
code: 'expect(foo).toEqual(document.activeElement)',
112+
errors: [
113+
{
114+
message: 'Use toHaveFocus instead of checking activeElement',
115+
},
116+
],
117+
output: 'expect(foo).toHaveFocus()',
118+
},
119+
],
120+
});

0 commit comments

Comments
 (0)