From f633800f4d63d0c0023bace4f955c4a2869d362b Mon Sep 17 00:00:00 2001 From: TheDiveO <6920158+thediveo@users.noreply.github.com> Date: Mon, 19 Sep 2022 19:47:31 +0200 Subject: [PATCH] introduces Eventually.Within.ProbeEvery with tests and documentation (#591) --- docs/index.md | 3 ++- internal/async_assertion.go | 10 ++++++++++ internal/async_assertion_test.go | 22 +++++++++++++++++++++- types/types.go | 8 +++++--- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/docs/index.md b/docs/index.md index 277055627..4c4881001 100644 --- a/docs/index.md +++ b/docs/index.md @@ -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: diff --git a/internal/async_assertion.go b/internal/async_assertion.go index 126bbcb3f..6a587969f 100644 --- a/internal/async_assertion.go +++ b/internal/async_assertion.go @@ -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...) diff --git a/internal/async_assertion_test.go b/internal/async_assertion_test.go index 1bedfdf58..3d555670b 100644 --- a/internal/async_assertion_test.go +++ b/internal/async_assertion_test.go @@ -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() { @@ -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") diff --git a/types/types.go b/types/types.go index c315ef065..3174a1346 100644 --- a/types/types.go +++ b/types/types.go @@ -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{}) @@ -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) @@ -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