Skip to content

Commit 67ab22c

Browse files
committed
Simplify StopTrying handling
- StopTrying now always signifies a failure - StopTrying(message).Wrap(err) can wrap an error - STopTrying(message).Attach(description, object) can attach arbitrary objects to the error report. These are rendered with Gomega's default formatter.
1 parent 75c8c70 commit 67ab22c

File tree

5 files changed

+398
-426
lines changed

5 files changed

+398
-426
lines changed

docs/index.md

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -492,24 +492,23 @@ When no explicit duration is provided, `Consistently` will use the default durat
492492
493493
### Bailing Out Early - Polling Functions
494494

495-
There are cases where you need to signal to `Eventually` and `Consistently` that they should stop trying. Gomega provides`StopTrying(format string, args ...any)` to allow you to send that signal. There are two ways to use `StopTrying`.
495+
There are cases where you need to signal to `Eventually` and `Consistently` that they should stop trying. Gomega provides`StopTrying(message string)` to allow you to send that signal. There are two ways to use `StopTrying`.
496496

497497
First, you can return `StopTrying` as an error. Consider, for example, the case where `Eventually` is searching through a set of possible queries with a server:
498498

499499
```go
500500
playerIndex, numPlayers := 0, 11
501501
Eventually(func() (string, error) {
502-
name := client.FetchPlayer(playerIndex)
503-
playerIndex += 1
504502
if playerIndex == numPlayers {
505-
return name, StopTrying("No more players left")
506-
} else {
507-
return name, nil
503+
return "", StopTrying("no more players left")
508504
}
505+
name := client.FetchPlayer(playerIndex)
506+
playerIndex += 1
507+
return name, nil
509508
}).Should(Equal("Patrick Mahomes"))
510509
```
511510

512-
Here we return a `StopTrying` error to tell `Eventually` that we've looked through all possible players and that it should stop. Note that `Eventually` will check last name returned by this function and succeed if that name is the desired name.
511+
Here we return a `StopTrying` error to tell `Eventually` that we've looked through all possible players and that it should stop.
513512

514513
You can also call `StopTrying(...).Now()` to immediately end execution of the function. Consider, for example, the case of a client communicating with a server that experiences an irrevocable error:
515514

@@ -523,35 +522,25 @@ Eventually(func() []string {
523522
}).Should(ContainElement("Patrick Mahomes"))
524523
```
525524

526-
calling `.Now()` will trigger a panic that will signal to `Eventually` that the it should stop trying.
525+
calling `.Now()` will trigger a panic that will signal to `Eventually` that it should stop trying.
527526

528-
You can also use both verison of `StopTrying()` with `Consistently`. Since `Consistently` is validating that something is _true_ consitently for the entire requested duration sending a `StopTrying()` signal is interpreted as success. Here's a somewhat contrived example:
527+
You can also return `StopTrying()` errors and use `StopTrying().Now()` with `Consistently`.
529528

530-
```go
531-
go client.DoSomethingComplicated()
532-
Consistently(func() int {
533-
if client.Status() == client.DoneStatus {
534-
StopTrying("Client finished").Now()
535-
}
536-
return client.NumErrors()
537-
}).Should(Equal(0))
538-
```
529+
Both `Eventually` and `Consistently` always treat the `StopTrying()` signal as a failure. The failure message will include the message passed in to `StopTrying()`.
539530

540-
here we succeed because no errors were identified while the client was working.
531+
You can add additional information to this failure message in a few ways. You can wrap an error via `StopTrying(message).Wrap(wrappedErr)` - now the output will read `<message>: <wrappedErr.Error()>`.
541532

542-
`StopTrying` also allows you wrap an error using the `%w` verb. For example:
533+
You can also attach arbitrary objects to `StopTrying()` via `StopTrying(message).Attach(description string, object any)`. Gomega will run the object through Gomega's standard formatting library to build a consistent representation for end users. You can attach multiple objects in this way and the output will look like:
543534

544-
```go
545-
Eventually(func() []string {
546-
names, err := client.FetchAllPlayers()
547-
if err == client.TOKEN_EXPIRED || err == client.SEVER_GONE {
548-
StopTrying("An irrecoverable error occurred: %w", err).Now()
549-
}
550-
return names
551-
}).Should(ContainElement("Patrick Mahomes"))
552535
```
536+
Told to stop trying after <X>
553537
554-
Wrapping an error in this way allows you to simultaneously signal that `Eventually` should stop trying _and_ that the assertion should count as a failure regardless of the state of the match when `StopTrying` is returned/thrown.
538+
<message>: <wrappedErr.Error()>
539+
<description>:
540+
<formatted-object>
541+
<description>:
542+
<formatted-object>
543+
```
555544

556545
### Bailing Out Early - Matchers
557546

@@ -561,9 +550,9 @@ Just like functions being polled, matchers can also indicate if `Eventually`/`Co
561550
Match(actual interface{}) (success bool, err error)
562551
```
563552

564-
If a matcher returns `StopTrying` for `error`, or calls `StopTrying(...).Now()`, `Eventually` and `Consistently` will stop polling and use the returned value of `success` to determine if the match succeeded or not. To signal that the `success` values should wrap an error via `StopTrying("<reason>: %w", err)`.
553+
If a matcher returns `StopTrying` for `error`, or calls `StopTrying(...).Now()`, `Eventually` and `Consistently` will stop polling and fail: `StopTrying` **always** signifies a failure.
565554

566-
> Note: An older mechanism for doing this is documented in the [custom matchers section below](#aborting-eventuallyconsistently)
555+
> Note: An alternative mechanism for having matchers bail out early is documented in the [custom matchers section below](#aborting-eventuallyconsistently). This mechanism, which entails implementing a `MatchMayChangeIntheFuture(<actual>) bool` method, allows matchers to signify that no future change is possible out-of-band of the call to the matcher.
567556
568557
### Modifying Default Intervals
569558

0 commit comments

Comments
 (0)