Skip to content

feat(prefer-wait-for): new rule prefer-wait-for #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Mar 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d8a6818
feat(prefer-wait-for): new rule prefer-wait-for
Belco90 Mar 14, 2020
3dc56de
docs(prefer-wait-for): pr fixes
Belco90 Mar 15, 2020
ea8fcce
test(prefer-wait-for): increase coverage
Belco90 Mar 15, 2020
fe39525
refactor(prefer-wait-for): use ternary
Belco90 Mar 15, 2020
550155f
docs(prefer-wait-for): PR small fixes
Belco90 Mar 16, 2020
d550a23
test(prefer-wait-for): include imports
Belco90 Mar 18, 2020
4e21af6
fix(prefer-wait-for): fist attempt to report related imports
Belco90 Mar 19, 2020
0c4ae1e
refactor(prefer-wait-for): merge wait reports under single func
Belco90 Mar 19, 2020
506f956
fix(prefer-wait-for): fix single imports
Belco90 Mar 19, 2020
8e2ba9a
fix(prefer-wait-for): fix several imports
Belco90 Mar 19, 2020
e69fb42
fix(prefer-wait-for): guard against empty named imports
Belco90 Mar 19, 2020
938e907
fix(prefer-wait-for): fix more imports cases
Belco90 Mar 21, 2020
c5b413a
feat(prefer-wait-for): new rule prefer-wait-for
Belco90 Mar 14, 2020
df677fe
docs(prefer-wait-for): pr fixes
Belco90 Mar 15, 2020
0c698cd
test(prefer-wait-for): increase coverage
Belco90 Mar 15, 2020
a841ffe
refactor(prefer-wait-for): use ternary
Belco90 Mar 15, 2020
c2be2ec
docs(prefer-wait-for): PR small fixes
Belco90 Mar 16, 2020
b410020
test(prefer-wait-for): include imports
Belco90 Mar 18, 2020
41414a4
fix(prefer-wait-for): fist attempt to report related imports
Belco90 Mar 19, 2020
99dac28
refactor(prefer-wait-for): merge wait reports under single func
Belco90 Mar 19, 2020
12980e8
fix(prefer-wait-for): fix single imports
Belco90 Mar 19, 2020
623f88b
fix(prefer-wait-for): fix several imports
Belco90 Mar 19, 2020
82fa2df
fix(prefer-wait-for): guard against empty named imports
Belco90 Mar 19, 2020
03b352d
fix(prefer-wait-for): fix more imports cases
Belco90 Mar 21, 2020
67c1f5b
Merge remote-tracking branch 'origin/feature/rule-prefer-wait-for' in…
Belco90 Mar 21, 2020
158be04
Merge remote-tracking branch 'origin/v3' into feature/rule-prefer-wai…
Belco90 Mar 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ To enable this configuration use the `extends` property in your
| [no-manual-cleanup](docs/rules/no-manual-cleanup.md) | Disallow the use of `cleanup` | | |
| [no-wait-for-empty-callback](docs/rules/no-wait-for-empty-callback.md) | Disallow empty callbacks for `waitFor` and `waitForElementToBeRemoved` | | |
| [prefer-explicit-assert](docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than just `getBy*` queries | | |
| [prefer-wait-for](docs/rules/prefer-wait-for.md) | Use `waitFor` instead of deprecated wait methods | | ![fixable-badge][] |

[build-badge]: https://img.shields.io/travis/testing-library/eslint-plugin-testing-library?style=flat-square
[build-url]: https://travis-ci.org/testing-library/eslint-plugin-testing-library
Expand Down
48 changes: 48 additions & 0 deletions docs/rules/prefer-wait-for.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Use `waitFor` instead of deprecated wait methods (prefer-wait-for)

`dom-testing-library` v7 released a new async util called `waitFor` which satisfies the use cases of `wait`, `waitForElement`, and `waitForDomChange` making them deprecated.

## Rule Details

This rule aims to use `waitFor` async util rather than previous deprecated ones.

Deprecated `wait` async utils are:

- `wait`
- `waitForElement`
- `waitForDomChange`

> This rule will auto fix deprecated async utils for you, including the necessary empty callback for `waitFor`. This means `wait();` will be replaced with `waitFor(() => {});`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯


Examples of **incorrect** code for this rule:

```js
const foo = async () => {
await wait();
await wait(() => {});
await waitForElement(() => {});
await waitForDomChange();
await waitForDomChange(mutationObserverOptions);
await waitForDomChange({ timeout: 100});
};
```

Examples of **correct** code for this rule:

```js
const foo = async () => {
// new waitFor method
await waitFor(() => {});

// previous waitForElementToBeRemoved is not deprecated
await waitForElementToBeRemoved(() => {});
};
```

## When Not To Use It

When using dom-testing-library (or any other Testing Library relying on dom-testing-library) prior to v7.

## Further Reading

- [dom-testing-library v7 release](https://github.com/testing-library/dom-testing-library/releases/tag/v7.0.0)
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const rules = {
'no-manual-cleanup': require('./rules/no-manual-cleanup'),
'no-wait-for-empty-callback': require('./rules/no-wait-for-empty-callback'),
'prefer-explicit-assert': require('./rules/prefer-explicit-assert'),
'prefer-wait-for': require('./rules/prefer-wait-for'),
};

const recommendedRules = {
Expand Down
120 changes: 120 additions & 0 deletions lib/rules/prefer-wait-for.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
'use strict';

const { getDocsUrl } = require('../utils');

const DEPRECATED_METHODS = ['wait', 'waitForElement', 'waitForDomChange'];

module.exports = {
meta: {
type: 'suggestion',
docs: {
description: 'Use `waitFor` instead of deprecated wait methods',
category: 'Best Practices',
recommended: false,
url: getDocsUrl('prefer-wait-for'),
},
messages: {
preferWaitForMethod:
'`{{ methodName }}` is deprecated in favour of `waitFor`',
preferWaitForImport: 'import `waitFor` instead of deprecated async utils',
},
fixable: 'code',
schema: [],
},

create: function(context) {
const importNodes = [];
const waitNodes = [];

const reportImport = node => {
context.report({
node: node,
messageId: 'preferWaitForImport',
fix(fixer) {
const excludedImports = [...DEPRECATED_METHODS, 'waitFor'];

// get all import names excluding all testing library `wait*` utils...
const newImports = node.specifiers
.filter(
specifier => !excludedImports.includes(specifier.imported.name)
)
.map(specifier => specifier.imported.name);

// ... and append `waitFor`
newImports.push('waitFor');

// build new node with new imports and previous source value
const newNode = `import { ${newImports.join(',')} } from '${
node.source.value
}';`;

return fixer.replaceText(node, newNode);
},
});
};

const reportWait = node => {
context.report({
node: node,
messageId: 'preferWaitForMethod',
data: {
methodName: node.name,
},
fix(fixer) {
const { parent } = node;
const [arg] = parent.arguments;
const fixers = [];

if (arg) {
// if method been fixed already had a callback
// then we just replace the method name.
fixers.push(fixer.replaceText(node, 'waitFor'));

if (node.name === 'waitForDomChange') {
// if method been fixed is `waitForDomChange`
// then the arg received was options object so we need to insert
// empty callback before.
fixers.push(fixer.insertTextBefore(arg, `() => {}, `));
}
} else {
// if wait method been fixed didn't have any callback
// then we replace the method name and include an empty callback.
fixers.push(fixer.replaceText(parent, 'waitFor(() => {})'));
}

return fixers;
},
});
};

return {
'ImportDeclaration[source.value=/testing-library/]'(node) {
const importedNames = node.specifiers
.map(specifier => specifier.imported && specifier.imported.name)
.filter(Boolean);

if (
importedNames.some(importedName =>
DEPRECATED_METHODS.includes(importedName)
)
) {
importNodes.push(node);
}
},
'CallExpression > Identifier[name=/^(wait|waitForElement|waitForDomChange)$/]'(
node
) {
waitNodes.push(node);
},
'Program:exit'() {
waitNodes.forEach(waitNode => {
reportWait(waitNode);
});

importNodes.forEach(importNode => {
reportImport(importNode);
});
},
};
},
};
Loading