Skip to content

Commit 441493c

Browse files
neriyardenMichaelDeBoey
authored andcommitted
feat(await-async-utils): add autofix for direct usage
1 parent 64341f6 commit 441493c

File tree

2 files changed

+192
-2
lines changed

2 files changed

+192
-2
lines changed

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 {

tests/lib/rules/await-async-utils.test.ts

+184-2
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,13 @@ ruleTester.run(RULE_NAME, rule, {
346346
data: { name: asyncUtil },
347347
},
348348
],
349+
output: `
350+
import { ${asyncUtil} } from '${testingFramework}';
351+
test('${asyncUtil} util not waited is invalid', () => {
352+
doSomethingElse();
353+
await ${asyncUtil}(() => getByLabelText('email'));
354+
});
355+
`,
349356
} as const)
350357
),
351358
...ASYNC_UTILS.map(
@@ -366,6 +373,13 @@ ruleTester.run(RULE_NAME, rule, {
366373
data: { name: asyncUtil },
367374
},
368375
],
376+
output: `
377+
import { ${asyncUtil} } from '${testingFramework}';
378+
test('${asyncUtil} util not waited is invalid', () => {
379+
doSomethingElse();
380+
const el = await ${asyncUtil}(() => getByLabelText('email'));
381+
});
382+
`,
369383
} as const)
370384
),
371385
...ASYNC_UTILS.map(
@@ -386,6 +400,13 @@ ruleTester.run(RULE_NAME, rule, {
386400
data: { name: asyncUtil },
387401
},
388402
],
403+
output: `
404+
import * as asyncUtil from '${testingFramework}';
405+
test('asyncUtil.${asyncUtil} util not handled is invalid', () => {
406+
doSomethingElse();
407+
await asyncUtil.${asyncUtil}(() => getByLabelText('email'));
408+
});
409+
`,
389410
} as const)
390411
),
391412
...ASYNC_UTILS.map(
@@ -406,6 +427,13 @@ ruleTester.run(RULE_NAME, rule, {
406427
data: { name: asyncUtil },
407428
},
408429
],
430+
output: `
431+
import { ${asyncUtil} } from '${testingFramework}';
432+
test('${asyncUtil} util promise saved not handled is invalid', () => {
433+
doSomethingElse();
434+
const aPromise = await ${asyncUtil}(() => getByLabelText('email'));
435+
});
436+
`,
409437
} as const)
410438
),
411439
...ASYNC_UTILS.map(
@@ -433,6 +461,14 @@ ruleTester.run(RULE_NAME, rule, {
433461
data: { name: asyncUtil },
434462
},
435463
],
464+
output: `
465+
import { ${asyncUtil} } from '${testingFramework}';
466+
test('several ${asyncUtil} utils not handled are invalid', () => {
467+
const aPromise = ${asyncUtil}(() => getByLabelText('username'));
468+
doSomethingElse(aPromise);
469+
await ${asyncUtil}(() => getByLabelText('email'));
470+
});
471+
`,
436472
} as const)
437473
),
438474
...ASYNC_UTILS.map(
@@ -460,6 +496,14 @@ ruleTester.run(RULE_NAME, rule, {
460496
data: { name: asyncUtil },
461497
},
462498
],
499+
output: `
500+
import { ${asyncUtil} } from '${testingFramework}';
501+
test('unhandled expression that evaluates to promise is invalid', () => {
502+
const aPromise = ${asyncUtil}(() => getByLabelText('username'));
503+
doSomethingElse(aPromise);
504+
await ${asyncUtil}(() => getByLabelText('email'));
505+
});
506+
`,
463507
} as const)
464508
),
465509
...ASYNC_UTILS.map(
@@ -485,6 +529,18 @@ ruleTester.run(RULE_NAME, rule, {
485529
data: { name: 'waitForSomethingAsync' },
486530
},
487531
],
532+
output: `
533+
import { ${asyncUtil}, render } from '${testingFramework}';
534+
535+
function waitForSomethingAsync() {
536+
return ${asyncUtil}(() => somethingAsync())
537+
}
538+
539+
test('unhandled promise from function wrapping ${asyncUtil} util is invalid', async () => {
540+
render()
541+
await waitForSomethingAsync()
542+
});
543+
`,
488544
} as const)
489545
),
490546
...ASYNC_UTILS.map(
@@ -507,6 +563,15 @@ ruleTester.run(RULE_NAME, rule, {
507563
data: { name: asyncUtil },
508564
},
509565
],
566+
output: `
567+
import { ${asyncUtil} } from 'some-other-library';
568+
test(
569+
'aggressive reporting - util "${asyncUtil}" which is not related to testing library is invalid',
570+
async () => {
571+
doSomethingElse();
572+
await ${asyncUtil}();
573+
});
574+
`,
510575
} as const)
511576
),
512577
...ASYNC_UTILS.map(
@@ -532,6 +597,18 @@ ruleTester.run(RULE_NAME, rule, {
532597
data: { name: 'waitForSomethingAsync' },
533598
},
534599
],
600+
output: `
601+
import { ${asyncUtil}, render } from '${testingFramework}';
602+
603+
function waitForSomethingAsync() {
604+
return ${asyncUtil}(() => somethingAsync())
605+
}
606+
607+
test('unhandled promise from function wrapping ${asyncUtil} util is invalid', async () => {
608+
render()
609+
const el = await waitForSomethingAsync()
610+
});
611+
`,
535612
} as const)
536613
),
537614

