oxc-project/oxc · warning

Expect in a promise chain must be awaited or returned

Error message

Expect in a promise chain must be awaited or returned

What it means

Diagnostic from the shared jest/vitest `valid-expect-in-promise` rule (expect_in_unhandled_promise). It fires when an `expect()` call lives inside a `.then()`/`.catch()`/`.finally()` callback of a promise that is neither awaited nor returned from the test. The test function returns before the callback runs, so failures vanish and the test is a false pass.

Source

Thrown at crates/oxc_linter/src/rules/shared/jest_vitest/valid_expect_in_promise.rs:21

    AstKind,
    ast::{
        Argument, CallExpression, Expression, FunctionBody, MemberExpression,
        SimpleAssignmentTarget, Statement,
    },
};
use oxc_ast_visit::{VisitJs, walk_js};
use oxc_diagnostics::OxcDiagnostic;
use oxc_span::{GetSpan, Span};
use oxc_str::CompactStr;
use rustc_hash::{FxHashMap, FxHashSet};

use crate::{
    context::LintContext,
    utils::{JestGeneralFnKind, PossibleJestNode, get_node_name_vec, parse_general_jest_fn_call},
};

fn expect_in_unhandled_promise(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Expect in a promise chain must be awaited or returned")
        .with_help("Either `await` the promise, `return` it, or use `expect().resolves`/`expect().rejects`.")
        .with_label(span)
}

fn expect_in_promise_after_return(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Expect in a promise chain is unreachable after a `return` statement")
        .with_help("Move the promise before the `return` and ensure it is awaited or returned.")
        .with_label(span)
}

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

Ensures that `expect` calls inside promise chains (`.then()`, `.catch()`,
`.finally()`) are properly awaited or returned from the test.

### Why is this bad?

When `expect` is called inside a promise callback that is not awaited or

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Make the test async and `await` the chain: `it('x', async () => { await fetchData().then((d) => expect(d).toBe(1)); });`.
  2. Or `return` the chain from the test: `return fetchData().then(...)`.
  3. Or drop the chain: `const d = await fetchData(); expect(d).toBe(1);`.
  4. For promise assertions use `await expect(p).resolves.toBe(1)` / `.rejects` instead of .then/.catch wrappers.

Example fix

// before
it('loads', () => {
  fetchData().then((data) => expect(data.length).toBe(1));
});

// after
it('loads', async () => {
  const data = await fetchData();
  expect(data.length).toBe(1);
});
Defensive patterns

Strategy: validation

Validate before calling

// detect expect inside then/catch/finally callbacks
const floating = /\.(then|catch|finally)\s*\(\s*\(?[^)]*\)?\s*=>\s*(\{[^}]*|)expect\s*\(/;
if (floating.test(src)) console.warn('expect() inside a promise chain callback — await or return it');

Prevention

When it happens

Trigger: The rule parses general jest function calls (test/it handlers) and inspects promise-chain member expressions; when an expect sits in the callback and the chain is floating, this diagnostic is emitted. Examples: `it('x', () => { fetchData().then((d) => expect(d).toBe(1)); });` or `.catch(() => expect(err).toBeDefined());` without await/return.

Common situations: Legacy promise-chain tests written before async/await, tests where a refactor removed `return` from `return promise.then(...)`, and fire-and-forget `.catch` handlers that swallow assertion errors.

Related errors


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