From 0fbea2cf058ce831ded933add08a9095376beb8b Mon Sep 17 00:00:00 2001 From: Justin Bishop Date: Mon, 25 May 2026 12:03:48 -0700 Subject: [PATCH] Fix bannerHidesWhenScoringUnavailable CI flake MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The drain task can be scheduled (banner → .loading) before it has reached engine.start() → observation emit → scheduleCacheRebuild() → cacheDebounce's 5 s sleep registration. If advanceTime runs first, currentTime jumps past the not-yet-scheduled wakeTime and the rebuild never fires — banner stays .loading. Wait for the sleep to register first, then advance. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../SearchRecommendationCollectorTests.swift | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/PodHavenTests/ViewModelTests/SearchRecommendationCollectorTests.swift b/PodHavenTests/ViewModelTests/SearchRecommendationCollectorTests.swift index 2ebde4ee..53ecbb4e 100644 --- a/PodHavenTests/ViewModelTests/SearchRecommendationCollectorTests.swift +++ b/PodHavenTests/ViewModelTests/SearchRecommendationCollectorTests.swift @@ -968,11 +968,18 @@ import Testing } ) - // Advance time once, well beyond the engine's 400 ms cacheRebuild debounce. - // That fires buildContext (returns nil) and bumps scoringRevision. With - // the fix, awaitScoringContext returns and the banner transitions to - // .hidden; without it, the banner stays .loading forever. - await fakeSleeper.advanceTime(by: .seconds(5)) + // The drain task may not yet have reached engine.start() → observation → + // scheduleCacheRebuild by the time the banner shows .loading. Wait for + // the engine's cacheRebuild debounce to register its sleep before + // advancing time, otherwise advanceTime jumps the clock past a not-yet- + // scheduled wakeTime and the rebuild never fires. + try await fakeSleeper.waitForSleepRequests(count: 1) + + // Advance well beyond the cacheRebuild debounce. That fires buildContext + // (returns nil) and bumps scoringRevision. With the fix, awaitScoringContext + // returns and the banner transitions to .hidden; without it, the banner + // stays .loading forever. + await fakeSleeper.advanceTime(by: .seconds(10)) try await Wait.until( { @MainActor in collector.bannerState == .hidden }, { @MainActor in