oxc-project/oxc · warning

Promises which return async assertions must be awaited.

Error message

Promises which return async assertions must be awaited.

What it means

Diagnostic from the shared jest/vitest `valid-expect` rule (Message::PromisesWithAsyncAssertionsMustBeAwaited). It is the chained variant of the await check: the async assertion sits inside or at the end of a `.then()`/`.catch()` (or Promise.all-style) chain, and that whole chain is floating — not awaited or returned — so the assertion may never execute.

Source

Thrown at crates/oxc_linter/src/rules/shared/jest_vitest/valid_expect.rs:23

use oxc_semantic::ScopeId;
use oxc_span::{GetSpan, Span};
use rustc_hash::FxHashSet;
use schemars::JsonSchema;

use crate::{
    AstNode,
    context::LintContext,
    utils::{
        ExpectError, PossibleJestNode, collect_possible_jest_call_node, parse_expect_jest_fn_call,
    },
};

fn valid_expect_diagnostic<S: Into<Cow<'static, str>>>(
    x1: S,
    x2: &'static str,
    span3: Span,
) -> OxcDiagnostic {
    OxcDiagnostic::warn(x1).with_help(x2).with_label(span3)
}

pub const DOCUMENTATION: &str = r"### What it does

Checks that `expect()` is called correctly.

### Why is this bad?

`expect()` is a function that is used to assert values in tests.
It should be called with a single argument, which is the value to be tested.
If you call `expect()` with no arguments, or with more than one argument, it will not work as expected.

### Examples

Examples of **incorrect** code for this rule:
```javascript
expect();
expect('something');

View on GitHub (pinned to e1e7af627c)

Solutions

  1. `await` (or `return`) the entire chain: `await Promise.resolve().then(() => expect(p).resolves.toBe(1));`.
  2. Better: rewrite the chain as `await expect(p).resolves.toBe(1)` directly, dropping the then/catch wrapper.
  3. Move the assertion out of the callback and assert on the awaited result: `const v = await p; expect(v).toBe(1);`.
  4. Run `oxlint --fix`; the rule's multifix adds `await` and `async` where safe.

Example fix

// before
it('works', () => {
  Promise.resolve(2).then((v) => expect(Promise.resolve(v)).resolves.toBe(2));
});

// after
it('works', async () => {
  await Promise.resolve(2).then((v) => expect(Promise.resolve(v)).resolves.toBe(2));
});
Defensive patterns

Strategy: validation

Validate before calling

// flag expect() inside .then/.catch callbacks that are not awaited/returned
const bad = /(^|[^.\w])(return\s+)?\w+\.(then|catch)\([^)]*=>\s*\{?\s*expect\(/;
if (bad.test(sourceOfTestFile)) console.warn('assertion inside a floating promise chain');

Prevention

When it happens

Trigger: `get_parent_if_thenable`/`find_promise_call_expression_node` walk past `then`/`catch` links; when the final chain node differs from the assertion node (`target_node.id() != final_node.id()`) and the chain's parent is not an acceptable await/return position, this message is emitted. Examples: `Promise.resolve().then(() => expect(p).resolves.toBe(1));`, or `promise.catch(() => expect(x).toResolve());` left as a statement.

Common situations: Refactoring `promise.then(...)`-style tests into modern async/await without deleting the chain; assertions appended inside `.catch()` callbacks for error-path checks; Promise.race/all wrappers around async assertions.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/b534128118d6074a. Report an issue: GitHub.