From c1c37bb7d7dd0cbb67784713eb4a4b0d191be7d5 Mon Sep 17 00:00:00 2001 From: gronod Date: Mon, 14 Sep 2026 18:40:27 +0000 Subject: [PATCH] test(m4): retry Start Read until the chartread session is running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit testTwoPassAverageFailurePromotesFirstPass died on Gitea run 35443 waiting for btnCalibrate after a single Start click. Handheld in the same job succeeded: AX reported enabled and synthesized the click, but SwiftUI startRead() was still a no-op (same class as 35251). Re-click until btnCancel/Calibrate/Trigger exist — Cancel is in the tree for the whole session — then wait for Calibrate. --- Tests/ICCeryUITests/Milestone4UITests.swift | 37 ++++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/Tests/ICCeryUITests/Milestone4UITests.swift b/Tests/ICCeryUITests/Milestone4UITests.swift index 5cce6e9..4471f90 100644 --- a/Tests/ICCeryUITests/Milestone4UITests.swift +++ b/Tests/ICCeryUITests/Milestone4UITests.swift @@ -154,15 +154,34 @@ final class Milestone4UITests: XCTestCase { /// Runs the mock handheld chartread session to completion /// (start → calibrate → strip A → strip B → Done & Save). + /// + /// `isEnabled` can be true in AX while the SwiftUI action is still + /// a no-op (runs 35251, 35443). Re-click until the session is + /// actually running (`btnCancel` is shown whenever + /// `isChartreadRunning`), then wait for Calibrate. private func driveOnePass(startButton: String) { let start = app.buttons[startButton] - XCTAssertTrue(start.waitForExistence(timeout: 10)) - let deadline = Date().addingTimeInterval(10) - while Date() < deadline, !start.isEnabled { + XCTAssertTrue(start.waitForExistence(timeout: 10), startButton) + let enabledBy = Date().addingTimeInterval(10) + while Date() < enabledBy, !start.isEnabled { RunLoop.current.run(until: Date().addingTimeInterval(0.1)) } - XCTAssertTrue(start.isEnabled) - start.click() + XCTAssertTrue(start.isEnabled, "\(startButton) never enabled") + + let sessionBy = Date().addingTimeInterval(25) + while Date() < sessionBy, !chartreadSessionRunning { + if start.exists, start.isEnabled { + start.click() + } + RunLoop.current.run(until: Date().addingTimeInterval(0.4)) + } + XCTAssertTrue( + chartreadSessionRunning, + "\(startButton) click never started chartread; " + + "notice=\(element("noticeText").value as? String ?? "") " + + "start.exists=\(start.exists)" + ) + _ = waitFor("btnCalibrate", timeout: 25) app.buttons["btnCalibrate"].click() driveStripsUntilDone() @@ -170,6 +189,14 @@ final class Milestone4UITests: XCTestCase { app.buttons["btnDoneRead"].firstMatch.click() } + /// `btnCancel` is in the tree for the whole chartread session; + /// Calibrate/Trigger only appear after the first classified prompt. + private var chartreadSessionRunning: Bool { + element("btnCancel").exists + || element("btnCalibrate").exists + || element("btnTrigger").exists + } + /// Clicks Trigger for each remaining strip until `btnDoneRead` /// appears — the button is re-polled each pass so a click that /// races a state transition isn't lost. -- 2.39.5