Skip to content
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

Move rules settings to ESLint shared config: refactor await-async-query and no-await-sync-query #260

Merged
merged 27 commits into from
Nov 28, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
cb8c50c
refactor(no-await-sync-query): use custom rule creator
Belco90 Nov 11, 2020
501f604
refactor(no-await-sync-query): improve error message
Belco90 Nov 11, 2020
4279c72
test(no-await-sync-query): check error location in invalid cases
Belco90 Nov 11, 2020
19fbcf3
refactor(no-await-sync-query): catch sync queries with detection helper
Belco90 Nov 11, 2020
1364182
test(no-await-sync-query): use more realistic scenarios
Belco90 Nov 11, 2020
79973d5
test(no-await-sync-query): add more cases for custom queries and sett…
Belco90 Nov 11, 2020
9447804
refactor(await-async-query): use custom rule creator
Belco90 Nov 14, 2020
2cdafb7
refactor(await-async-query): improve error message
Belco90 Nov 14, 2020
b4f506d
feat: new detection helpers for findBy queries
Belco90 Nov 15, 2020
6ac7555
refactor(await-async-query): detection helpers + aggressive reporting
Belco90 Nov 23, 2020
ee1b791
test(await-async-query): add cases for custom queries
Belco90 Nov 23, 2020
0260208
test(await-async-query): add more cases for custom queries
Belco90 Nov 23, 2020
12d5c67
test(await-async-query): check errors locations
Belco90 Nov 23, 2020
10af260
test(await-async-query): mix built-in and custom queries
Belco90 Nov 23, 2020
c13aea1
test(await-async-query): non-matching query case
Belco90 Nov 23, 2020
743f29d
feat(await-async-query): report query wrappers
Belco90 Nov 23, 2020
ae51b6a
refactor(await-async-query): extract ast utils for functions
Belco90 Nov 24, 2020
30caeea
test(await-async-query): cases for arrow functions
Belco90 Nov 24, 2020
0312ec9
refactor(await-async-query): extract ast util for promise handled
Belco90 Nov 24, 2020
e0a8e42
test(await-async-query): increase coverage
Belco90 Nov 24, 2020
11e1b1f
refactor(await-async-query): rename isPromiseResolved to hasChainedThen
Belco90 Nov 24, 2020
03131e0
docs(await-async-query): update rule description and examples
Belco90 Nov 24, 2020
2cce123
docs(await-async-query): minor improvements
Belco90 Nov 27, 2020
2d5438a
refactor: minor type fix
Belco90 Nov 28, 2020
e8b93ef
docs(await-async-query): more fixes
Belco90 Nov 28, 2020
7fa901d
docs(await-async-query): wrong return type
Belco90 Nov 28, 2020
bce0486
refactor(await-async-query): check regex more efficiently
Belco90 Nov 28, 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ To enable this configuration use the `extends` property in your

| Rule | Description | Configurations | Fixable |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ------------------ |
| [await-async-query](docs/rules/await-async-query.md) | Enforce async queries to have proper `await` | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | |
| [await-async-query](docs/rules/await-async-query.md) | Enforce promises from async queries to be handled | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | |
| [await-async-utils](docs/rules/await-async-utils.md) | Enforce async utils to be awaited properly | ![dom-badge][] ![angular-badge][] ![react-badge][] ![vue-badge][] | |
| [await-fire-event](docs/rules/await-fire-event.md) | Enforce async fire event methods to be awaited | ![vue-badge][] | |
| [consistent-data-testid](docs/rules/consistent-data-testid.md) | Ensure `data-testid` values match a provided regex. | | |
Expand Down
89 changes: 50 additions & 39 deletions docs/rules/await-async-query.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,86 @@
# Enforce async queries to have proper `await` (await-async-query)
# Enforce promises from async queries to be handled (await-async-query)

Ensure that promises returned by async queries are handled properly.

## Rule Details

Some of the queries variants that Testing Library provides are
Some queries variants that Testing Library provides are
asynchronous as they return a promise which resolves when elements are
found. Those queries variants are:

- `findBy*`
- `findAllBy*`

