diff --git a/lib/node-utils.ts b/lib/node-utils.ts index 605330ac..148bc8ef 100644 --- a/lib/node-utils.ts +++ b/lib/node-utils.ts @@ -147,6 +147,19 @@ export function findClosestCallNode( } } +export function isCallExpressionCallee( + node: TSESTree.CallExpression, + identifier: TSESTree.Identifier +): boolean { + const nodeInnerIdentifier = getIdentifierNode(node); + + if (nodeInnerIdentifier) { + return nodeInnerIdentifier.name === identifier.name; + } + + return false; +} + export function isObjectExpression( node: TSESTree.Expression ): node is TSESTree.ObjectExpression { diff --git a/lib/rules/no-await-sync-query.ts b/lib/rules/no-await-sync-query.ts index ced9d104..15c4d0c3 100644 --- a/lib/rules/no-await-sync-query.ts +++ b/lib/rules/no-await-sync-query.ts @@ -1,5 +1,9 @@ import { TSESTree } from '@typescript-eslint/experimental-utils'; import { createTestingLibraryRule } from '../create-testing-library-rule'; +import { + findClosestCallExpressionNode, + isCallExpressionCallee, +} from '../node-utils'; export const RULE_NAME = 'no-await-sync-query'; export type MessageIds = 'noAwaitSyncQuery'; @@ -26,6 +30,15 @@ export default createTestingLibraryRule({ create(context, _, helpers) { return { 'AwaitExpression > CallExpression Identifier'(node: TSESTree.Identifier) { + const closestCallExpression = findClosestCallExpressionNode(node, true); + if (!closestCallExpression) { + return; + } + + if (!isCallExpressionCallee(closestCallExpression, node)) { + return; + } + if (helpers.isSyncQuery(node)) { context.report({ node, diff --git a/tests/lib/rules/no-await-sync-query.test.ts b/tests/lib/rules/no-await-sync-query.test.ts index 40b46ba5..cb31c4a6 100644 --- a/tests/lib/rules/no-await-sync-query.test.ts +++ b/tests/lib/rules/no-await-sync-query.test.ts @@ -76,6 +76,26 @@ ruleTester.run(RULE_NAME, rule, { } `, }, + + // https://github.com/testing-library/eslint-plugin-testing-library/issues/276 + ` + // sync query within call expression but not part of the callee + const chooseElementFromSomewhere = async (text, getAllByLabelText) => { + const someElement = getAllByLabelText(text)[0].parentElement; + // ... + await someOtherAsyncFunction(); + }; + + await chooseElementFromSomewhere('someTextToUseInAQuery', getAllByLabelText); + `, + + `// edge case for coverage: + // valid use case without call expression + // so there is no innermost function scope found + await test('edge case for no innermost function scope', () => { + const foo = getAllByLabelText + }) + `, ], invalid: [