eslint-plugin-jest-dom
Advanced tools
Comparing version 3.3.0 to 3.4.0
@@ -6,3 +6,3 @@ "use strict"; | ||
}); | ||
exports.queriesByVariant = exports.queries = void 0; | ||
exports.queries = void 0; | ||
@@ -12,8 +12,2 @@ var _dom = require("@testing-library/dom"); | ||
const queries = Object.keys(_dom.queries); | ||
exports.queries = queries; | ||
const queriesByVariant = { | ||
query: queries.filter(q => q.startsWith("query")), | ||
get: queries.filter(q => q.startsWith("get")), | ||
find: queries.filter(q => q.startsWith("find")) | ||
}; | ||
exports.queriesByVariant = queriesByVariant; | ||
exports.queries = queries; |
@@ -33,57 +33,116 @@ "use strict"; | ||
function check(context, { | ||
queryNode, | ||
matcherNode, | ||
matcherArguments, | ||
negatedMatcher | ||
}) { | ||
const query = queryNode.name || queryNode.property.name; // toHaveLength() is only invalid with 0 or 1 | ||
const create = context => { | ||
const alternativeMatchers = /(toHaveLength|toBeDefined|toBeNull)/; | ||
if (matcherNode.name === "toHaveLength" && matcherArguments[0].value > 1) { | ||
return; | ||
} | ||
function check({ | ||
queryNode, | ||
matcherNode, | ||
matcherArguments, | ||
negatedMatcher, | ||
expect | ||
}) { | ||
if (!queryNode || !queryNode.name && !queryNode.property) return; // toHaveLength() is only invalid with 0 or 1 | ||
if (_queries.queries.includes(query)) { | ||
context.report({ | ||
node: matcherNode, | ||
messageId: "use-document", | ||
loc: matcherNode.loc, | ||
if (matcherNode.name === "toHaveLength" && matcherArguments[0].value > 1) { | ||
return; | ||
} | ||
fix(fixer) { | ||
const operations = []; // Flip the .not if neccessary | ||
const query = queryNode.name || queryNode.property.name; | ||
if (isAntonymMatcher(matcherNode, matcherArguments)) { | ||
if (negatedMatcher) { | ||
operations.push(fixer.removeRange([matcherNode.range[0] - 5, matcherNode.range[0] - 1])); | ||
} else { | ||
operations.push(fixer.insertTextBefore(matcherNode, "not.")); | ||
} | ||
} // Replace the actual matcher | ||
if (_queries.queries.includes(query)) { | ||
context.report({ | ||
node: matcherNode, | ||
messageId: "use-document", | ||
loc: matcherNode.loc, | ||
fix(fixer) { | ||
const operations = []; // Remove any arguments in the matcher | ||
operations.push(fixer.replaceText(matcherNode, "toBeInTheDocument")); // Remove any arguments in the matcher | ||
for (const argument of Array.from(matcherArguments)) { | ||
operations.push(fixer.remove(argument)); | ||
} // Flip the .not if necessary | ||
for (const argument of matcherArguments) { | ||
operations.push(fixer.remove(argument)); | ||
if (isAntonymMatcher(matcherNode, matcherArguments)) { | ||
if (negatedMatcher) { | ||
operations.push(fixer.replaceTextRange([expect.range[1], matcherNode.range[1]], ".toBeInTheDocument")); | ||
return operations; | ||
} else { | ||
operations.push(fixer.insertTextBefore(matcherNode, "not.")); | ||
} | ||
} // Replace the actual matcher | ||
operations.push(fixer.replaceText(matcherNode, "toBeInTheDocument")); | ||
return operations; | ||
} | ||
return operations; | ||
}); | ||
} | ||
} | ||
function getQueryNodeFromAssignment(identifierName) { | ||
const variable = context.getScope().set.get(identifierName); | ||
const init = variable.defs[0].node.init; | ||
let queryNode; | ||
if (init) { | ||
// let foo = screen.<query>(); | ||
queryNode = init.type === "AwaitExpression" ? init.argument.callee.property : init.callee.property || init.callee; | ||
} else { | ||
// let foo; | ||
// foo = screen.<query>(); | ||
const assignmentRef = variable.references.reverse().find(ref => !!ref.writeExpr); | ||
if (!assignmentRef) { | ||
return; | ||
} | ||
}); | ||
queryNode = assignmentRef.writeExpr.type === "AwaitExpression" ? assignmentRef.writeExpr.argument.callee : assignmentRef.writeExpr.type === "CallExpression" ? assignmentRef.writeExpr.callee : assignmentRef.writeExpr; | ||
} | ||
return queryNode; | ||
} | ||
} | ||
const create = context => { | ||
const alternativeMatchers = /(toHaveLength|toBeDefined|toBeNull)/; | ||
return { | ||
// Grabbing expect(<query>).not.<matcher> | ||
[`CallExpression[callee.object.object.callee.name='expect'][callee.object.property.name='not'][callee.property.name=${alternativeMatchers}]`](node) { | ||
const queryNode = node.callee.object.object.arguments[0].callee; | ||
// expect(<query>).not.<matcher> | ||
[`CallExpression[callee.object.object.callee.name='expect'][callee.object.property.name='not'][callee.property.name=${alternativeMatchers}], CallExpression[callee.object.callee.name='expect'][callee.object.property.name='not'][callee.object.arguments.0.argument.callee.name=${alternativeMatchers}]`](node) { | ||
const arg = node.callee.object.object.arguments[0]; | ||
const queryNode = arg.type === "AwaitExpression" ? arg.argument.callee : arg.callee; | ||
const matcherNode = node.callee.property; | ||
const matcherArguments = node.arguments; | ||
check(context, { | ||
const expect = node.callee.object.object; | ||
check({ | ||
negatedMatcher: true, | ||
queryNode, | ||
matcherNode, | ||
matcherArguments, | ||
expect | ||
}); | ||
}, | ||
// // const foo = <query> expect(foo).not.<matcher> | ||
[`MemberExpression[object.object.callee.name=expect][object.property.name=not][property.name=${alternativeMatchers}][object.object.arguments.0.type=Identifier]`](node) { | ||
const queryNode = getQueryNodeFromAssignment(node.object.object.arguments[0].name); | ||
const matcherNode = node.property; | ||
const matcherArguments = node.parent.arguments; | ||
const expect = node.object.object; | ||
check({ | ||
negatedMatcher: true, | ||
queryNode, | ||
matcherNode, | ||
matcherArguments, | ||
expect | ||
}); | ||
}, | ||
// const foo = <query> expect(foo).<matcher> | ||
[`MemberExpression[object.callee.name=expect][property.name=${alternativeMatchers}][object.arguments.0.type=Identifier]`](node) { | ||
const queryNode = getQueryNodeFromAssignment(node.object.arguments[0].name); | ||
const matcherNode = node.property; | ||
const matcherArguments = node.parent.arguments; | ||
check({ | ||
negatedMatcher: false, | ||
queryNode, | ||
matcherNode, | ||
matcherArguments | ||
@@ -93,8 +152,10 @@ }); | ||
// Grabbing expect(<query>).<matcher> | ||
[`CallExpression[callee.object.callee.name='expect'][callee.property.name=${alternativeMatchers}]`](node) { | ||
const queryNode = node.callee.object.arguments[0].callee; | ||
// expect(await <query>).<matcher> | ||
// expect(<query>).<matcher> | ||
[`CallExpression[callee.object.callee.name='expect'][callee.property.name=${alternativeMatchers}], CallExpression[callee.object.callee.name='expect'][callee.object.arguments.0.argument.callee.name=${alternativeMatchers}]`](node) { | ||
const arg = node.callee.object.arguments[0]; | ||
const queryNode = arg.type === "AwaitExpression" ? arg.argument.callee : arg.callee; | ||
const matcherNode = node.callee.property; | ||
const matcherArguments = node.arguments; | ||
check(context, { | ||
check({ | ||
negatedMatcher: false, | ||
@@ -101,0 +162,0 @@ queryNode, |
{ | ||
"name": "eslint-plugin-jest-dom", | ||
"version": "3.3.0", | ||
"version": "3.4.0", | ||
"description": "ESLint plugin to follow best practices and anticipate common mistakes when writing tests with jest-dom", | ||
@@ -37,2 +37,3 @@ "main": "dist/index.js", | ||
"test": "kcd-scripts test", | ||
"test:smoke": "eslint-remote-tester --config ./smoke-test/eslint-remote-tester.config.js", | ||
"test:update": "npm test -- --updateSnapshot --coverage", | ||
@@ -47,5 +48,8 @@ "validate": "kcd-scripts validate" | ||
"devDependencies": { | ||
"@typescript-eslint/parser": "^4.8.2", | ||
"eslint": "7.14", | ||
"eslint-remote-tester": "^0.3.3", | ||
"jest-extended": "^0.11.5", | ||
"kcd-scripts": "6.5.1" | ||
"kcd-scripts": "6.5.1", | ||
"typescript": "^4.1.2" | ||
}, | ||
@@ -60,3 +64,4 @@ "peerDependencies": { | ||
"max-lines-per-function": "off", | ||
"testing-library/no-dom-import": "off" | ||
"testing-library/no-dom-import": "off", | ||
"consistent-return": "off" | ||
} | ||
@@ -67,3 +72,5 @@ }, | ||
"coverage", | ||
"dist" | ||
"dist", | ||
".cache-eslint-remote-tester", | ||
"eslint-remote-tester-results" | ||
], | ||
@@ -70,0 +77,0 @@ "engines": { |
@@ -103,13 +103,15 @@ <div align="center"> | ||
<!-- __BEGIN AUTOGENERATED TABLE__ --> | ||
Name | π | π§ | Description | ||
----- | ----- | ----- | ----- | ||
[prefer-checked](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-checked.md) | π | π§ | prefer toBeChecked over checking attributes | ||
[prefer-empty](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-empty.md) | π | π§ | Prefer toBeEmpty over checking innerHTML | ||
[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 | ||
[prefer-focus](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-focus.md) | π | π§ | prefer toHaveFocus over checking document.activeElement | ||
[prefer-in-document](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-in-document.md) | | π§ | Prefer .toBeInTheDocument() in favor of checking the length of the result using .toHaveLength(1) | ||
[prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | π | π§ | prefer toBeRequired over checking properties | ||
[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 | ||
[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 | ||
[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 | ||
| Name | π | π§ | Description | | ||
| ---------------------------------------------------------------------------------------------------------------------------------------------- | --- | --- | ------------------------------------------------------------------------------------------------ | | ||
| [prefer-checked](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-checked.md) | π | π§ | prefer toBeChecked over checking attributes | | ||
| [prefer-empty](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-empty.md) | π | π§ | Prefer toBeEmpty over checking innerHTML | | ||
| [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 | | ||
| [prefer-focus](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-focus.md) | π | π§ | prefer toHaveFocus over checking document.activeElement | | ||
| [prefer-in-document](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-in-document.md) | | π§ | Prefer .toBeInTheDocument() in favor of checking the length of the result using .toHaveLength(1) | | ||
| [prefer-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | π | π§ | prefer toBeRequired over checking properties | | ||
| [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 | | ||
| [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 | | ||
| [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 | | ||
<!-- __END AUTOGENERATED TABLE__ --> | ||
@@ -156,3 +158,3 @@ | ||
<td align="center"><a href="https://mario.dev"><img src="https://avatars1.githubusercontent.com/u/2677072?v=4" width="100px;" alt=""/><br /><sub><b>Mario BeltrΓ‘n AlarcΓ³n</b></sub></a><br /><a href="https://github.com/testing-library/eslint-plugin-jest-dom/commits?author=Belco90" title="Documentation">π</a></td> | ||
<td align="center"><a href="https://codepen.io/ariperkkio/"><img src="https://avatars2.githubusercontent.com/u/14806298?v=4" width="100px;" alt=""/><br /><sub><b>Ari PerkkiΓΆ</b></sub></a><br /><a href="https://github.com/testing-library/eslint-plugin-jest-dom/issues?q=author%3AAriPerkkio" title="Bug reports">π</a></td> | ||
<td align="center"><a href="https://codepen.io/ariperkkio/"><img src="https://avatars2.githubusercontent.com/u/14806298?v=4" width="100px;" alt=""/><br /><sub><b>Ari PerkkiΓΆ</b></sub></a><br /><a href="https://github.com/testing-library/eslint-plugin-jest-dom/issues?q=author%3AAriPerkkio" title="Bug reports">π</a> <a href="https://github.com/testing-library/eslint-plugin-jest-dom/commits?author=AriPerkkio" title="Code">π»</a> <a href="https://github.com/testing-library/eslint-plugin-jest-dom/commits?author=AriPerkkio" title="Tests">β οΈ</a></td> | ||
<td align="center"><a href="http://www.antn.se"><img src="https://avatars0.githubusercontent.com/u/785676?v=4" width="100px;" alt=""/><br /><sub><b>Anton Niklasson</b></sub></a><br /><a href="https://github.com/testing-library/eslint-plugin-jest-dom/commits?author=AntonNiklasson" title="Code">π»</a> <a href="https://github.com/testing-library/eslint-plugin-jest-dom/commits?author=AntonNiklasson" title="Tests">β οΈ</a> <a href="https://github.com/testing-library/eslint-plugin-jest-dom/commits?author=AntonNiklasson" title="Documentation">π</a></td> | ||
@@ -164,3 +166,2 @@ </tr> | ||
<!-- prettier-ignore-end --> | ||
<!-- ALL-CONTRIBUTORS-LIST:END --> | ||
@@ -167,0 +168,0 @@ |
55367
800
196
6