diff --git a/docs/rules/prefer-find-by.md b/docs/rules/prefer-find-by.md index d85b296f..210e4c8c 100644 --- a/docs/rules/prefer-find-by.md +++ b/docs/rules/prefer-find-by.md @@ -26,6 +26,15 @@ const submitButton = await waitFor(() => const submitButton = await waitFor(() => queryAllByText('button', { name: /submit/i }) ); + +// arrow functions with one statement, calling any sync query method with presence assertion +const submitButton = await waitFor(() => + expect(queryByLabel('button', { name: /submit/i })).toBeInTheDocument() +); + +const submitButton = await waitFor(() => + expect(queryByLabel('button', { name: /submit/i })).not.toBeFalsy() +); ``` Examples of **correct** code for this rule: diff --git a/lib/rules/prefer-find-by.ts b/lib/rules/prefer-find-by.ts index 9699d4f3..97c99300 100644 --- a/lib/rules/prefer-find-by.ts +++ b/lib/rules/prefer-find-by.ts @@ -111,6 +111,230 @@ export default createTestingLibraryRule({ }); } + function getWrongQueryNameInAssertion( + node: TSESTree.ArrowFunctionExpression + ) { + if ( + !isCallExpression(node.body) || + !isMemberExpression(node.body.callee) + ) { + return null; + } + + // expect(getByText).toBeInTheDocument() shape + if ( + isCallExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.arguments[0]) && + ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee) + ) { + return node.body.callee.object.arguments[0].callee.name; + } + + if (!ASTUtils.isIdentifier(node.body.callee.property)) { + return null; + } + + // expect(screen.getByText).toBeInTheDocument() shape + if ( + isCallExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.arguments[0]) && + isMemberExpression(node.body.callee.object.arguments[0].callee) && + ASTUtils.isIdentifier( + node.body.callee.object.arguments[0].callee.property + ) + ) { + return node.body.callee.object.arguments[0].callee.property.name; + } + + // expect(screen.getByText).not shape + if ( + isMemberExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.object) && + isCallExpression(node.body.callee.object.object.arguments[0]) && + isMemberExpression( + node.body.callee.object.object.arguments[0].callee + ) && + ASTUtils.isIdentifier( + node.body.callee.object.object.arguments[0].callee.property + ) + ) { + return node.body.callee.object.object.arguments[0].callee.property.name; + } + + // expect(getByText).not shape + if ( + isMemberExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.object) && + isCallExpression(node.body.callee.object.object.arguments[0]) && + ASTUtils.isIdentifier( + node.body.callee.object.object.arguments[0].callee + ) + ) { + return node.body.callee.object.object.arguments[0].callee.name; + } + + return node.body.callee.property.name; + } + + function getWrongQueryName(node: TSESTree.ArrowFunctionExpression) { + if (!isCallExpression(node.body)) { + return null; + } + + // expect(() => getByText) and expect(() => screen.getByText) shape + if ( + ASTUtils.isIdentifier(node.body.callee) && + helpers.isSyncQuery(node.body.callee) + ) { + return node.body.callee.name; + } + + return getWrongQueryNameInAssertion(node); + } + + function getCaller(node: TSESTree.ArrowFunctionExpression) { + if ( + !isCallExpression(node.body) || + !isMemberExpression(node.body.callee) + ) { + return null; + } + + if (ASTUtils.isIdentifier(node.body.callee.object)) { + // () => screen.getByText + return node.body.callee.object.name; + } + + if ( + // expect() + isCallExpression(node.body.callee.object) && + ASTUtils.isIdentifier(node.body.callee.object.callee) && + isCallExpression(node.body.callee.object.arguments[0]) && + isMemberExpression(node.body.callee.object.arguments[0].callee) && + ASTUtils.isIdentifier( + node.body.callee.object.arguments[0].callee.object + ) + ) { + return node.body.callee.object.arguments[0].callee.object.name; + } + + if ( + // expect().not + isMemberExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.object) && + isCallExpression(node.body.callee.object.object.arguments[0]) && + isMemberExpression( + node.body.callee.object.object.arguments[0].callee + ) && + ASTUtils.isIdentifier( + node.body.callee.object.object.arguments[0].callee.object + ) + ) { + return node.body.callee.object.object.arguments[0].callee.object.name; + } + + return null; + } + + function isSyncQuery(node: TSESTree.ArrowFunctionExpression) { + if (!isCallExpression(node.body)) { + return false; + } + + const isQuery = + ASTUtils.isIdentifier(node.body.callee) && + helpers.isSyncQuery(node.body.callee); + + const isWrappedInPresenceAssert = + isMemberExpression(node.body.callee) && + isCallExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.arguments[0]) && + ASTUtils.isIdentifier(node.body.callee.object.arguments[0].callee) && + helpers.isSyncQuery(node.body.callee.object.arguments[0].callee) && + helpers.isPresenceAssert(node.body.callee); + + const isWrappedInNegatedPresenceAssert = + isMemberExpression(node.body.callee) && + isMemberExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.object) && + isCallExpression(node.body.callee.object.object.arguments[0]) && + ASTUtils.isIdentifier( + node.body.callee.object.object.arguments[0].callee + ) && + helpers.isSyncQuery( + node.body.callee.object.object.arguments[0].callee + ) && + helpers.isPresenceAssert(node.body.callee.object); + + return ( + isQuery || isWrappedInPresenceAssert || isWrappedInNegatedPresenceAssert + ); + } + + function isScreenSyncQuery(node: TSESTree.ArrowFunctionExpression) { + if (!isArrowFunctionExpression(node) || !isCallExpression(node.body)) { + return false; + } + + if ( + !isMemberExpression(node.body.callee) || + !ASTUtils.isIdentifier(node.body.callee.property) + ) { + return false; + } + + if ( + !ASTUtils.isIdentifier(node.body.callee.object) && + !isCallExpression(node.body.callee.object) && + !isMemberExpression(node.body.callee.object) + ) { + return false; + } + + const isWrappedInPresenceAssert = + helpers.isPresenceAssert(node.body.callee) && + isCallExpression(node.body.callee.object) && + isCallExpression(node.body.callee.object.arguments[0]) && + isMemberExpression(node.body.callee.object.arguments[0].callee) && + ASTUtils.isIdentifier( + node.body.callee.object.arguments[0].callee.object + ); + + const isWrappedInNegatedPresenceAssert = + isMemberExpression(node.body.callee.object) && + helpers.isPresenceAssert(node.body.callee.object) && + isCallExpression(node.body.callee.object.object) && + isCallExpression(node.body.callee.object.object.arguments[0]) && + isMemberExpression(node.body.callee.object.object.arguments[0].callee); + + return ( + helpers.isSyncQuery(node.body.callee.property) || + isWrappedInPresenceAssert || + isWrappedInNegatedPresenceAssert + ); + } + + function getQueryArguments(node: TSESTree.CallExpression) { + if ( + isMemberExpression(node.callee) && + isCallExpression(node.callee.object) && + isCallExpression(node.callee.object.arguments[0]) + ) { + return node.callee.object.arguments[0].arguments; + } + + if ( + isMemberExpression(node.callee) && + isMemberExpression(node.callee.object) && + isCallExpression(node.callee.object.object) && + isCallExpression(node.callee.object.object.arguments[0]) + ) { + return node.callee.object.object.arguments[0].arguments; + } + + return node.arguments; + } + return { 'AwaitExpression > CallExpression'(node: TSESTree.CallExpression) { if ( @@ -122,27 +346,32 @@ export default createTestingLibraryRule({ // ensure the only argument is an arrow function expression - if the arrow function is a block // we skip it const argument = node.arguments[0]; - if (!isArrowFunctionExpression(argument)) { - return; - } - if (!isCallExpression(argument.body)) { + if ( + !isArrowFunctionExpression(argument) || + !isCallExpression(argument.body) + ) { return; } const waitForMethodName = node.callee.name; // ensure here it's one of the sync methods that we are calling - if ( - isMemberExpression(argument.body.callee) && - ASTUtils.isIdentifier(argument.body.callee.property) && - ASTUtils.isIdentifier(argument.body.callee.object) && - helpers.isSyncQuery(argument.body.callee.property) - ) { + if (isScreenSyncQuery(argument)) { + const caller = getCaller(argument); + + if (!caller) { + return; + } + // shape of () => screen.getByText - const fullQueryMethod = argument.body.callee.property.name; - const caller = argument.body.callee.object.name; + const fullQueryMethod = getWrongQueryName(argument); + + if (!fullQueryMethod) { + return; + } + const queryVariant = getFindByQueryVariant(fullQueryMethod); - const callArguments = argument.body.arguments; + const callArguments = getQueryArguments(argument.body); const queryMethod = fullQueryMethod.split('By')[1]; reportInvalidUsage(node, { @@ -166,17 +395,21 @@ export default createTestingLibraryRule({ }); return; } - if ( - !ASTUtils.isIdentifier(argument.body.callee) || - !helpers.isSyncQuery(argument.body.callee) - ) { + + if (!isSyncQuery(argument)) { return; } + // shape of () => getByText - const fullQueryMethod = argument.body.callee.name; + const fullQueryMethod = getWrongQueryName(argument); + + if (!fullQueryMethod) { + return; + } + const queryMethod = fullQueryMethod.split('By')[1]; const queryVariant = getFindByQueryVariant(fullQueryMethod); - const callArguments = argument.body.arguments; + const callArguments = getQueryArguments(argument.body); reportInvalidUsage(node, { queryMethod, diff --git a/tests/lib/rules/prefer-find-by.test.ts b/tests/lib/rules/prefer-find-by.test.ts index e59c9b91..7975a023 100644 --- a/tests/lib/rules/prefer-find-by.test.ts +++ b/tests/lib/rules/prefer-find-by.test.ts @@ -63,7 +63,6 @@ ruleTester.run(RULE_NAME, rule, { ...SYNC_QUERIES_COMBINATIONS.map((queryMethod) => ({ code: ` import {waitFor} from '@testing-library/foo'; - it('tests', async () => { await waitFor(function() { return ${queryMethod}('baz', { name: 'foo' }) @@ -74,7 +73,6 @@ ruleTester.run(RULE_NAME, rule, { { code: ` import {waitFor} from '@testing-library/foo'; - it('tests', async () => { await waitFor(() => myCustomFunction()) }) @@ -118,59 +116,48 @@ ruleTester.run(RULE_NAME, rule, { })), ...SYNC_QUERIES_COMBINATIONS.map((queryMethod) => ({ code: ` - import {waitFor} from '@testing-library/foo'; + import {screen, waitFor} from '@testing-library/foo'; it('tests', async () => { - await waitFor(() => expect(${queryMethod}('baz')).toBeInTheDocument()); + const { ${queryMethod} } = render() + await waitFor(() => expect(${queryMethod}('baz')).toBeDisabled()); }) `, })), - { + ...SYNC_QUERIES_COMBINATIONS.map((queryMethod) => ({ code: ` import {waitFor} from '@testing-library/foo'; it('tests', async () => { - await waitFor(); - await wait(); + await waitFor(() => expect(screen.${queryMethod}('baz')).not.toBeInTheDocument()); }) `, - }, - ], - invalid: [ - ...createScenario((waitMethod: string, queryMethod: string) => ({ + })), + ...SYNC_QUERIES_COMBINATIONS.map((queryMethod) => ({ code: ` - import {${waitMethod}} from '@testing-library/foo'; + import {waitFor} from '@testing-library/foo'; it('tests', async () => { const { ${queryMethod} } = render() - const submitButton = await ${waitMethod}(() => ${queryMethod}('foo', { name: 'baz' })) - }) - `, - errors: [ - { - messageId: 'preferFindBy', - data: { - queryVariant: getFindByQueryVariant(queryMethod), - queryMethod: queryMethod.split('By')[1], - prevQuery: queryMethod, - waitForMethodName: waitMethod, - }, - }, - ], - output: ` - import {${waitMethod}} from '@testing-library/foo'; - it('tests', async () => { - const { ${queryMethod}, ${buildFindByMethod(queryMethod)} } = render() - const submitButton = await ${buildFindByMethod( - queryMethod - )}('foo', { name: 'baz' }) + await waitFor(() => expect(${queryMethod}('baz')).not.toBeInTheDocument()); }) `, })), - ...createScenario((waitMethod: string, queryMethod: string) => ({ + { code: ` - import {${waitMethod}, screen} from '@testing-library/foo'; + import {waitFor} from '@testing-library/foo'; it('tests', async () => { - const submitButton = await ${waitMethod}(() => screen.${queryMethod}('foo', { name: 'baz' })) + await waitFor(); + await wait(); }) `, + }, + ], + invalid: [ + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}, screen} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await ${waitMethod}(() => screen.${queryMethod}('foo', { name: 'baz' })) + }) + `, errors: [ { messageId: 'preferFindBy', @@ -183,25 +170,25 @@ ruleTester.run(RULE_NAME, rule, { }, ], output: ` - import {${waitMethod}, screen} from '@testing-library/foo'; - it('tests', async () => { - const submitButton = await screen.${buildFindByMethod( - queryMethod - )}('foo', { name: 'baz' }) - }) - `, + import {${waitMethod}, screen} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await screen.${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, })), // // this scenario verifies it works when the render function is defined in another scope ...WAIT_METHODS.map( (waitMethod: string) => ({ code: ` - import {${waitMethod}} from '@testing-library/foo'; - const { getByText, queryByLabelText, findAllByRole } = customRender() - it('tests', async () => { - const submitButton = await ${waitMethod}(() => getByText('baz', { name: 'button' })) - }) - `, + import {${waitMethod}} from '@testing-library/foo'; + const { getByText, queryByLabelText, findAllByRole } = customRender() + it('tests', async () => { + const submitButton = await ${waitMethod}(() => getByText('baz', { name: 'button' })) + }) + `, errors: [ { messageId: 'preferFindBy', @@ -214,12 +201,12 @@ ruleTester.run(RULE_NAME, rule, { }, ], output: ` - import {${waitMethod}} from '@testing-library/foo'; - const { getByText, queryByLabelText, findAllByRole, findByText } = customRender() - it('tests', async () => { - const submitButton = await findByText('baz', { name: 'button' }) - }) - `, + import {${waitMethod}} from '@testing-library/foo'; + const { getByText, queryByLabelText, findAllByRole, findByText } = customRender() + it('tests', async () => { + const submitButton = await findByText('baz', { name: 'button' }) + }) + `, } as const) ), // // this scenario verifies when findBy* were already defined (because it was used elsewhere) @@ -227,12 +214,12 @@ ruleTester.run(RULE_NAME, rule, { (waitMethod: string) => ({ code: ` - import {${waitMethod}} from '@testing-library/foo'; - const { getAllByRole, findAllByRole } = customRender() - it('tests', async () => { - const submitButton = await ${waitMethod}(() => getAllByRole('baz', { name: 'button' })) - }) - `, + import {${waitMethod}} from '@testing-library/foo'; + const { getAllByRole, findAllByRole } = customRender() + it('tests', async () => { + const submitButton = await ${waitMethod}(() => getAllByRole('baz', { name: 'button' })) + }) + `, errors: [ { messageId: 'preferFindBy', @@ -245,12 +232,12 @@ ruleTester.run(RULE_NAME, rule, { }, ], output: ` - import {${waitMethod}} from '@testing-library/foo'; - const { getAllByRole, findAllByRole } = customRender() - it('tests', async () => { - const submitButton = await findAllByRole('baz', { name: 'button' }) - }) - `, + import {${waitMethod}} from '@testing-library/foo'; + const { getAllByRole, findAllByRole } = customRender() + it('tests', async () => { + const submitButton = await findAllByRole('baz', { name: 'button' }) + }) + `, } as const) ), // invalid code, as we need findBy* to be defined somewhere, but required for getting 100% coverage @@ -272,9 +259,9 @@ ruleTester.run(RULE_NAME, rule, { // this code would be invalid too, as findByRole is not defined anywhere. { code: ` - const getByRole = render().getByRole - const submitButton = await waitFor(() => getByRole('baz', { name: 'button' })) - `, + const getByRole = render().getByRole + const submitButton = await waitFor(() => getByRole('baz', { name: 'button' })) + `, errors: [ { messageId: 'preferFindBy', @@ -287,21 +274,21 @@ ruleTester.run(RULE_NAME, rule, { }, ], output: ` - const getByRole = render().getByRole - const submitButton = await findByRole('baz', { name: 'button' }) - `, + const getByRole = render().getByRole + const submitButton = await findByRole('baz', { name: 'button' }) + `, }, // custom query triggers the error but there is no fix - so output is the same ...WAIT_METHODS.map( (waitMethod: string) => ({ code: ` - import {${waitMethod},render} from '@testing-library/foo'; - it('tests', async () => { - const { getByCustomQuery } = render() - const submitButton = await ${waitMethod}(() => getByCustomQuery('baz')) - }) - `, + import {${waitMethod},render} from '@testing-library/foo'; + it('tests', async () => { + const { getByCustomQuery } = render() + const submitButton = await ${waitMethod}(() => getByCustomQuery('baz')) + }) + `, errors: [ { messageId: 'preferFindBy', @@ -314,12 +301,12 @@ ruleTester.run(RULE_NAME, rule, { }, ], output: ` - import {${waitMethod},render} from '@testing-library/foo'; - it('tests', async () => { - const { getByCustomQuery } = render() - const submitButton = await ${waitMethod}(() => getByCustomQuery('baz')) - }) - `, + import {${waitMethod},render} from '@testing-library/foo'; + it('tests', async () => { + const { getByCustomQuery } = render() + const submitButton = await ${waitMethod}(() => getByCustomQuery('baz')) + }) + `, } as const) ), // custom query triggers the error but there is no fix - so output is the same @@ -327,12 +314,12 @@ ruleTester.run(RULE_NAME, rule, { (waitMethod: string) => ({ code: ` - import {${waitMethod},render,screen} from '@testing-library/foo'; - it('tests', async () => { - const { getByCustomQuery } = render() - const submitButton = await ${waitMethod}(() => screen.getByCustomQuery('baz')) - }) - `, + import {${waitMethod},render,screen} from '@testing-library/foo'; + it('tests', async () => { + const { getByCustomQuery } = render() + const submitButton = await ${waitMethod}(() => screen.getByCustomQuery('baz')) + }) + `, errors: [ { messageId: 'preferFindBy', @@ -345,13 +332,323 @@ ruleTester.run(RULE_NAME, rule, { }, ], output: ` - import {${waitMethod},render,screen} from '@testing-library/foo'; + import {${waitMethod},render,screen} from '@testing-library/foo'; + it('tests', async () => { + const { getByCustomQuery } = render() + const submitButton = await ${waitMethod}(() => screen.getByCustomQuery('baz')) + }) + `, + } as const) + ), + // presence matchers + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; it('tests', async () => { - const { getByCustomQuery } = render() - const submitButton = await ${waitMethod}(() => screen.getByCustomQuery('baz')) + const { ${queryMethod} } = render() + const submitButton = await ${waitMethod}(() => ${queryMethod}('foo', { name: 'baz' })) }) `, - } as const) - ), + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod}, ${buildFindByMethod(queryMethod)} } = render() + const submitButton = await ${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod} } = render() + const submitButton = await ${waitMethod}(() => expect(${queryMethod}('foo', { name: 'baz' })).toBeInTheDocument()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod}, ${buildFindByMethod(queryMethod)} } = render() + const submitButton = await ${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod} } = render() + const submitButton = await ${waitMethod}(() => expect(${queryMethod}('foo', { name: 'baz' })).toBeDefined()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod}, ${buildFindByMethod(queryMethod)} } = render() + const submitButton = await ${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod} } = render() + const submitButton = await ${waitMethod}(() => expect(${queryMethod}('foo', { name: 'baz' })).not.toBeNull()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod}, ${buildFindByMethod(queryMethod)} } = render() + const submitButton = await ${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod} } = render() + const submitButton = await ${waitMethod}(() => expect(${queryMethod}('foo', { name: 'baz' })).toBeTruthy()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod}, ${buildFindByMethod(queryMethod)} } = render() + const submitButton = await ${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod} } = render() + const submitButton = await ${waitMethod}(() => expect(${queryMethod}('foo', { name: 'baz' })).not.toBeFalsy()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const { ${queryMethod}, ${buildFindByMethod(queryMethod)} } = render() + const submitButton = await ${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await ${waitMethod}(() => expect(screen.${queryMethod}('foo', { name: 'baz' })).toBeInTheDocument()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await screen.${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await ${waitMethod}(() => expect(screen.${queryMethod}('foo', { name: 'baz' })).toBeDefined()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await screen.${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await ${waitMethod}(() => expect(screen.${queryMethod}('foo', { name: 'baz' })).not.toBeNull()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await screen.${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await ${waitMethod}(() => expect(screen.${queryMethod}('foo', { name: 'baz' })).toBeTruthy()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await screen.${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), + ...createScenario((waitMethod: string, queryMethod: string) => ({ + code: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await ${waitMethod}(() => expect(screen.${queryMethod}('foo', { name: 'baz' })).not.toBeFalsy()) + }) + `, + errors: [ + { + messageId: 'preferFindBy', + data: { + queryVariant: getFindByQueryVariant(queryMethod), + queryMethod: queryMethod.split('By')[1], + prevQuery: queryMethod, + waitForMethodName: waitMethod, + }, + }, + ], + output: ` + import {${waitMethod}} from '@testing-library/foo'; + it('tests', async () => { + const submitButton = await screen.${buildFindByMethod( + queryMethod + )}('foo', { name: 'baz' }) + }) + `, + })), ], });