Quick / Nimble

A Matcher Framework for Swift and Objective-C
https://quick.github.io/Nimble/documentation/nimble/
Apache License 2.0
4.81k stars 598 forks source link

Allow usage of toEventually with async expressions #1039

Closed younata closed 1 year ago

younata commented 1 year ago

Changes to the readme also documents this.

basically, this now allows the following code:

await expect { await someAsyncFunction() }.toEventually(equal(someValue))

await expecta(await someAsyncFunction()).to(equal(someValue))

toEventually will continuously call (and wait for) the expression passed in to evaluate, it's just now compatible with async expressions. It does kick off a new task each time it polls. This is due to the fact that toEventually uses dispatch queues under the hood, and dispatch queues are always synchronous contexts. If the expression you're verifying needs to run on the main thread, you'll likely have to force it to do so. Either by marking the test itself as running on the main thread, or by marking the expression as running on the main thread, like so:

@MainActor func test_something() async {
    await expect { await someFunctionThatMustRunOnTheMainThread() }.toEventually(equal(someValue))
}

func test_something() async {
    await expect { @MainActor in await someFunctionThatMustRunOnTheMainThread() }.toEventually(equal(someValue))
}

Predicates are unchanged. This implementation converts the async expression to a synchronous expression as part of the to/toNot/toEventually ... call. This does mean that a large amount of operator overloads are now duplicated, because we need to do the awaiting as part of the operator, and this change does break operator overloads for anyone else using this.