Skip to content

Commit c9fcf83

Browse files
authored
feat(no-wait-for-multiple-assertions): add auto-fix (#1099)
Closes #1082
1 parent db8756c commit c9fcf83

File tree

4 files changed

+169
-2
lines changed

4 files changed

+169
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ module.exports = [
340340
| [no-render-in-lifecycle](docs/rules/no-render-in-lifecycle.md) | Disallow the use of `render` in testing frameworks setup functions | ![badge-angular][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | |
341341
| [no-test-id-queries](docs/rules/no-test-id-queries.md) | Ensure no `data-testid` queries are used | | | |
342342
| [no-unnecessary-act](docs/rules/no-unnecessary-act.md) | Disallow wrapping Testing Library utils or empty callbacks in `act` | ![badge-marko][] ![badge-react][] | | |
343-
| [no-wait-for-multiple-assertions](docs/rules/no-wait-for-multiple-assertions.md) | Disallow the use of multiple `expect` calls inside `waitFor` | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | |
343+
| [no-wait-for-multiple-assertions](docs/rules/no-wait-for-multiple-assertions.md) | Disallow the use of multiple `expect` calls inside `waitFor` | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | 🔧 |
344344
| [no-wait-for-side-effects](docs/rules/no-wait-for-side-effects.md) | Disallow the use of side effects in `waitFor` | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | 🔧 |
345345
| [no-wait-for-snapshot](docs/rules/no-wait-for-snapshot.md) | Ensures no snapshot is generated inside of a `waitFor` call | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-svelte][] ![badge-vue][] | | |
346346
| [prefer-explicit-assert](docs/rules/prefer-explicit-assert.md) | Suggest using explicit assertions rather than standalone queries | | | |

docs/rules/no-wait-for-multiple-assertions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

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

5+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6+
57
<!-- end auto-generated rule header -->
68

79
## Rule Details

lib/rules/no-wait-for-multiple-assertions.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
3333
'Avoid using multiple assertions within `waitFor` callback',
3434
},
3535
schema: [],
36+
fixable: 'code',
3637
},
3738
defaultOptions: [],
3839
create(context, _, helpers) {
@@ -108,6 +109,37 @@ export default createTestingLibraryRule<Options, MessageIds>({
108109
context.report({
109110
node: expressionStatement,
110111
messageId: 'noWaitForMultipleAssertion',
112+
fix(fixer) {
113+
const sourceCode = getSourceCode(context);
114+
115+
const lineStart = sourceCode.getIndexFromLoc({
116+
line: expressionStatement.loc.start.line,
117+
column: 0,
118+
});
119+
const lineEnd = sourceCode.getIndexFromLoc({
120+
line: expressionStatement.loc.end.line + 1,
121+
column: 0,
122+
});
123+
const lines = sourceCode.getText().split('\n');
124+
const line = lines[callExpressionNode.loc.start.line - 1];
125+
const indent = line.match(/^\s*/)?.[0] ?? '';
126+
127+
const expressionStatementLines = lines.slice(
128+
expressionStatement.loc.start.line - 1,
129+
expressionStatement.loc.end.line
130+
);
131+
const statementText = expressionStatementLines
132+
.join('\n')
133+
.trimStart();
134+
135+
return [
136+
fixer.removeRange([lineStart, lineEnd]),
137+
fixer.insertTextAfter(
138+
callExpressionNode,
139+
`\n${indent}${statementText}`
140+
),
141+
];
142+
},
111143
});
112144
}
113145
}

tests/lib/rules/no-wait-for-multiple-assertions.test.ts

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ ruleTester.run(RULE_NAME, rule, {
137137
errors: [
138138
{ line: 4, column: 11, messageId: 'noWaitForMultipleAssertion' },
139139
],
140+
output: `
141+
await waitFor(() => {
142+
expect(a).toEqual('a')
143+
})
144+
expect(a).toEqual('a')
145+
`,
140146
},
141147
{
142148
code: `
@@ -148,6 +154,12 @@ ruleTester.run(RULE_NAME, rule, {
148154
errors: [
149155
{ line: 4, column: 11, messageId: 'noWaitForMultipleAssertion' },
150156
],
157+
output: `
158+
await waitFor(() => {
159+
expect(screen.getByTestId('a')).toHaveTextContent('a')
160+
})
161+
expect(screen.getByTestId('a')).toHaveTextContent('a')
162+
`,
151163
},
152164
...SUPPORTED_TESTING_FRAMEWORKS.map<RuleInvalidTestCase>(
153165
(testingFramework) => ({
@@ -162,6 +174,13 @@ ruleTester.run(RULE_NAME, rule, {
162174
errors: [
163175
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
164176
],
177+
output: `// Aggressive Reporting disabled
178+
import { waitFor } from '${testingFramework}'
179+
await waitFor(() => {
180+
expect(a).toEqual('a')
181+
})
182+
expect(a).toEqual('a')
183+
`,
165184
})
166185
),
167186
{
@@ -176,6 +195,13 @@ ruleTester.run(RULE_NAME, rule, {
176195
errors: [
177196
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
178197
],
198+
output: `// Aggressive Reporting disabled
199+
import { waitFor as renamedWaitFor } from 'test-utils'
200+
await renamedWaitFor(() => {
201+
expect(a).toEqual('a')
202+
})
203+
expect(a).toEqual('a')
204+
`,
179205
},
180206
{
181207
code: `
@@ -188,6 +214,13 @@ ruleTester.run(RULE_NAME, rule, {
188214
errors: [
189215
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
190216
],
217+
output: `
218+
await waitFor(() => {
219+
expect(a).toEqual('a')
220+
console.log('testing-library')
221+
})
222+
expect(a).toEqual('a')
223+
`,
191224
},
192225
{
193226
code: `
@@ -202,6 +235,15 @@ ruleTester.run(RULE_NAME, rule, {
202235
errors: [
203236
{ line: 6, column: 13, messageId: 'noWaitForMultipleAssertion' },
204237
],
238+
output: `
239+
test('should whatever', async () => {
240+
await waitFor(() => {
241+
expect(a).toEqual('a')
242+
console.log('testing-library')
243+
})
244+
expect(a).toEqual('a')
245+
})
246+
`,
205247
},
206248
{
207249
code: `
@@ -214,6 +256,13 @@ ruleTester.run(RULE_NAME, rule, {
214256
errors: [
215257
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
216258
],
259+
output: `
260+
await waitFor(async () => {
261+
expect(a).toEqual('a')
262+
await somethingAsync()
263+
})
264+
expect(a).toEqual('a')
265+
`,
217266
},
218267
{
219268
code: `
@@ -229,6 +278,32 @@ ruleTester.run(RULE_NAME, rule, {
229278
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
230279
{ line: 6, column: 11, messageId: 'noWaitForMultipleAssertion' },
231280
],
281+
output: [
282+
`
283+
await waitFor(function() {
284+
expect(a).toEqual('a')
285+
expect(a).toEqual('a')
286+
expect(a).toEqual('a')
287+
})
288+
expect(a).toEqual('a')
289+
`,
290+
`
291+
await waitFor(function() {
292+
expect(a).toEqual('a')
293+
expect(a).toEqual('a')
294+
})
295+
expect(a).toEqual('a')
296+
expect(a).toEqual('a')
297+
`,
298+
`
299+
await waitFor(function() {
300+
expect(a).toEqual('a')
301+
})
302+
expect(a).toEqual('a')
303+
expect(a).toEqual('a')
304+
expect(a).toEqual('a')
305+
`,
306+
],
232307
},
233308
{
234309
code: `
@@ -243,6 +318,24 @@ ruleTester.run(RULE_NAME, rule, {
243318
{ line: 4, column: 11, messageId: 'noWaitForMultipleAssertion' },
244319
{ line: 6, column: 11, messageId: 'noWaitForMultipleAssertion' },
245320
],
321+
output: [
322+
`
323+
await waitFor(function() {
324+
expect(a).toEqual('a')
325+
expect(b).toEqual('b')
326+
expect(b).toEqual('b')
327+
})
328+
expect(a).toEqual('a')
329+
`,
330+
`
331+
await waitFor(function() {
332+
expect(a).toEqual('a')
333+
expect(b).toEqual('b')
334+
})
335+
expect(b).toEqual('b')
336+
expect(a).toEqual('a')
337+
`,
338+
],
246339
},
247340
{
248341
code: `
@@ -255,6 +348,13 @@ ruleTester.run(RULE_NAME, rule, {
255348
errors: [
256349
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
257350
],
351+
output: `
352+
await waitFor(function() {
353+
expect(a).toEqual('a')
354+
console.log('testing-library')
355+
})
356+
expect(a).toEqual('a')
357+
`,
258358
},
259359
{
260360
code: `
@@ -267,18 +367,51 @@ ruleTester.run(RULE_NAME, rule, {
267367
errors: [
268368
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
269369
],
370+
output: `
371+
await waitFor(async function() {
372+
expect(a).toEqual('a')
373+
const el = await somethingAsync()
374+
})
375+
expect(a).toEqual('a')
376+
`,
270377
},
271378
{
272379
code: `
273380
await waitFor(() => {
274381
expect(window.fetch).toHaveBeenCalledTimes(1);
275382
expect(localStorage.setItem).toHaveBeenCalledWith('bar', 'baz');
276383
expect(window.fetch).toHaveBeenCalledWith('/foo');
277-
});
384+
})
385+
`,
386+
errors: [
387+
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
388+
],
389+
output: `
390+
await waitFor(() => {
391+
expect(window.fetch).toHaveBeenCalledTimes(1);
392+
expect(localStorage.setItem).toHaveBeenCalledWith('bar', 'baz');
393+
})
394+
expect(window.fetch).toHaveBeenCalledWith('/foo');
395+
`,
396+
},
397+
{
398+
code: `
399+
await waitFor(() => {
400+
expect(window.fetch).toHaveBeenCalledTimes(1);
401+
expect(localStorage.setItem).toHaveBeenCalledWith('bar', 'baz');
402+
expect(window.fetch).toHaveBeenCalledWith('/foo'); // comment
403+
})
278404
`,
279405
errors: [
280406
{ line: 5, column: 11, messageId: 'noWaitForMultipleAssertion' },
281407
],
408+
output: `
409+
await waitFor(() => {
410+
expect(window.fetch).toHaveBeenCalledTimes(1);
411+
expect(localStorage.setItem).toHaveBeenCalledWith('bar', 'baz');
412+
})
413+
expect(window.fetch).toHaveBeenCalledWith('/foo'); // comment
414+
`,
282415
},
283416
],
284417
});

0 commit comments

Comments
 (0)