Skip to content

Commit 09a9f8c

Browse files
authored
fix(prefer-find-by): ensure autofix keeps assertion (#1107)
Fixes: #579
1 parent d8643b7 commit 09a9f8c

File tree

2 files changed

+87
-17
lines changed

2 files changed

+87
-17
lines changed

lib/rules/prefer-find-by.ts

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ASTUtils } from '@typescript-eslint/utils';
2+
import { isIdentifier } from '@typescript-eslint/utils/ast-utils';
23

34
import { createTestingLibraryRule } from '../create-testing-library-rule';
45
import {
@@ -409,7 +410,8 @@ export default createTestingLibraryRule<Options, MessageIds>({
409410
return;
410411
}
411412

412-
if (!isCallExpression(argument.body)) {
413+
const argumentBody = argument.body;
414+
if (!isCallExpression(argumentBody)) {
413415
return;
414416
}
415417

@@ -438,29 +440,42 @@ export default createTestingLibraryRule<Options, MessageIds>({
438440
}
439441

440442
const queryVariant = getFindByQueryVariant(fullQueryMethod);
441-
const callArguments = getQueryArguments(argument.body);
443+
const callArguments = getQueryArguments(argumentBody);
442444
const queryMethod = fullQueryMethod.split('By')[1];
443445

444446
if (!queryMethod) {
445447
return;
446448
}
447-
448449
reportInvalidUsage(node, {
449450
queryMethod,
450451
queryVariant,
451452
prevQuery: fullQueryMethod,
452453
fix(fixer) {
453-
const property = (
454-
(argument.body as TSESTree.CallExpression)
455-
.callee as TSESTree.MemberExpression
456-
).property;
457-
if (helpers.isCustomQuery(property as TSESTree.Identifier)) {
458-
return null;
459-
}
460-
const newCode = `${caller}.${queryVariant}${queryMethod}(${callArguments
454+
const findByCallText = `${caller}.${queryVariant}${queryMethod}(${callArguments
461455
.map((callArgNode) => sourceCode.getText(callArgNode))
462456
.join(', ')}${waitOptionsSourceCode})`;
463-
return fixer.replaceText(node, newCode);
457+
458+
if (!isMemberExpression(argumentBody.callee)) return null;
459+
460+
const { property, object } = argumentBody.callee;
461+
if (ASTUtils.isVariableDeclarator(node.parent.parent)) {
462+
if (isIdentifier(property) && helpers.isCustomQuery(property)) {
463+
return null;
464+
}
465+
return fixer.replaceText(node, findByCallText);
466+
}
467+
468+
if (!isCallExpression(object)) return null;
469+
470+
const originalExpect = sourceCode.getText(argumentBody);
471+
const awaited = `await ${findByCallText}`;
472+
const newExpect = originalExpect.replace(
473+
sourceCode.getText(object.arguments[0]),
474+
awaited
475+
);
476+
const output = originalExpect.replace(originalExpect, newExpect);
477+
478+
return fixer.replaceText(node.parent, output);
464479
},
465480
});
466481
return;
@@ -481,7 +496,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
481496

482497
const queryMethod = fullQueryMethod.split('By')[1];
483498
const queryVariant = getFindByQueryVariant(fullQueryMethod);
484-
const callArguments = getQueryArguments(argument.body);
499+
const callArguments = getQueryArguments(argumentBody);
485500

486501
reportInvalidUsage(node, {
487502
queryMethod,
@@ -490,10 +505,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
490505
fix(fixer) {
491506
// we know from above callee is an Identifier
492507
if (
493-
helpers.isCustomQuery(
494-
(argument.body as TSESTree.CallExpression)
495-
.callee as TSESTree.Identifier
496-
)
508+
helpers.isCustomQuery(argumentBody.callee as TSESTree.Identifier)
497509
) {
498510
return null;
499511
}

tests/lib/rules/prefer-find-by.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,64 @@ ruleTester.run(RULE_NAME, rule, {
691691
})
692692
`,
693693
})),
694+
...createScenario((waitMethod, queryMethod) => ({
695+
code: `
696+
import { screen } from '${testingFramework}';
697+
698+
it('tests', async () => {
699+
await ${waitMethod}(() => expect(screen.${queryMethod}('button', { name: 'Count is: 0' })).toBeInTheDocument())
700+
})
701+
`,
702+
errors: [
703+
{
704+
line: 5,
705+
column: 11,
706+
messageId: 'preferFindBy',
707+
data: {
708+
queryVariant: getFindByQueryVariant(queryMethod),
709+
queryMethod: queryMethod.split('By')[1],
710+
prevQuery: queryMethod,
711+
waitForMethodName: waitMethod,
712+
},
713+
},
714+
],
715+
output: `
716+
import { screen } from '${testingFramework}';
717+
718+
it('tests', async () => {
719+
expect(await screen.${buildFindByMethod(queryMethod)}('button', { name: 'Count is: 0' })).toBeInTheDocument()
720+
})
721+
`,
722+
})),
723+
...createScenario((waitMethod, queryMethod) => ({
724+
code: `
725+
import { screen } from '${testingFramework}';
726+
727+
it('tests', async () => {
728+
await ${waitMethod}(() => expect(screen.${queryMethod}('button', { name: 'Count is: 0' })).toBeInTheDocument(), { timeout: 100, interval: 200 })
729+
})
730+
`,
731+
errors: [
732+
{
733+
line: 5,
734+
column: 11,
735+
messageId: 'preferFindBy',
736+
data: {
737+
queryVariant: getFindByQueryVariant(queryMethod),
738+
queryMethod: queryMethod.split('By')[1],
739+
prevQuery: queryMethod,
740+
waitForMethodName: waitMethod,
741+
},
742+
},
743+
],
744+
output: `
745+
import { screen } from '${testingFramework}';
746+
747+
it('tests', async () => {
748+
expect(await screen.${buildFindByMethod(queryMethod)}('button', { name: 'Count is: 0' }, { timeout: 100, interval: 200 })).toBeInTheDocument()
749+
})
750+
`,
751+
})),
694752
// Issue #579, https://github.com/testing-library/eslint-plugin-testing-library/issues/579
695753
// findBy can have two sets of options: await screen.findByText('text', queryOptions, waitForOptions)
696754
...createScenario((waitMethod, queryMethod) => ({

0 commit comments

Comments
 (0)