Skip to content

fix: handled promises assigned to vars are valid #1047

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/rules/await-async-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getFunctionName,
getInnermostReturningFunction,
getVariableReferences,
isCallExpression,
isObjectPattern,
isPromiseHandled,
isProperty,
Expand Down Expand Up @@ -110,6 +111,8 @@ export default createTestingLibraryRule<Options, MessageIds>({
const isAssigningKnownAsyncFunctionWrapper =
ASTUtils.isIdentifier(node.id) &&
node.init !== null &&
!isCallExpression(node.init) &&
!ASTUtils.isAwaitExpression(node.init) &&
functionWrappersNames.includes(
getDeepestIdentifierNode(node.init)?.name ?? ''
);
Expand Down
106 changes: 106 additions & 0 deletions tests/lib/rules/await-async-events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
})),
Expand Down Expand Up @@ -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')));
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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()
Expand Down
17 changes: 17 additions & 0 deletions tests/lib/rules/await-async-queries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
40 changes: 40 additions & 0 deletions tests/lib/rules/await-async-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
});
`,
})),
{
Expand Down Expand Up @@ -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',
Expand Down