Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ module.exports = [
| Name                            | Description | 💼 | ⚠️ | 🔧 |
| :------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------ | :-- |
| [await-async-events](docs/rules/await-async-events.md) | Enforce promises from async event methods are handled | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | 🔧 |
| [await-async-queries](docs/rules/await-async-queries.md) | Enforce promises from async queries to be handled | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | |
| [await-async-queries](docs/rules/await-async-queries.md) | Enforce promises from async queries to be handled | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | 🔧 |
| [await-async-utils](docs/rules/await-async-utils.md) | Enforce promises from async utils to be awaited properly | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | |
| [consistent-data-testid](docs/rules/consistent-data-testid.md) | Ensures consistent usage of `data-testid` | | | |
| [no-await-sync-events](docs/rules/no-await-sync-events.md) | Disallow unnecessary `await` for sync events | ![badge-angular][] ![badge-dom][] ![badge-react][] | | |
Expand Down
2 changes: 2 additions & 0 deletions docs/rules/await-async-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

💼 This rule is enabled in the following configs: `angular`, `dom`, `marko`, `react`, `svelte`, `vue`.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->

Ensure that promises returned by async queries are handled properly.
Expand Down
64 changes: 64 additions & 0 deletions lib/rules/await-async-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { ASTUtils } from '@typescript-eslint/utils';
import { createTestingLibraryRule } from '../create-testing-library-rule';
import {
findClosestCallExpressionNode,
findClosestFunctionExpressionNode,
getDeepestIdentifierNode,
getFunctionName,
getInnermostReturningFunction,
getVariableReferences,
isMemberExpression,
isPromiseHandled,
} from '../node-utils';

Expand Down Expand Up @@ -37,6 +39,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
asyncQueryWrapper:
'promise returned from `{{ name }}` wrapper over async query must be handled',
},
fixable: 'code',
schema: [],
},
defaultOptions: [],
Expand Down Expand Up @@ -85,6 +88,18 @@ export default createTestingLibraryRule<Options, MessageIds>({
node: identifierNode,
messageId: 'awaitAsyncQuery',
data: { name: identifierNode.name },
fix: (fixer) => {
if (
isMemberExpression(identifierNode.parent) &&
ASTUtils.isIdentifier(identifierNode.parent.object)
) {
return fixer.insertTextBefore(
identifierNode.parent,
'await '
);
}
return fixer.insertTextBefore(identifierNode, 'await ');
},
});
return;
}
Expand All @@ -102,6 +117,10 @@ export default createTestingLibraryRule<Options, MessageIds>({
node: identifierNode,
messageId: 'awaitAsyncQuery',
data: { name: identifierNode.name },
fix: (fixer) =>
references.map((ref) =>
fixer.insertTextBefore(ref.identifier, 'await ')
),
});
return;
}
Expand All @@ -115,6 +134,51 @@ export default createTestingLibraryRule<Options, MessageIds>({
node: identifierNode,
messageId: 'asyncQueryWrapper',
data: { name: identifierNode.name },
fix: (fixer) => {
const functionExpression =
findClosestFunctionExpressionNode(node);

if (!functionExpression) return null;

let IdentifierNodeFixer;
if (isMemberExpression(identifierNode.parent)) {
/**
* If the wrapper is a property of an object,
* add 'await' before the object, e.g.:
* const obj = { wrapper: () => screen.findByText(/foo/i) };
* await obj.wrapper();
*/
IdentifierNodeFixer = fixer.insertTextBefore(
identifierNode.parent,
'await '
);
} else {
/**
* Add 'await' before the wrapper function, e.g.:
* const wrapper = () => screen.findByText(/foo/i);
* await wrapper();
*/
IdentifierNodeFixer = fixer.insertTextBefore(
identifierNode,
'await '
);
}

if (functionExpression.async) {
return IdentifierNodeFixer;
} else {
/**
* Mutate the actual node so if other nodes exist in this
* function expression body they don't also try to fix it.
*/
functionExpression.async = true;

return [
IdentifierNodeFixer,
fixer.insertTextBefore(functionExpression, 'async '),
];
}
},
});
}
},
Expand Down
Loading