Skip to content

prefer_expect_later

v0.4.0 Warning Fix Testing Rules

Flags an expect() call whose first argument is a Future. Nothing awaits a plain expect, so the test method returns before the future resolves and the assertion’s outcome is never seen.

loadCart() returns a Future. The test body is synchronous, so it finishes immediately and passes whatever the future eventually produces — including a failure:

void main() {
test('loads the cart', () {
expect(loadCart(), completion(isNotNull));
});
}
Future<Object?> loadCart() async => null;

The same hole when the future is held in a variable first — the rule reads the static type, not the shape of the expression:

void main() {
test('totals the cart', () {
final total = cartTotal();
expect(total, completion(equals(240)));
});
}
Future<int> cartTotal() async => 240;

await expectLater(...) in an async body. The test now waits for the future and the matcher runs against its value:

void main() {
test('loads the cart', () async {
await expectLater(loadCart(), completion(isNotNull));
});
test('totals the cart', () async {
final total = cartTotal();
await expectLater(total, completion(equals(240)));
});
}
Future<Object?> loadCart() async => null;
Future<int> cartTotal() async => 240;

Awaiting the value instead is equally correct, and often reads better — the matcher then describes the resolved value rather than the future:

void main() {
test('totals the cart', () async {
expect(await cartTotal(), equals(240));
});
}
Future<int> cartTotal() async => 240;

expect is only a problem when the actual value is a Future. A plain value needs no change:

void main() {
test('sums the lines', () {
expect(subtotal(), equals(240));
});
}
int subtotal() => 240;

The rule also reports expect only — an expectLater you already wrote is left alone, awaited or not.

See also: test package - expectLater

This rule is in the core preset, so it is on with preset: core, preset: recommended or preset: opinionated.

To turn it off:

many_lints.yaml
rules:
prefer_expect_later: false

To keep the rule on but skip certain paths, use per-rule exclude.