Skip to content

Expose structured tap failure reasons #150

@passsy

Description

@passsy

Problem

Tests sometimes need to assert that a tap failed for a semantic reason, for example because the target widget is inside an IgnorePointer.
Today the public signal for that case is the human-readable TestFailure.message.
That makes tests couple themselves to Spot's diagnostic prose, so a wording improvement can break users even when the behavior is unchanged.

Current workaround

await expectLater(
  () => act.tap(spot<SaveButton>()),
  throwsA(
    isA<TestFailure>().having(
      (error) => error.message,
      'message',
      contains('is wrapped in IgnorePointer'),
    ),
  ),
);

This proves the behavior, but it treats the error message as API.
It also makes it hard to distinguish intentional behavior assertions from brittle text snapshots.

Possible API

await expectLater(
  () => act.tap(spot<SaveButton>()),
  throwsSpotTapFailure(reason: SpotTapFailureReason.ignorePointer),
);

An alternative would be a non-throwing tap API that returns structured failure details.

final result = await act.tryTap(spot<SaveButton>());
expect(result.reason, SpotTapFailureReason.ignorePointer);

The exact shape is flexible.
The important part is that tests can assert the machine-readable reason while Spot remains free to improve the human-readable diagnostic message.

Reason examples

  • ignorePointer
  • absorbedPointer
  • offstage
  • notHitTestable
  • partiallyHitTestable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions