Skip to content

Instantly share code, notes, and snippets.

@CassiusPacheco
Last active September 1, 2022 08:30
Show Gist options
  • Save CassiusPacheco/4353b7655595af254a14b7270bf29f64 to your computer and use it in GitHub Desktop.
Save CassiusPacheco/4353b7655595af254a14b7270bf29f64 to your computer and use it in GitHub Desktop.
toBlocking equivalent for Combine's Publishers
extension Publisher {
func waitForCompletion(timeout: TimeInterval = 1.0, file: StaticString = #file, line: UInt = #line) throws -> [Output] {
let expectation = XCTestExpectation(description: "wait for completion")
var completion: Subscribers.Completion<Failure>?
var output = [Output]()
let subscription = self.collect()
.sink(receiveCompletion: { receiveCompletion in
completion = receiveCompletion
expectation.fulfill()
}, receiveValue: { value in
output = value
})
XCTWaiter().wait(for: [expectation], timeout: timeout)
subscription.cancel()
switch try XCTUnwrap(completion, "Publisher never completed", file: file, line: line) {
case let .failure(error):
throw error
case .finished:
return output
}
}
func waitForFirstOutput(timeout: TimeInterval = 1.0, file: StaticString = #file, line: UInt = #line) throws -> Output {
return try XCTUnwrap(prefix(1).waitForCompletion(file: file, line: line).first, "", file: file, line: line)
}
}
@samwize
Copy link

samwize commented Sep 1, 2022

Nice gist. I read your blog https://cassiuspacheco.com/synchronising-combines-publishers-for-easy-testing. But your example don't work, because you set current.value = 2 before subscribing. Maybe subject behaviour changed since you wrote in 2020.

This extension works though, just must note that the values must send after a subscription is setup. Or at least send asynchronously.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment