-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Ben Monro
committed
Oct 27, 2019
0 parents
commit 0823052
Showing
18 changed files
with
637 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
coverage/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"parserOptions": { | ||
"ecmaVersion": 2018 | ||
}, | ||
"env": { | ||
"commonjs": true, | ||
"es6": true, | ||
"node": true | ||
// "jest/globals": true | ||
}, | ||
"plugins": [ | ||
"eslint-plugin", | ||
"prettier" | ||
], | ||
"extends": [ | ||
"plugin:eslint-plugin/recommended" | ||
], | ||
"rules": { | ||
"prettier/prettier": "error", | ||
"no-var": "error" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
coverage | ||
yarn.lock | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"trailingComma": "es5", | ||
"singleQuote": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# eslint-plugin-jest-dom | ||
|
||
lint rules for use with jest-dom | ||
|
||
## Installation | ||
|
||
You'll first need to install [ESLint](http://eslint.org): | ||
|
||
``` | ||
$ npm i eslint --save-dev | ||
``` | ||
|
||
Next, install `eslint-plugin-jest-dom`: | ||
|
||
``` | ||
$ npm install eslint-plugin-jest-dom --save-dev | ||
``` | ||
|
||
**Note:** If you installed ESLint globally (using the `-g` flag) then you must also install `eslint-plugin-jest-dom` globally. | ||
|
||
## Usage | ||
|
||
Add `jest-dom` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix: | ||
|
||
```json | ||
{ | ||
"plugins": [ | ||
"jest-dom" | ||
] | ||
} | ||
``` | ||
|
||
|
||
Then configure the rules you want to use under the rules section. | ||
|
||
```json | ||
{ | ||
"rules": { | ||
"jest-dom/prefer-checked": "error", | ||
"jest-dom/prefer-enabled-disabled": "error", | ||
"jest-dom/prefer-required": "error" | ||
} | ||
} | ||
``` | ||
|
||
## Supported Rules | ||
|
||
✔️ indicates that a rule is recommended for all users. | ||
|
||
🛠 indicates that a rule is fixable. | ||
|
||
<!-- __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-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-required](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/prefer-required.md) | ✔️ | 🛠 | prefer toBeRequired over checking properties | ||
<!-- __END AUTOGENERATED TABLE__ --> | ||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
'use strict'; | ||
|
||
const fs = require('fs'); | ||
const path = require('path'); | ||
const rules = require('..').rules; | ||
|
||
const README_LOCATION = path.resolve(__dirname, '..', 'README.md'); | ||
const BEGIN_TABLE_MARKER = '<!-- __BEGIN AUTOGENERATED TABLE__ -->\n'; | ||
const END_TABLE_MARKER = '\n<!-- __END AUTOGENERATED TABLE__ -->'; | ||
|
||
const expectedTableLines = Object.keys(rules) | ||
.sort() | ||
.reduce( | ||
(lines, ruleId) => { | ||
const rule = rules[ruleId]; | ||
|
||
lines.push( | ||
[ | ||
`[${ruleId}](https://github.com/testing-library/eslint-plugin-jest-dom/blob/master/docs/rules/${ruleId}.md)`, | ||
rule.meta.docs.recommended ? '✔️' : '', | ||
rule.meta.fixable ? '🛠' : '', | ||
rule.meta.docs.description, | ||
].join(' | ') | ||
); | ||
|
||
return lines; | ||
}, | ||
['Name | ✔️ | 🛠 | Description', '----- | ----- | ----- | -----'] | ||
) | ||
.join('\n'); | ||
|
||
const readmeContents = fs.readFileSync(README_LOCATION, 'utf8'); | ||
|
||
if (!readmeContents.includes(BEGIN_TABLE_MARKER)) { | ||
throw new Error( | ||
`Could not find '${BEGIN_TABLE_MARKER}' marker in README.md.` | ||
); | ||
} | ||
|
||
if (!readmeContents.includes(END_TABLE_MARKER)) { | ||
throw new Error(`Could not find '${END_TABLE_MARKER}' marker in README.md.`); | ||
} | ||
|
||
const linesStartIndex = | ||
readmeContents.indexOf(BEGIN_TABLE_MARKER) + BEGIN_TABLE_MARKER.length; | ||
const linesEndIndex = readmeContents.indexOf(END_TABLE_MARKER); | ||
|
||
const updatedReadmeContents = | ||
readmeContents.slice(0, linesStartIndex) + | ||
expectedTableLines + | ||
readmeContents.slice(linesEndIndex); | ||
|
||
if (module.parent) { | ||
module.exports = updatedReadmeContents; | ||
} else { | ||
fs.writeFileSync(README_LOCATION, updatedReadmeContents); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# prefer toBeDisabled() or toBeEnabled() over toHaveProperty('disabled', true|false) (prefer-enabled-disabled) | ||
|
||
## Rule Details | ||
|
||
This rule aims to prevent false positives and improve readability and should only be used with the `@testing-library/jest-dom` package. See below for examples of those potential issues and why this rule is recommended. The rule is autofixable and will replace any instances of `.toHaveProperty()` or `.toHaveAttribute()` with `.toBeEnabled()` or `toBeDisabled()` as appropriate. | ||
|
||
In addition, to avoid double negatives and confusing syntax, `expect(element).not.toBeDisabled()` is also reported and auto-fixed to `expect(element).toBeEnabled()` and vice versa. | ||
|
||
### False positives | ||
|
||
Consider these 2 snippets: | ||
|
||
```js | ||
const { getByRole } = render(<input type="checkbox" disabled />); | ||
const element = getByRole('checkbox'); | ||
expect(element).toHaveProperty('disabled'); // passes | ||
|
||
const { getByRole } = render(<input type="checkbox" />); | ||
const element = getByRole('checkbox'); | ||
expect(element).toHaveProperty('disabled'); // also passes 😱 | ||
``` | ||
|
||
### Readability | ||
|
||
Consider the following snippets: | ||
|
||
```js | ||
const { getByRole } = render(<input type="checkbox" />); | ||
const element = getByRole('checkbox'); | ||
|
||
expect(element).toHaveAttribute('disabled', false); // fails | ||
expect(element).toHaveAttribute('disabled', ''); // fails | ||
expect(element).not.toHaveAttribute('disabled', ''); // passes | ||
|
||
expect(element).not.toHaveAttribute('disabled', true); // passes. | ||
expect(element).not.toHaveAttribute('disabled', false); // also passes. | ||
``` | ||
|
||
As you can see, using `toHaveAttribute` in this case is confusing, unintuitive and can even lead to false positive tests. | ||
|
||
Examples of **incorrect** code for this rule: | ||
|
||
```js | ||
expect(element).toHaveProperty('disabled', true); | ||
expect(element).toHaveAttribute('disabled', false); | ||
|
||
expect(element).toHaveAttribute('disabled'); | ||
expect(element).not.toHaveProperty('disabled'); | ||
|
||
expect(element).not.toBeDisabled(); | ||
expect(element).not.toBeEnabled(); | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```js | ||
expect(element).toBeEnabled(); | ||
|
||
expect(element).toBeDisabled(); | ||
|
||
expect(element).toHaveProperty('checked', true); | ||
|
||
expect(element).toHaveAttribute('checked'); | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
Don't use this rule if you: | ||
|
||
- don't use `jest-dom` | ||
- want to allow `.toHaveProperty('disabled', true|false);` | ||
|
||
## Further reading | ||
|
||
- [toBeDisabled](https://github.com/testing-library/jest-dom#tobedisabled) | ||
- [toBeEnabled](https://github.com/testing-library/jest-dom#tobeenabled) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module.exports = { | ||
testMatch: ['**/tests/**/*.js'], | ||
collectCoverage: true, | ||
coverageThreshold: { | ||
global: { | ||
branches: 96.55, | ||
functions: 100, | ||
lines: 98.97, | ||
statements: 0, | ||
}, | ||
}, | ||
testPathIgnorePatterns: ['<rootDir>/tests/fixtures/'], | ||
collectCoverageFrom: ['lib/**/*.js', '!**/node_modules/**'], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
module.exports = ({ preferred, negatedPreferred, attributes }) => context => { | ||
function getCorrectFunctionFor(node, negated = false) { | ||
return (node.arguments.length === 1 || | ||
node.arguments[1].value === true || | ||
node.arguments[1].value === '') && | ||
!negated | ||
? preferred | ||
: negatedPreferred; | ||
} | ||
|
||
const isBannedArg = node => | ||
attributes.some(attr => attr === node.arguments[0].value); | ||
|
||
return { | ||
[`CallExpression[callee.property.name=/${preferred}|${negatedPreferred}/][callee.object.property.name='not'][callee.object.object.callee.name='expect']`]( | ||
node | ||
) { | ||
if (negatedPreferred.startsWith('toBe')) { | ||
const incorrectFunction = node.callee.property.name; | ||
|
||
const correctFunction = | ||
incorrectFunction === preferred ? negatedPreferred : preferred; | ||
context.report({ | ||
message: `Use ${correctFunction}() instead of not.${incorrectFunction}()`, | ||
node, | ||
fix(fixer) { | ||
return fixer.replaceTextRange( | ||
[node.callee.object.property.start, node.end], | ||
`${correctFunction}()` | ||
); | ||
}, | ||
}); | ||
} | ||
}, | ||
"CallExpression[callee.property.name=/toHaveProperty|toHaveAttribute/][callee.object.property.name='not'][callee.object.object.callee.name='expect']"( | ||
node | ||
) { | ||
const arg = node.arguments[0].value; | ||
if (isBannedArg(node)) { | ||
const correctFunction = getCorrectFunctionFor(node, true); | ||
|
||
const incorrectFunction = node.callee.property.name; | ||
context.report({ | ||
message: `Use ${correctFunction}() instead of not.${incorrectFunction}('${arg}')`, | ||
node, | ||
fix(fixer) { | ||
return fixer.replaceTextRange( | ||
[node.callee.object.property.start, node.end], | ||
`${correctFunction}()` | ||
); | ||
}, | ||
}); | ||
} | ||
}, | ||
"CallExpression[callee.object.callee.name='expect'][callee.property.name=/toHaveProperty|toHaveAttribute/]"( | ||
node | ||
) { | ||
if (isBannedArg(node)) { | ||
const correctFunction = getCorrectFunctionFor(node); | ||
|
||
const incorrectFunction = node.callee.property.name; | ||
|
||
const message = `Use ${correctFunction}() instead of ${incorrectFunction}(${node.arguments | ||
.map(({ raw }) => raw) | ||
.join(', ')})`; | ||
context.report({ | ||
node: node.callee.property, | ||
message, | ||
fix(fixer) { | ||
return [ | ||
fixer.replaceTextRange( | ||
[node.callee.property.start, node.end], | ||
`${correctFunction}()` | ||
), | ||
]; | ||
}, | ||
}); | ||
} | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* @fileoverview lint rules for use with jest-dom | ||
* @author Ben Monro | ||
*/ | ||
'use strict'; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
let requireIndex = require('requireindex'); | ||
|
||
//------------------------------------------------------------------------------ | ||
// Plugin Definition | ||
//------------------------------------------------------------------------------ | ||
|
||
// import all rules in lib/rules | ||
module.exports.rules = requireIndex(__dirname + '/rules'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/** | ||
* @fileoverview prefer toBeDisabled or toBeEnabled over attribute checks | ||
* @author Ben Monro | ||
*/ | ||
'use strict'; | ||
|
||
const createBannedAttributeRule = require('../createBannedAttributeRule'); | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: | ||
'prefer toBeChecked over checking attributes', | ||
category: 'jest-dom', | ||
recommended: true, | ||
url: 'prefer-checked', | ||
}, | ||
fixable: 'code', | ||
}, | ||
|
||
create: createBannedAttributeRule({ | ||
preferred: 'toBeChecked', | ||
negatedPreferred: 'not.toBeChecked', | ||
attributes: ['checked', 'aria-checked'], | ||
}), | ||
}; |
Oops, something went wrong.