swift-testing-wait-until
waitUntil: No Task.sleep in Tests
Section titled “waitUntil: No Task.sleep in Tests”Wait for the actual state change instead of a fixed delay. Add this
TestHelpers.swift to your test target (the lint rules already exclude
*TestHelpers.swift):
import Foundation
/// Thrown by `waitUntil` when the condition never became true within the timeout.struct WaitTimeoutError: Error, CustomStringConvertible { let timeout: Duration var description: String { "waitUntil timed out after \(timeout)" }}
/// Polls `condition` until true, throwing on timeout. Runs on the caller's actor/// (via `#isolation`) so the closure may read `@MainActor` fixtures safely.func waitUntil( timeout: Duration = .seconds(2), pollInterval: Duration = .milliseconds(10), isolation _: isolated (any Actor)? = #isolation, _ condition: () -> Bool) async throws { let clock = ContinuousClock() let deadline = clock.now.advanced(by: timeout) while !condition() { guard clock.now < deadline else { throw WaitTimeoutError(timeout: timeout) } try await Task.sleep(for: pollInterval) }}Usage: try await waitUntil { viewModel.isLoaded } instead of
try await Task.sleep(for: .seconds(1)).