Skip to content

Commit 172a5ac

Browse files
authored
feat(prefer-explicit-assert): add an option to toggle the matching of findBy queries (#452)
A recent patch implemented matching findBy* queries by the prefer-explicit-assert rule. This patch makes it possible to disable it in cases where it's too distracting. Fixes #449
1 parent 280fdcd commit 172a5ac

File tree

3 files changed

+62
-36
lines changed

3 files changed

+62
-36
lines changed

docs/rules/prefer-explicit-assert.md

+22-17
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ elements in their tests rather than just use `getBy*` queries and expect
1313
it doesn't throw an error so it's easier to understand what's the
1414
expected behavior within the test.
1515

16-
Examples of **incorrect** code for this rule:
16+
Examples of **incorrect** code for this rule with the default configuration:
1717

1818
```js
1919
// just calling `getBy*` query expecting not to throw an error as an
@@ -23,9 +23,13 @@ getByText('foo');
2323

2424
const utils = render(<Component />);
2525
utils.getByText('foo');
26+
27+
// This is an incorrect code when `includeFindQueries` is `true`, which is the
28+
// default. Set it to `false` to shut off all warnings about find* queries.
29+
await findByText('foo');
2630
```
2731

28-
Examples of **correct** code for this rule:
32+
Examples of **correct** code for this rule with the default configuration:
2933

3034
```js
3135
// wrapping the get query within a `expect` and use some matcher for
@@ -43,25 +47,26 @@ expect(queryByText('foo')).toBeInTheDocument();
4347
await waitFor(() => getByText('foo'));
4448
fireEvent.click(getByText('bar'));
4549
const quxElement = getByText('qux');
50+
51+
expect(await findbyText('foo')).toBeTruthy();
52+
const myButton = await screen.findByRole('button', { name: /Accept/ });
4653
```
4754

4855
## Options
4956

50-
This rule has one option:
51-
52-
- `assertion`: this string allows defining the preferred assertion to use
53-
with `getBy*` queries. By default, any assertion is valid (`toBeTruthy`,
54-
`toBeDefined`, etc.). However, they all assert slightly different things.
55-
This option ensures all `getBy*` assertions are consistent and use the same
56-
assertion. This rule only allows defining a presence matcher
57-
(`toBeInTheDocument`, `toBeTruthy`, or `toBeDefined`), but checks for both
58-
presence and absence matchers (`not.toBeFalsy` and `not.toBeNull`). This means
59-
other assertions such as `toHaveValue` or `toBeDisabled` will not trigger this
60-
rule since these are valid uses with `getBy*`.
61-
62-
```js
63-
"testing-library/prefer-explicit-assert": ["error", {"assertion": "toBeInTheDocument"}],
64-
```
57+
| Option | Required | Default | Details | Example |
58+
| -------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
59+
| `assertion` | No | None | This string allows defining the preferred assertion to use with `getBy*` queries. By default, any assertion is valid (`toBeTruthy`, `toBeDefined`, etc.). However, they all assert slightly different things. This option ensures all `getBy*` assertions are consistent and use the same assertion. This rule only allows defining a presence matcher (`toBeInTheDocument`, `toBeTruthy`, or `toBeDefined`), but checks for both presence and absence matchers (`not.toBeFalsy` and `not.toBeNull`). This means other assertions such as `toHaveValue` or `toBeDisabled` will not trigger this rule since these are valid uses with `getBy*`. | `"toBeInTheDocument"` |
60+
| `includeFindQueries` | No | `true` | This boolean controls whether queries such as `findByText` are also checked by this rule. | `false` |
61+
62+
This is how you can use these options in eslint configuration:
63+
64+
```js
65+
"testing-library/prefer-explicit-assert": [
66+
"error",
67+
{ "assertion": "toBeInTheDocument", "includeFindQueries": false }
68+
],
69+
```
6570

6671
## When Not To Use It
6772

lib/rules/prefer-explicit-assert.ts

+23-19
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export type MessageIds =
1515
type Options = [
1616
{
1717
assertion?: string;
18+
includeFindQueries?: boolean;
1819
}
1920
];
2021

@@ -91,13 +92,14 @@ export default createTestingLibraryRule<Options, MessageIds>({
9192
type: 'string',
9293
enum: PRESENCE_MATCHERS,
9394
},
95+
includeFindQueries: { type: 'boolean' },
9496
},
9597
},
9698
],
9799
},
98-
defaultOptions: [{}],
100+
defaultOptions: [{ includeFindQueries: true }],
99101
create(context, [options], helpers) {
100-
const { assertion } = options;
102+
const { assertion, includeFindQueries } = options;
101103
const getQueryCalls: TSESTree.Identifier[] = [];
102104
const findQueryCalls: TSESTree.Identifier[] = [];
103105

@@ -112,26 +114,28 @@ export default createTestingLibraryRule<Options, MessageIds>({
112114
}
113115
},
114116
'Program:exit'() {
115-
findQueryCalls.forEach((queryCall) => {
116-
const memberExpression = isMemberExpression(queryCall.parent)
117-
? queryCall.parent
118-
: queryCall;
117+
if (includeFindQueries) {
118+
findQueryCalls.forEach((queryCall) => {
119+
const memberExpression = isMemberExpression(queryCall.parent)
120+
? queryCall.parent
121+
: queryCall;
119122

120-
if (
121-
isVariableDeclaration(queryCall) ||
122-
!isAtTopLevel(memberExpression)
123-
) {
124-
return;
125-
}
123+
if (
124+
isVariableDeclaration(queryCall) ||
125+
!isAtTopLevel(memberExpression)
126+
) {
127+
return;
128+
}
126129

127-
context.report({
128-
node: queryCall,
129-
messageId: 'preferExplicitAssert',
130-
data: {
131-
queryType: 'findBy*',
132-
},
130+
context.report({
131+
node: queryCall,
132+
messageId: 'preferExplicitAssert',
133+
data: {
134+
queryType: 'findBy*',
135+
},
136+
});
133137
});
134-
});
138+
}
135139

136140
getQueryCalls.forEach((queryCall) => {
137141
const node = isMemberExpression(queryCall.parent)

tests/lib/rules/prefer-explicit-assert.test.ts

+17
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@ ruleTester.run(RULE_NAME, rule, {
6060
const quxElement = await find${queryMethod}('qux')
6161
}`,
6262
})),
63+
...COMBINED_QUERIES_METHODS.map((queryMethod) => ({
64+
code: `
65+
async () => {
66+
expect(await find${queryMethod}('qux')).toBeInTheDocument();
67+
}`,
68+
})),
69+
...COMBINED_QUERIES_METHODS.map((queryMethod) => ({
70+
code: `
71+
async () => {
72+
await find${queryMethod}('foo')
73+
}`,
74+
options: [
75+
{
76+
includeFindQueries: false,
77+
},
78+
],
79+
})),
6380
...COMBINED_QUERIES_METHODS.map((queryMethod) => ({
6481
code: `const quxElement = find${queryMethod}('qux')`,
6582
})),

0 commit comments

Comments
 (0)