@@ -555,6 +632,15 @@ ruleTester.run(RULE_NAME, rule, {
555632
data: { name: asyncUtil },
556633
},
557634
],
635+
output: `
636+
import * as asyncUtils from 'some-other-library';
637+
test(
638+
'aggressive reporting - util "asyncUtils.${asyncUtil}" which is not related to testing library is invalid',
639+
async () => {
640+
doSomethingElse();
641+
await asyncUtils.${asyncUtil}();
642+
});
643+
`,
558644
} as const)
559645
),
560646
...ASYNC_UTILS.map(
@@ -563,11 +649,11 @@ ruleTester.run(RULE_NAME, rule, {
563649
code: `
564650
function setup() {
565651
const utils = render(<MyComponent />);
566-
652+
567653
const waitForAsyncUtil = () => {
568654
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
569655
};
570-
656+
571657
return { waitForAsyncUtil, ...utils };
572658
}
573659
@@ -584,6 +670,22 @@ ruleTester.run(RULE_NAME, rule, {
584670
data: { name: 'waitForAsyncUtil' },
585671
},
586672
],
673+
output: `
674+
function setup() {
675+
const utils = render(<MyComponent />);
676+
677+
const waitForAsyncUtil = () => {
678+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
679+
};
680+
681+
return { waitForAsyncUtil, ...utils };
682+
}
683+
684+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
685+
const { user, waitForAsyncUtil } = setup();
686+
await waitForAsyncUtil();
687+
});
688+
`,
587689
} as const)
588690
),
589691
...ASYNC_UTILS.map(
@@ -614,6 +716,23 @@ ruleTester.run(RULE_NAME, rule, {
614716
data: { name: 'myAlias' },
615717
},
616718
],
719+
output: `
720+
function setup() {
721+
const utils = render(<MyComponent />);
722+
723+
const waitForAsyncUtil = () => {
724+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
725+
};
726+
727+
return { waitForAsyncUtil, ...utils };
728+
}
729+
730+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
731+
const { user, waitForAsyncUtil } = setup();
732+
const myAlias = waitForAsyncUtil;
733+
await myAlias();
734+
});
735+
`,
617736
} as const)
618737
),
619738
...ASYNC_UTILS.map(
@@ -643,6 +762,22 @@ ruleTester.run(RULE_NAME, rule, {
643762
data: { name: 'waitForAsyncUtil' },
644763
},
645764
],
765+
output: `
766+
function setup() {
767+
const utils = render(<MyComponent />);
768+
769+
const waitForAsyncUtil = () => {
770+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
771+
};
772+
773+
return { waitForAsyncUtil, ...utils };
774+
}
775+
776+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
777+
const { ...clone } = setup();
778+
await clone.waitForAsyncUtil();
779+
});
780+
`,
646781
} as const)
647782
),
648783
...ASYNC_UTILS.map(
@@ -672,6 +807,22 @@ ruleTester.run(RULE_NAME, rule, {
672807
data: { name: 'myAlias' },
673808
},
674809
],
810+
output: `
811+
function setup() {
812+
const utils = render(<MyComponent />);
813+
814+
const waitForAsyncUtil = () => {
815+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
816+
};
817+
818+
return { waitForAsyncUtil, ...utils };
819+
}
820+
821+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
822+
const { waitForAsyncUtil: myAlias } = setup();
823+
await myAlias();
824+
});
825+
`,
675826
} as const)
676827
),
677828
...ASYNC_UTILS.map(
@@ -700,6 +851,21 @@ ruleTester.run(RULE_NAME, rule, {
700851
data: { name: 'waitForAsyncUtil' },
701852
},
702853
],
854+
output: `
855+
function setup() {
856+
const utils = render(<MyComponent />);
857+
858+
const waitForAsyncUtil = () => {
859+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
860+
};
861+
862+
return { waitForAsyncUtil, ...utils };
863+
}
864+
865+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
866+
await setup().waitForAsyncUtil();
867+
});
868+
`,
703869
} as const)
704870
),
705871
...ASYNC_UTILS.map(
@@ -729,6 +895,22 @@ ruleTester.run(RULE_NAME, rule, {
729895
data: { name: 'myAlias' },
730896
},
731897
],
898+
output: `
899+
function setup() {
900+
const utils = render(<MyComponent />);
901+
902+
const waitForAsyncUtil = () => {
903+
return ${asyncUtil}(screen.queryByTestId('my-test-id'));
904+
};
905+
906+
return { waitForAsyncUtil, ...utils };
907+
}
908+
909+
test('unhandled promise from destructed property of async function wrapper is invalid', () => {
910+
const myAlias = setup().waitForAsyncUtil;
911+
await myAlias();
912+
});
913+
`,
732914
} as const)
733915
),
734916
]),

0 commit comments

Comments
 (0)