Skip to content

Add support for collapsed error messages#2651

Draft
natebosch wants to merge 1 commit into
masterfrom
collapse-failure-messages
Draft

Add support for collapsed error messages#2651
natebosch wants to merge 1 commit into
masterfrom
collapse-failure-messages

Conversation

@natebosch
Copy link
Copy Markdown
Member

@natebosch natebosch commented May 20, 2026

Checks against a subject are commonly nested against some other subject,
for example the check for an exact list length is in practice an
equals expectation checked against an integer which is the "has
length" subject, nested under the subject holding the list instance.
Failure messages have a rigid structure that represents this nesting
pattern and always indent the "clauses" (the descriptions of what was
checked in expectations) following the "label" which describes subject.

For very simple conditions the noise of the structure is greater than
the signal of the description output by the specific failing
expectation. For instance a trivial check for an future completing to an
expected value looks like:

  Expected: a Future<List<int>> that:
    completes to a value that:
      is not empty
  Actual: a Future<List<int>> that:
    completes to a value that:
    Actual: []
    Which: is empty

Add support for collapsing this to.

  Expected: a Future<List<int>> that completes to a non-empty iterable
  Actual: a Future<List<int>> that completes to []
  Which: is empty

Add a predicateNoun callback argument to expect, expectAsync, and
expectUnawaited. Extensions must pass a callback which provides the
"clause" representation like "is empty". Now they may also pass a
callback which provides a predicate noun formed by combining the
clause with a noun for the subject like "an empty iterable".

Add a addPredicate callback argument to nest, and nestAsync.
Extensions must pass a callback which provides a label for the value
they are deriving from the original subject like "completes to a value".
Now they may also pass a callback which takes a collapsed form of the
noun as described by nested conditions, and attaches the predicate it
contributes.

Check for possibilities to collapse failure messages down to predicate
nouns when generating failure messages.

Add predicate noun callbacks to existing extensions where sensible.
Tweak some wording where I noticed inconsistencies.

Use of these new arguments is completely optional for extension
implementations and impacts only the failure message formatting which is
not considered a breaking change.

The user impact is that many simple expectation failures will be more
compact and readable, but the position of the failing expectation in
a series of cascaded expectations may cause a significantly different
output for the same checks usage. It has always been the case that
expectations which follow a failure have no impact on the output,
because they are never reached to run. Now when the first expectation in
a series has a collapsible representation it's failure triggers an
overall collapsed format which will read differently to the expanded
format if any condition other than the first fails.

@github-actions github-actions Bot added the package:checks Issues related to pkg:checks label May 20, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 20, 2026

PR Health

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

This check can be disabled by tagging the PR with skip-changelog-check.

@natebosch natebosch force-pushed the collapse-failure-messages branch 6 times, most recently from dccf79c to ccbd58e Compare May 20, 2026 03:14
Checks against a subject are commonly nested against some other subject,
for example the check for an exact list length is in practice an
`equals` expectation checked against an integer which is the "has
length" subject, nested under the subject holding the list instance.
Failure messages have a rigid structure that represents this nesting
pattern and always indent the "clauses" (the descriptions of what was
checked in expectations) following the "label" which describes subject.

For very simple conditions the noise of the structure is greater than
the signal of the description output by the specific failing
expectation. For instance a trivial check for an future completing to an
expected value looks like:

```
  Expected: a Future<List<int>> that:
    completes to a value that:
      is not empty
  Actual: a Future<List<int>> that:
    completes to a value that:
    Actual: []
    Which: is empty
```

Add support for collapsing this to.

```
  Expected: a Future<List<int>> that completes to a non-empty iterable
  Actual: a Future<List<int>> that completes to []
  Which: is empty
```

Add a `predicateNoun` callback argument to `expect`, `expectAsync`, and
`expectUnawaited`. Extensions must pass a callback which provides the
"clause" representation like "is empty". Now they may also pass a
callback which provides a predicate noun formed by combining the
clause with a noun for the subject like "an empty iterable".

Add a `addPredicate` callback argument to `nest`, and `nestAsync`.
Extensions must pass a callback which provides a label for the value
they are deriving from the original subject like "completes to a value".
Now they may also pass a callback which takes a collapsed form of the
noun as described by nested conditions, and attaches the predicate it
contributes.

Check for possibilities to collapse failure messages down to predicate
nouns when generating failure messages.

Add predicate noun callbacks to existing extensions where sensible.
Tweak some wording where I noticed inconsistencies.

Use of these new arguments is completely optional for extension
implementations and impacts only the failure message formatting which is
not considered a breaking change.

The user impact is that many simple expectation failures will be more
compact and readable, but the position of the failing expectation in
a series of cascaded expectations may cause a significantly different
output for the same checks usage. It has always been the case that
expectations which follow a failure have no impact on the output,
because they are never reached to run. Now when the first expectation in
a series has a collapsible representation it's failure triggers an
overall collapsed format which will read differently to the expanded
format if any condition other than the first fails.
@natebosch natebosch force-pushed the collapse-failure-messages branch from ccbd58e to bd2f609 Compare May 20, 2026 03:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package:checks Issues related to pkg:checks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant