Skip to content

Commit ff4f760

Browse files
MrHensindresorhus
authored andcommitted
Add no-incorrect-deep-equal rule (#264)
1 parent 348c4e8 commit ff4f760

File tree

5 files changed

+427
-0
lines changed

5 files changed

+427
-0
lines changed

docs/rules/no-incorrect-deep-equal.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Avoid using `deepEqual` with primitives
2+
3+
The `deepEqual` and `notDeepEqual` assertions are unnecessary when comparing primitives. Use `is` or `not` instead.
4+
5+
This rule is fixable.
6+
7+
8+
## Fail
9+
10+
```js
11+
t.deepEqual(expression, 'foo');
12+
t.deepEqual(expression, 1);
13+
t.deepEqual(expression, `foo${bar}`);
14+
t.deepEqual(expression, null);
15+
t.deepEqual(expression, undefined);
16+
t.notDeepEqual(expression, undefined);
17+
```
18+
19+
20+
## Pass
21+
22+
```js
23+
t.is(expression, 'foo');
24+
25+
t.deepEqual(expression, otherExpression);
26+
t.deepEqual(expression, {});
27+
t.deepEqual(expression, []);
28+
t.notDeepEqual(expression, []);
29+
```

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module.exports = {
2929
'ava/no-identical-title': 'error',
3030
'ava/no-ignored-test-files': 'error',
3131
'ava/no-import-test-files': 'error',
32+
'ava/no-incorrect-deep-equal': 'error',
3233
'ava/no-inline-assertions': 'error',
3334
'ava/no-invalid-end': 'error',
3435
'ava/no-nested-tests': 'error',

readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Configure it in `package.json`.
4747
"ava/no-identical-title": "error",
4848
"ava/no-ignored-test-files": "error",
4949
"ava/no-import-test-files": "error",
50+
"ava/no-incorrect-deep-equal": "error",
5051
"ava/no-inline-assertions": "error",
5152
"ava/no-invalid-end": "error",
5253
"ava/no-nested-tests": "error",
@@ -86,6 +87,7 @@ The rules will only activate in test files.
8687
- [no-identical-title](docs/rules/no-identical-title.md) - Ensure no tests have the same title.
8788
- [no-ignored-test-files](docs/rules/no-ignored-test-files.md) - Ensure no tests are written in ignored files.
8889
- [no-import-test-files](docs/rules/no-import-test-files.md) - Ensure no test files are imported anywhere.
90+
- [no-incorrect-deep-equal](docs/rules/no-incorrect-deep-equal.md) - Avoid using `deepEqual` with primitives. *(fixable)*
8991
- [no-inline-assertions](docs/rules/no-inline-assertions.md) - Ensure assertions are not called from inline arrow functions. *(fixable)*
9092
- [no-invalid-end](docs/rules/no-invalid-end.md) - Ensure `t.end()` is only called inside `test.cb()`.
9193
- [no-nested-tests](docs/rules/no-nested-tests.md) - Ensure no tests are nested.

rules/no-incorrect-deep-equal.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
'use strict';
2+
const {visitIf} = require('enhance-visitors');
3+
const util = require('../util');
4+
const createAvaRule = require('../create-ava-rule');
5+
6+
const MESSAGE_ID = 'no-deep-equal-with-primative';
7+
8+
const buildDeepEqualMessage = (context, node) => {
9+
context.report({
10+
node,
11+
messageId: MESSAGE_ID,
12+
data: {
13+
callee: node.callee.property.name
14+
},
15+
fix: fixer => fixer.replaceText(node.callee.property, 'is')
16+
});
17+
};
18+
19+
const buildNotDeepEqualMessage = (context, node) => {
20+
context.report({
21+
node,
22+
messageId: MESSAGE_ID,
23+
data: {
24+
callee: node.callee.property.name
25+
},
26+
fix: fixer => fixer.replaceText(node.callee.property, 'not')
27+
});
28+
};
29+
30+
const create = context => {
31+
const ava = createAvaRule();
32+
33+
const callExpression = 'CallExpression';
34+
const deepEqual = '[callee.property.name="deepEqual"]';
35+
const notDeepEqual = '[callee.property.name="notDeepEqual"]';
36+
37+
const argumentsLiteral = ':matches([arguments.0.type="Literal"],[arguments.1.type="Literal"])';
38+
const argumentsUndefined = ':matches([arguments.0.type="Identifier"][arguments.0.name="undefined"],[arguments.1.type="Identifier"][arguments.1.name="undefined"])';
39+
const argumentsTemplate = ':matches([arguments.0.type="TemplateLiteral"],[arguments.1.type="TemplateLiteral"])';
40+
41+
return ava.merge({
42+
[`${callExpression}${deepEqual}${argumentsLiteral}`]: visitIf([
43+
ava.isInTestFile,
44+
ava.isInTestNode
45+
])(node => {
46+
buildDeepEqualMessage(context, node);
47+
}),
48+
[`${callExpression}${deepEqual}${argumentsUndefined}`]: visitIf([
49+
ava.isInTestFile,
50+
ava.isInTestNode
51+
])(node => {
52+
buildDeepEqualMessage(context, node);
53+
}),
54+
[`${callExpression}${deepEqual}${argumentsTemplate}`]: visitIf([
55+
ava.isInTestFile,
56+
ava.isInTestNode
57+
])(node => {
58+
buildDeepEqualMessage(context, node);
59+
}),
60+
[`${callExpression}${notDeepEqual}${argumentsLiteral}`]: visitIf([
61+
ava.isInTestFile,
62+
ava.isInTestNode
63+
])(node => {
64+
buildNotDeepEqualMessage(context, node);
65+
}),
66+
[`${callExpression}${notDeepEqual}${argumentsUndefined}`]: visitIf([
67+
ava.isInTestFile,
68+
ava.isInTestNode
69+
])(node => {
70+
buildNotDeepEqualMessage(context, node);
71+
}),
72+
[`${callExpression}${notDeepEqual}${argumentsTemplate}`]: visitIf([
73+
ava.isInTestFile,
74+
ava.isInTestNode
75+
])(node => {
76+
buildNotDeepEqualMessage(context, node);
77+
})
78+
});
79+
};
80+
81+
module.exports = {
82+
create,
83+
meta: {
84+
docs: {
85+
url: util.getDocsUrl(__filename)
86+
},
87+
fixable: true,
88+
messages: {
89+
[MESSAGE_ID]: 'Avoid using `{{callee}}` with literal primitives'
90+
},
91+
type: 'suggestion'
92+
}
93+
};

0 commit comments

Comments
 (0)