From cc986245a1532893951cdcfa186989cf71788ba2 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Sat, 17 Oct 2026 22:57:31 -0500 Subject: [PATCH] Make the muted loop-not-running test wait for the reschedule testRescheduleMutedLoopNotLoopingAlerts failed now and then on the first run after a simulator had been idle. Changing the muter reschedules the loop-not-running notifications from ExtensionDataManager.lastLoopCompleted, which the host app refreshes only after launch; a value more than 20 minutes old schedules nothing, leaving the unmuted notifications from loopDidComplete in place. Earlier runs also leave a 4-hour mute in UserDefaults, which hides the problem until it expires. The test now sets the last loop date it reschedules from, and reads the pending notifications until the muted versions replace the others, for up to 5 seconds, instead of reading them once. --- .../Managers/Alerts/AlertManagerTests.swift | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/LoopTests/Managers/Alerts/AlertManagerTests.swift b/LoopTests/Managers/Alerts/AlertManagerTests.swift index 5eeca9cebd..51fd42ea0a 100644 --- a/LoopTests/Managers/Alerts/AlertManagerTests.swift +++ b/LoopTests/Managers/Alerts/AlertManagerTests.swift @@ -490,21 +490,23 @@ class AlertManagerTests: XCTestCase { UNUserNotificationCenter.current().removeAllPendingNotificationRequests() let lastLoopDate = Date() + // Rescheduling reads the last loop date from the shared extension context + var context = ExtensionDataManager.context ?? StatusExtensionContext() + context.lastLoopCompleted = lastLoopDate + ExtensionDataManager.context = context + alertManager.loopDidComplete(lastLoopDate) alertManager.alertMuter.configuration.startTime = Date() alertManager.alertMuter.configuration.duration = .hours(4) waitOnMain() - - let testExpectation = expectation(description: #function) - var loopNotRunningRequests: [UNNotificationRequest] = [] - UNUserNotificationCenter.current().getPendingNotificationRequests() { notificationRequests in - loopNotRunningRequests = notificationRequests.filter({ - $0.content.categoryIdentifier == LoopNotificationCategory.loopNotRunning.rawValue - }) - testExpectation.fulfill() + + var loopNotRunningRequests = pendingLoopNotRunningRequests() + let deadline = Date().addingTimeInterval(5) + while loopNotRunningRequests.contains(where: { $0.content.interruptionLevel == .timeSensitive && $0.content.sound != nil }), Date() < deadline { + RunLoop.current.run(until: Date().addingTimeInterval(0.1)) + loopNotRunningRequests = pendingLoopNotRunningRequests() } - wait(for: [testExpectation], timeout: 1) if #available(iOS 15.0, *) { XCTAssertNil(loopNotRunningRequests.first(where: { $0.content.interruptionLevel == .timeSensitive })?.content.sound) if let request = loopNotRunningRequests.first(where: { $0.content.interruptionLevel == .critical }) { @@ -521,6 +523,19 @@ class AlertManagerTests: XCTestCase { } } } + + private func pendingLoopNotRunningRequests() -> [UNNotificationRequest] { + let pendingExpectation = expectation(description: #function) + var requests: [UNNotificationRequest] = [] + UNUserNotificationCenter.current().getPendingNotificationRequests() { notificationRequests in + requests = notificationRequests.filter({ + $0.content.categoryIdentifier == LoopNotificationCategory.loopNotRunning.rawValue + }) + pendingExpectation.fulfill() + } + wait(for: [pendingExpectation], timeout: 1) + return requests + } } extension Swift.Result {