diff --git a/lib/rules/await-async-utils.ts b/lib/rules/await-async-utils.ts index 74cb382d..f26bd958 100644 --- a/lib/rules/await-async-utils.ts +++ b/lib/rules/await-async-utils.ts @@ -7,6 +7,7 @@ import { getFunctionName, getInnermostReturningFunction, getVariableReferences, + isCallExpression, isObjectPattern, isPromiseHandled, isProperty, @@ -110,6 +111,8 @@ export default createTestingLibraryRule({ const isAssigningKnownAsyncFunctionWrapper = ASTUtils.isIdentifier(node.id) && node.init !== null && + !isCallExpression(node.init) && + !ASTUtils.isAwaitExpression(node.init) && functionWrappersNames.includes( getDeepestIdentifierNode(node.init)?.name ?? '' ); diff --git a/tests/lib/rules/await-async-events.test.ts b/tests/lib/rules/await-async-events.test.ts index 0548e618..01de4d16 100644 --- a/tests/lib/rules/await-async-events.test.ts +++ b/tests/lib/rules/await-async-events.test.ts @@ -134,6 +134,21 @@ ruleTester.run(RULE_NAME, rule, { await triggerEvent() }) + `, + options: [{ eventModule: 'fireEvent' }] as const, + })), + ...FIRE_EVENT_ASYNC_FUNCTIONS.map((eventMethod) => ({ + code: ` + import { fireEvent } from '${testingFramework}' + test('await promise assigned to a variable from function wrapping event method is valid', () => { + function triggerEvent() { + doSomething() + return fireEvent.${eventMethod}(getByLabelText('username')) + } + + const result = await triggerEvent() + expect(result).toBe(undefined) + }) `, options: [{ eventModule: 'fireEvent' }] as const, })), @@ -364,6 +379,21 @@ ruleTester.run(RULE_NAME, rule, { ...USER_EVENT_ASYNC_FUNCTIONS.map((eventMethod) => ({ code: ` import userEvent from '${testingFramework}' + test('await promise assigned to a variable from function wrapping event method is valid', () => { + function triggerEvent() { + doSomething() + return userEvent.${eventMethod}(getByLabelText('username')) + } + + const result = await triggerEvent() + expect(result).toBe(undefined) + }) + `, + options: [{ eventModule: 'userEvent' }] as const, + })), + ...USER_EVENT_ASYNC_FUNCTIONS.map((eventMethod) => ({ + code: ` + import userEvent from '${testingFramework}' test('await expression that evaluates to promise is valid', async () => { await (null, userEvent.${eventMethod}(getByLabelText('username'))); await (condition ? null : userEvent.${eventMethod}(getByLabelText('username'))); @@ -775,6 +805,44 @@ ruleTester.run(RULE_NAME, rule, { ({ code: ` import { fireEvent } from '${testingFramework}' + test('unhandled promise assigned to a variable returned from function wrapping event method is invalid', () => { + function triggerEvent() { + doSomething() + return fireEvent.${eventMethod}(getByLabelText('username')) + } + + const result = triggerEvent() + expect(result).toBe(undefined) + }) + `, + errors: [ + { + line: 9, + column: 24, + messageId: 'awaitAsyncEventWrapper', + data: { name: 'triggerEvent' }, + }, + ], + options: [{ eventModule: 'fireEvent' }], + output: ` + import { fireEvent } from '${testingFramework}' + test('unhandled promise assigned to a variable returned from function wrapping event method is invalid', async () => { + function triggerEvent() { + doSomething() + return fireEvent.${eventMethod}(getByLabelText('username')) + } + + const result = await triggerEvent() + expect(result).toBe(undefined) + }) + `, + }) as const + ), + ...FIRE_EVENT_ASYNC_FUNCTIONS.map( + (eventMethod) => + ({ + code: ` + import { fireEvent } from '${testingFramework}' function triggerEvent() { doSomething() @@ -977,6 +1045,44 @@ ruleTester.run(RULE_NAME, rule, { ({ code: ` import userEvent from '${testingFramework}' + test('unhandled promise assigned to a variable returned from function wrapping event method is invalid', function() { + function triggerEvent() { + doSomething() + return userEvent.${eventMethod}(getByLabelText('username')) + } + + const result = triggerEvent() + expect(result).toBe(undefined) + }) + `, + errors: [ + { + line: 9, + column: 24, + messageId: 'awaitAsyncEventWrapper', + data: { name: 'triggerEvent' }, + }, + ], + options: [{ eventModule: 'userEvent' }], + output: ` + import userEvent from '${testingFramework}' + test('unhandled promise assigned to a variable returned from function wrapping event method is invalid', async function() { + function triggerEvent() { + doSomething() + return userEvent.${eventMethod}(getByLabelText('username')) + } + + const result = await triggerEvent() + expect(result).toBe(undefined) + }) + `, + }) as const + ), + ...USER_EVENT_ASYNC_FUNCTIONS.map( + (eventMethod) => + ({ + code: ` + import userEvent from '${testingFramework}' function triggerEvent() { doSomething() diff --git a/tests/lib/rules/await-async-queries.test.ts b/tests/lib/rules/await-async-queries.test.ts index dfbc6008..8354d346 100644 --- a/tests/lib/rules/await-async-queries.test.ts +++ b/tests/lib/rules/await-async-queries.test.ts @@ -291,6 +291,23 @@ ruleTester.run(RULE_NAME, rule, { `, })), + // handled promise assigned to variable returned from async query wrapper is valid + ...ALL_ASYNC_COMBINATIONS_TO_TEST.map( + (query) => + ({ + code: ` + const queryWrapper = () => { + return screen.${query}('foo') + } + + test("A valid example test", async () => { + const element = await queryWrapper() + expect(element).toBeVisible() + }) + `, + }) as const + ), + // non-matching query is valid ` test('A valid example test', async () => { diff --git a/tests/lib/rules/await-async-utils.test.ts b/tests/lib/rules/await-async-utils.test.ts index 8f23bbf3..e018a223 100644 --- a/tests/lib/rules/await-async-utils.test.ts +++ b/tests/lib/rules/await-async-utils.test.ts @@ -250,6 +250,20 @@ ruleTester.run(RULE_NAME, rule, { test('handled promise from function wrapping ${asyncUtil} util is valid', async () => { await waitForSomethingAsync() }); + `, + })), + ...ASYNC_UTILS.map((asyncUtil) => ({ + code: ` + import { ${asyncUtil} } from '${testingFramework}'; + + function waitForSomethingAsync() { + return ${asyncUtil}(() => somethingAsync()) + } + + test('handled promise in variable declaration from function wrapping ${asyncUtil} util is valid', async () => { + const result = await waitForSomethingAsync() + expect(result).toBe('foo') + }); `, })), { @@ -506,6 +520,32 @@ ruleTester.run(RULE_NAME, rule, { (asyncUtil) => ({ code: ` + import { ${asyncUtil}, render } from '${testingFramework}'; + + function waitForSomethingAsync() { + return ${asyncUtil}(() => somethingAsync()) + } + + test('unhandled promise in variable declaration from function wrapping ${asyncUtil} util is invalid', async () => { + render() + const result = waitForSomethingAsync() + expect(result).toBe('foo') + }); + `, + errors: [ + { + messageId: 'asyncUtilWrapper', + line: 10, + column: 24, + data: { name: 'waitForSomethingAsync' }, + }, + ], + }) as const + ), + ...ASYNC_UTILS.map( + (asyncUtil) => + ({ + code: ` import { ${asyncUtil} } from 'some-other-library'; // rather than ${testingFramework} test( 'aggressive reporting - util "${asyncUtil}" which is not related to testing library is invalid',