#if canImport(Combine) import Combine import XCTest @available(iOS 13, macOS 10.15, tvOS 13, watchOS 6, *) extension PublisherExpectations { /// A publisher expectation which waits for the recorded publisher /// to complete. /// /// When waiting for this expectation, a RecordingError.notCompleted is /// thrown if the publisher does not complete on time. /// /// Otherwise, a [Record.Recording](https://developer.apple.com/documentation/combine/record/recording) /// is returned. /// /// For example: /// /// // SUCCESS: no timeout, no error /// func testArrayPublisherRecording() throws { /// let publisher = ["foo", "bar", "baz"].publisher /// let recorder = publisher.record() /// let recording = try wait(for: recorder.recording, timeout: 1) /// XCTAssertEqual(recording.output, ["foo", "bar", "baz"]) /// if case let .failure(error) = recording.completion { /// XCTFail("Unexpected error \(error)") /// } /// } public struct Recording: PublisherExpectation { let recorder: Recorder public func _setup(_ expectation: XCTestExpectation) { recorder.fulfillOnCompletion(expectation) } /// Returns the expected output, or throws an error if the /// expectation fails. /// /// For example: /// /// // SUCCESS: no error /// func testArrayPublisherSynchronousRecording() throws { /// let publisher = ["foo", "bar", "baz"].publisher /// let recorder = publisher.record() /// let recording = try recorder.recording.get() /// XCTAssertEqual(recording.output, ["foo", "bar", "baz"]) /// if case let .failure(error) = recording.completion { /// XCTFail("Unexpected error \(error)") /// } /// } public func get() throws -> Record.Recording { try recorder.value { (elements, completion, remainingElements, consume) in if let completion { consume(remainingElements.count) return Record.Recording(output: elements, completion: completion) } else { throw RecordingError.notCompleted } } } } } #endif