Skip to content

Commit

Permalink
introduces Eventually.Within.ProbeEvery with tests and documentation (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
thediveo authored Sep 19, 2022
1 parent fb586b3 commit f633800
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 5 deletions.
3 changes: 2 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,11 @@ The first optional argument is the timeout (which defaults to 1s), the second is

> As with synchronous assertions, you can annotate asynchronous assertions by passing either a format string and optional inputs or a function of type `func() string` after the `GomegaMatcher`.
Alternatively, the timeout and polling interval can also be specified by chaining `WithTimeout` and `WithPolling` to `Eventually`:
Alternatively, the timeout and polling interval can also be specified by chaining `Within` and `ProbeEvery` or `WithTimeout` and `WithPolling` to `Eventually`:

```go
Eventually(ACTUAL).WithTimeout(TIMEOUT).WithPolling(POLLING_INTERVAL).Should(MATCHER)
Eventually(ACTUAL).Within(TIMEOUT).ProbeEvery(POLLING_INTERVAL).Should(MATCHER)
```

Eventually works with any Gomega compatible matcher and supports making assertions against three categories of `ACTUAL` value:
Expand Down
10 changes: 10 additions & 0 deletions internal/async_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ func (assertion *AsyncAssertion) WithPolling(interval time.Duration) types.Async
return assertion
}

func (assertion *AsyncAssertion) Within(timeout time.Duration) types.AsyncAssertion {
assertion.timeoutInterval = timeout
return assertion
}

func (assertion *AsyncAssertion) ProbeEvery(interval time.Duration) types.AsyncAssertion {
assertion.pollingInterval = interval
return assertion
}

func (assertion *AsyncAssertion) Should(matcher types.GomegaMatcher, optionalDescription ...interface{}) bool {
assertion.g.THelper()
vetOptionalDescription("Asynchronous assertion", optionalDescription...)
Expand Down
22 changes: 21 additions & 1 deletion internal/async_assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@ var _ = Describe("Asynchronous Assertions", func() {
Ω(ig.FailureMessage).Should(ContainSubstring("positive: no match"))
Ω(ig.FailureSkip).Should(Equal([]int{3}))
})

It("maps Within() correctly to timeout and polling intervals", func() {
counter := 0
ig.G.Eventually(func() bool {
counter++
return false
}).WithTimeout(0).WithPolling(20 * time.Millisecond).Within(200 * time.Millisecond).Should(BeTrue())
Ω(counter).Should(BeNumerically(">", 2))
Ω(counter).Should(BeNumerically("<", 20))

counter = 0
ig.G.Eventually(func() bool {
counter++
return false
}).WithTimeout(0).WithPolling(0). // first zero intervals, then set them
Within(200 * time.Millisecond).ProbeEvery(20 * time.Millisecond).
Should(BeTrue())
Ω(counter).Should(BeNumerically(">", 2))
Ω(counter).Should(BeNumerically("<", 20))
})
})

Context("the negative case", func() {
Expand Down Expand Up @@ -309,7 +329,7 @@ var _ = Describe("Asynchronous Assertions", func() {
})
})

Context("when passed a function that takes no arguments and returns mutliple values", func() {
Context("when passed a function that takes no arguments and returns multiple values", func() {
Context("with Eventually", func() {
It("polls the function until the first returned value satisfies the matcher _and_ all additional values are zero", func() {
counter, s, f, err := 0, "hi", Foo{Bar: "hi"}, errors.New("hi")
Expand Down
8 changes: 5 additions & 3 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

type GomegaFailHandler func(message string, callerSkip ...int)

//A simple *testing.T interface wrapper
// A simple *testing.T interface wrapper
type GomegaTestingT interface {
Helper()
Fatalf(format string, args ...interface{})
Expand All @@ -30,9 +30,9 @@ type Gomega interface {
SetDefaultConsistentlyPollingInterval(time.Duration)
}

//All Gomega matchers must implement the GomegaMatcher interface
// All Gomega matchers must implement the GomegaMatcher interface
//
//For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding-your-own-matchers
// For details on writing custom matchers, check out: http://onsi.github.io/gomega/#adding-your-own-matchers
type GomegaMatcher interface {
Match(actual interface{}) (success bool, err error)
FailureMessage(actual interface{}) (message string)
Expand Down Expand Up @@ -70,6 +70,8 @@ type AsyncAssertion interface {
WithOffset(offset int) AsyncAssertion
WithTimeout(interval time.Duration) AsyncAssertion
WithPolling(interval time.Duration) AsyncAssertion
Within(timeout time.Duration) AsyncAssertion
ProbeEvery(interval time.Duration) AsyncAssertion
}

// Assertions are returned by Ω and Expect and enable assertions against Gomega matchers
Expand Down

0 comments on commit f633800

Please sign in to comment.