Skip to content

Commit 9717acd

Browse files
neriyardenMichaelDeBoey
authored andcommitted
feat(await-async-utils): add autofix for direct usage
1 parent 657ed01 commit 9717acd

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

Diff for: lib/rules/await-async-utils.ts

+8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
getFunctionName,
88
getInnermostReturningFunction,
99
getVariableReferences,
10+
isMemberExpression,
1011
isObjectPattern,
1112
isPromiseHandled,
1213
isProperty,
@@ -36,6 +37,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
3637
'Promise returned from {{ name }} wrapper over async util must be handled',
3738
},
3839
schema: [],
40+
fixable: 'code',
3941
},
4042
defaultOptions: [],
4143

@@ -149,6 +151,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
149151
data: {
150152
name: node.name,
151153
},
154+
fix: (fixer) => {
155+
if (isMemberExpression(node.parent)) {
156+
return fixer.insertTextBefore(node.parent, 'await ');
157+
}
158+
return fixer.insertTextBefore(node, 'await ');
159+
},
152160
});
153161
}
154162
} else {

Diff for: tests/lib/rules/await-async-utils.test.ts

+182
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,13 @@ ruleTester.run(RULE_NAME, rule, {
347347
data: { name: asyncUtil },
348348
},
349349
],
350+
output: `
351+
import { ${asyncUtil} } from '${testingFramework}';
352+
test('${asyncUtil} util not waited is invalid', () => {
353+
doSomethingElse();
354+
await ${asyncUtil}(() => getByLabelText('email'));
355+
});
356+
`,
350357
}) as const
351358
),
352359
...ASYNC_UTILS.map(
@@ -367,6 +374,13 @@ ruleTester.run(RULE_NAME, rule, {
367374
data: { name: asyncUtil },
368375
},
369376
],
377+
output: `
378+
import { ${asyncUtil} } from '${testingFramework}';
379+
test('${asyncUtil} util not waited is invalid', () => {
380+
doSomethingElse();
381+
const el = await ${asyncUtil}(() => getByLabelText('email'));
382+
});
383+
`,
370384
}) as const
371385
),
372386
...ASYNC_UTILS.map(
@@ -387,6 +401,13 @@ ruleTester.run(RULE_NAME, rule, {
387401
data: { name: asyncUtil },
388402
},
389403
],
404+
output: `
405+
import * as asyncUtil from '${testingFramework}';
406+
test('asyncUtil.${asyncUtil} util not handled is invalid', () => {
407+
doSomethingElse();
408+
await asyncUtil.${asyncUtil}(() => getByLabelText('email'));
409+
});
410+
`,
390411
}) as const
391412
),
392413
...ASYNC_UTILS.map(
@@ -407,6 +428,13 @@ ruleTester.run(RULE_NAME, rule, {
407428
data: { name: asyncUtil },
408429
},
409430
],
431+
output: `
432+
import { ${asyncUtil} } from '${testingFramework}';
433+
test('${asyncUtil} util promise saved not handled is invalid', () => {
434+
doSomethingElse();
435+
const aPromise = await ${asyncUtil}(() => getByLabelText('email'));
436+
});
437+
`,
410438
}) as const
411439
),
412440
...ASYNC_UTILS.map(
@@ -434,6 +462,14 @@ ruleTester.run(RULE_NAME, rule, {
434462
data: { name: asyncUtil },
435463
},
436464
],
465+
output: `
466+
import { ${asyncUtil} } from '${testingFramework}';
467+
test('several ${asyncUtil} utils not handled are invalid', () => {
468+
const aPromise = ${asyncUtil}(() => getByLabelText('username'));
469+
doSomethingElse(aPromise);
470+
await ${asyncUtil}(() => getByLabelText('email'));
471+
});
472+
`,
437473
}) as const
438474
),
439475
...ASYNC_UTILS.map(
@@ -461,6 +497,14 @@ ruleTester.run(RULE_NAME, rule, {
461497
data: { name: asyncUtil },
462498
},
463499
],
500+
output: `
501+
import { ${asyncUtil} } from '${testingFramework}';
502+
test('unhandled expression that evaluates to promise is invalid', () => {
503+
const aPromise = ${asyncUtil}(() => getByLabelText('username'));
504+
doSomethingElse(aPromise);
505+
await ${asyncUtil}(() => getByLabelText('email'));
506+
});
507+
`,
464508
}) as const
465509
),
466510
...ASYNC_UTILS.map(
@@ -486,6 +530,18 @@ ruleTester.run(RULE_NAME, rule, {
486530
data: { name: 'waitForSomethingAsync' },
487531
},
488532
],
533+
output: `
534+
import { ${asyncUtil}, render } from '${testingFramework}';
535+
536+
function waitForSomethingAsync() {
537+
return ${asyncUtil}(() => somethingAsync())
538+
}
539+
540+
test('unhandled promise from function wrapping ${asyncUtil} util is invalid', async () => {
541+
render()
542+
await waitForSomethingAsync()
543+
});
544+
`,
489545
}) as const
490546
),
491547
...ASYNC_UTILS.map(
@@ -508,6 +564,15 @@ ruleTester.run(RULE_NAME, rule, {
508564
data: { name: asyncUtil },
509565
},
510566
],
567+
output: `
568+
import { ${asyncUtil} } from 'some-other-library';
569+
test(
570+
'aggressive reporting - util "${asyncUtil}" which is not related to testing library is invalid',
571+
async () => {
572+
doSomethingElse();
573+
await ${asyncUtil}();
574+
});
575+
`,
511576
}) as const
512577
),
513578
...ASYNC_UTILS.map(
@@ -533,6 +598,18 @@ ruleTester.run(RULE_NAME, rule, {
533598
data: { name: 'waitForSomethingAsync' },
534599
},
535600
],
601+
output: `
602+
import { ${asyncUtil}, render } from '${testingFramework}';
603+
604+
function waitForSomethingAsync() {
605+
return ${asyncUtil}(() => somethingAsync())
606+
}
607+
608+
test('unhandled promise from function wrapping ${asyncUtil} util is invalid', async () => {
609+
render()
610+
const el = await waitForSomethingAsync()
611+
});
612+
`,
536613
}) as const
537614
),
538615

