Asynchronous Assertion Not Awaited

ID

javascript.async_assertion_not_awaited

Severity

critical

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

JavaScript

Tags

assertion, async, reliability, testing

Description

Reports an asynchronous assertion written as a bare statement inside a test: an expect(…​).resolves or expect(…​).rejects chain, or a Testing Library waitFor(…​). All of these return a promise and do their checking on a later turn of the event loop, so a statement that neither awaits nor returns that promise lets the test function finish first.

Only a discarded result is reported. An await, a return, an assignment, a .then() continuation and an argument position such as Promise.all([…​]) all hand the promise to code that can settle it.

An expect(…​) carrying a promise modifier but no matcher at all is left to javascript.assertions_complete, which reports the missing matcher.

Rationale

// Bad
it('rejects an empty cart', async () => {
  expect(charge([])).rejects.toThrow('empty');   // starts checking, waits for nothing
  waitFor(() => expect(receipt).toBeVisible());  // polls into the void
});
  • The test is recorded as passed before either assertion has a verdict, so it is green whatever the code under test does.

  • When the assertion does fail, the rejection has no owner: it surfaces as an unhandled rejection charged to whichever test is running by then, or is swallowed entirely.

  • Because both lines read exactly like the awaited form, nothing in review or in the diff points at the missing keyword.

  • The gap survives every later reading of the file, since the test’s title still claims the behaviour is covered.

Remediation

Await the promise, or return it so the runner awaits it.

// Good
it('rejects an empty cart', async () => {
  await expect(charge([])).rejects.toThrow('empty');
  await waitFor(() => expect(receipt).toBeVisible());
});

© 2026 Xygeni. All rights reserved