Skip to content

Commit 87566a2

Browse files
authored
fix: prevent direct checks against attributes (#16)
* added direct checks * removed commented out test
1 parent 18b4258 commit 87566a2

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

lib/createBannedAttributeRule.js

+33
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,39 @@ module.exports = ({ preferred, negatedPreferred, attributes }) => context => {
3232
});
3333
}
3434
},
35+
36+
"CallExpression[callee.property.name=/toBe(Truthy|Falsy)?|toEqual/][callee.object.callee.name='expect']"(
37+
node
38+
) {
39+
const {
40+
arguments: [{ property, property: { name } = {} }],
41+
} = node.callee.object;
42+
const matcher = node.callee.property.name;
43+
const matcherArg = node.arguments.length && node.arguments[0].value;
44+
if (attributes.some(attr => attr === name)) {
45+
const isNegated =
46+
matcher.endsWith('Falsy') ||
47+
((matcher === 'toBe' || matcher === 'toEqual') &&
48+
matcherArg !== true);
49+
const correctFunction = getCorrectFunctionFor(
50+
node.callee.object,
51+
isNegated
52+
);
53+
context.report({
54+
node,
55+
message: `Use ${correctFunction}() instead of checking .${name} directly`,
56+
fix(fixer) {
57+
return [
58+
fixer.removeRange([property.start - 1, property.end]),
59+
fixer.replaceTextRange(
60+
[node.callee.property.start, node.end],
61+
`${correctFunction}()`
62+
),
63+
];
64+
},
65+
});
66+
}
67+
},
3568
"CallExpression[callee.property.name=/toHaveProperty|toHaveAttribute/][callee.object.property.name='not'][callee.object.object.callee.name='expect']"(
3669
node
3770
) {

tests/fixtures/createBannedAttributeTestCases.js

+33
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,38 @@ module.exports = ({ preferred, negatedPreferred, attribute }) => {
2222
},
2323
];
2424
}
25+
let directChecks = [];
26+
if (!/-/.test(attribute)) {
27+
directChecks = [
28+
{
29+
code: `expect(getByText('foo').${attribute}).toBeTruthy()`,
30+
errors: [
31+
{
32+
message: `Use ${preferred} instead of checking .${attribute} directly`,
33+
},
34+
],
35+
output: `expect(getByText('foo')).${[preferred]}`,
36+
},
37+
{
38+
code: `expect(getByText('foo').${attribute}).toBeFalsy()`,
39+
errors: [
40+
{
41+
message: `Use ${negatedPreferred} instead of checking .${attribute} directly`,
42+
},
43+
],
44+
output: `expect(getByText('foo')).${[negatedPreferred]}`,
45+
},
46+
{
47+
code: `expect(getByText('foo').${attribute}).toBe(true)`,
48+
errors: [
49+
{
50+
message: `Use ${preferred} instead of checking .${attribute} directly`,
51+
},
52+
],
53+
output: `expect(getByText('foo')).${[preferred]}`,
54+
},
55+
];
56+
}
2557
return {
2658
valid: [
2759
`expect(element).not.toHaveProperty('value', 'foo')`,
@@ -31,6 +63,7 @@ module.exports = ({ preferred, negatedPreferred, attribute }) => {
3163
],
3264
invalid: [
3365
...doubleNegativeCases,
66+
...directChecks,
3467
{
3568
code: `expect(element).toHaveProperty('${attribute}', true)`,
3669
errors: [

0 commit comments

Comments
 (0)