@@ -556,6 +633,15 @@ ruleTester.run(RULE_NAME, rule, {
556633
data: { name: asyncUtil },
557634
},
558635
],
636+
output: `
637+
import * as asyncUtils from 'some-other-library';
638+
test(
639+
'aggressive reporting - util "asyncUtils.${asyncUtil}" which is not related to testing library is invalid',
640+
async () => {
641+
doSomethingElse();
642+
await asyncUtils.${asyncUtil}();
643+
});
644+
`,
559645
}) as const
560646
),
561647
...ASYNC_UTILS.map(
@@ -586,6 +672,22 @@ ruleTester.run(RULE_NAME, rule, {
586672
data: { name: 'waitForAsyncUtil' },
587673
},
588674
],
675+
output: `
676+
function setup() {
677+
const utils = render(<MyComponent />);
678+
679+
const waitForAsyncUtil = () => {
680+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
681+
};
682+
683+
return { waitForAsyncUtil, ...utils };
684+
}
685+
686+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
687+
const { user, waitForAsyncUtil } = setup();
688+
await waitForAsyncUtil();
689+
});
690+
`,
589691
}) as const
590692
),
591693
...ASYNC_UTILS.map(
@@ -617,6 +719,23 @@ ruleTester.run(RULE_NAME, rule, {
617719
data: { name: 'myAlias' },
618720
},
619721
],
722+
output: `
723+
function setup() {
724+
const utils = render(<MyComponent />);
725+
726+
const waitForAsyncUtil = () => {
727+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
728+
};
729+
730+
return { waitForAsyncUtil, ...utils };
731+
}
732+
733+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
734+
const { user, waitForAsyncUtil } = setup();
735+
const myAlias = waitForAsyncUtil;
736+
await myAlias();
737+
});
738+
`,
620739
}) as const
621740
),
622741
...ASYNC_UTILS.map(
@@ -647,6 +766,22 @@ ruleTester.run(RULE_NAME, rule, {
647766
data: { name: 'waitForAsyncUtil' },
648767
},
649768
],
769+
output: `
770+
function setup() {
771+
const utils = render(<MyComponent />);
772+
773+
const waitForAsyncUtil = () => {
774+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
775+
};
776+
777+
return { waitForAsyncUtil, ...utils };
778+
}
779+
780+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
781+
const { ...clone } = setup();
782+
await clone.waitForAsyncUtil();
783+
});
784+
`,
650785
}) as const
651786
),
652787
...ASYNC_UTILS.map(
@@ -677,6 +812,22 @@ ruleTester.run(RULE_NAME, rule, {
677812
data: { name: 'myAlias' },
678813
},
679814
],
815+
output: `
816+
function setup() {
817+
const utils = render(<MyComponent />);
818+
819+
const waitForAsyncUtil = () => {
820+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
821+
};
822+
823+
return { waitForAsyncUtil, ...utils };
824+
}
825+
826+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
827+
const { waitForAsyncUtil: myAlias } = setup();
828+
await myAlias();
829+
});
830+
`,
680831
}) as const
681832
),
682833
...ASYNC_UTILS.map(
@@ -706,6 +857,21 @@ ruleTester.run(RULE_NAME, rule, {
706857
data: { name: 'waitForAsyncUtil' },
707858
},
708859
],
860+
output: `
861+
function setup() {
862+
const utils = render(<MyComponent />);
863+
864+
const waitForAsyncUtil = () => {
865+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
866+
};
867+
868+
return { waitForAsyncUtil, ...utils };
869+
}
870+
871+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
872+
await setup().waitForAsyncUtil();
873+
});
874+
`,
709875
}) as const
710876
),
711877
...ASYNC_UTILS.map(
@@ -736,6 +902,22 @@ ruleTester.run(RULE_NAME, rule, {
736902
data: { name: 'myAlias' },
737903
},
738904
],
905+
output: `
906+
function setup() {
907+
const utils = render(<MyComponent />);
908+
909+
const waitForAsyncUtil = () => {
910+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
911+
};
912+
913+
return { waitForAsyncUtil, ...utils };
914+
}
915+
916+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
917+
const myAlias = setup().waitForAsyncUtil;
918+
await myAlias();
919+
});
920+
`,
739921
}) as const
740922
),
741923
]),

0 commit comments

Comments
 (0)