This rule aims to prevent users from forgetting to await the returned
This rule aims to prevent users from forgetting to handle the returned
promise from those async queries to be fulfilled, which could lead to
errors in the tests. The promises can be handled by using either `await`
operator or `then` method.
errors in the tests. The promise will be considered as handled when:

- using `await` operator
- chaining `then` method
- chaining `resolves` or `rejects` from jest
- is returned from a function (in this case, that particular function will be analyzed by this rule too)
Belco90 marked this conversation as resolved.
Show resolved Hide resolved

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

```js
const foo = () => {
// ...
const rows = findAllByRole('row');
// ...
};

const bar = () => {
// ...
findByText('submit');
// ...
};

const baz = () => {
// ...
screen.findAllByPlaceholderText('name');
// ...
};
// async query without handling promise
const rows = findAllByRole('row');

findByIcon('search');

screen.findAllByPlaceholderText('name');
```

```js
// promise from async query returned within wrapper function without being handled
const findMyButton = () => findByText('my button');

const someButton = findMyButton(); // promise unhandled here
```

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

```js
// `await` operator is correct
const foo = async () => {
// ...
const rows = await findAllByRole('row');
// ...
};
const rows = await findAllByRole('row');

await screen.findAllByPlaceholderText('name');

const promise = findByIcon('search');
const element = await promise;
```

```js
// `then` method is correct
const bar = () => {
// ...
findByText('submit').then(() => {
// ...
});
};

const baz = () => {
// ...
await screen.findAllByPlaceholderText('name');
// ...
};
findByText('submit').then(() => {});

const promise = findByRole('button');
promise.then(() => {});
```

```js
// return the promise within a function is correct too!
const findMyButton = () => findByText('my button');
```

```js
// promise from async query returned within wrapper function being handled
const findMyButton = () => findByText('my button');

const someButton = await findMyButton();
```

```js
// using a resolves/rejects matcher is also correct
expect(findByTestId('alert')).resolves.toBe('Success');
expect(findByTestId('alert')).rejects.toBe('Error');
```

```js
// sync queries don't need to handle any promise
const element = getByRole('role');
```

## Further Reading

- [Async queries variants](https://testing-library.com/docs/dom-testing-library/api-queries#findby)
Expand Down
18 changes: 18 additions & 0 deletions lib/detect-testing-library-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export type DetectionHelpers = {
isValidFilename: () => boolean;
isGetByQuery: (node: TSESTree.Identifier) => boolean;
isQueryByQuery: (node: TSESTree.Identifier) => boolean;
isFindByQuery: (node: TSESTree.Identifier) => boolean;
isSyncQuery: (node: TSESTree.Identifier) => boolean;
isAsyncQuery: (node: TSESTree.Identifier) => boolean;
isPresenceAssert: (node: TSESTree.MemberExpression) => boolean;
isAbsenceAssert: (node: TSESTree.MemberExpression) => boolean;
canReportErrors: () => boolean;
Expand Down Expand Up @@ -145,13 +147,27 @@ export function detectTestingLibraryUtils<
return !!node.name.match(/^query(All)?By.+$/);
};

/**
* Determines whether a given node is `findBy*` or `findAllBy*` query variant or not.
*/
const isFindByQuery: DetectionHelpers['isFindByQuery'] = (node) => {
return !!node.name.match(/^find(All)?By.+$/);
Belco90 marked this conversation as resolved.
Show resolved Hide resolved
};

/**
* Determines whether a given node is sync query or not.
*/
const isSyncQuery: DetectionHelpers['isSyncQuery'] = (node) => {
return isGetByQuery(node) || isQueryByQuery(node);
};

/**
* Determines whether a given node is async query or not.
*/
const isAsyncQuery: DetectionHelpers['isAsyncQuery'] = (node) => {
Copy link
Member Author

Choose a reason for hiding this comment

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

Final detection helpers to complete requirement 4: aggressive query reporting

return isFindByQuery(node);
};

/**
* Determines whether a given MemberExpression node is a presence assert
*
Expand Down Expand Up @@ -293,7 +309,9 @@ export function detectTestingLibraryUtils<
isValidFilename,
isGetByQuery,
isQueryByQuery,
isFindByQuery,
isSyncQuery,
isAsyncQuery,
isPresenceAssert,
isAbsenceAssert,
canReportErrors,
Expand Down
Loading