// // WaitHelpers.swift // PlantGuideUITests // // Centralized wait helpers for UI tests. // Replaces sleep() with deterministic, predicate-based waits. // import XCTest // MARK: - XCUIElement Wait Helpers extension XCUIElement { /// Waits until the element exists and is hittable. /// - Parameter timeout: Maximum seconds to wait (default 5). /// - Returns: `true` if the element became hittable within the timeout. @discardableResult func waitUntilHittable(timeout: TimeInterval = 5) -> Bool { let predicate = NSPredicate(format: "exists == true AND isHittable == true") let expectation = XCTNSPredicateExpectation(predicate: predicate, object: self) return XCTWaiter.wait(for: [expectation], timeout: timeout) == .completed } /// Waits until the element disappears. /// - Parameter timeout: Maximum seconds to wait (default 5). /// - Returns: `true` if the element disappeared within the timeout. @discardableResult func waitUntilGone(timeout: TimeInterval = 5) -> Bool { let predicate = NSPredicate(format: "exists == false") let expectation = XCTNSPredicateExpectation(predicate: predicate, object: self) return XCTWaiter.wait(for: [expectation], timeout: timeout) == .completed } /// Waits until the element's value equals the expected string. /// - Parameters: /// - expectedValue: Target value. /// - timeout: Maximum seconds to wait (default 5). /// - Returns: `true` if the value matched within the timeout. @discardableResult func waitForValue(_ expectedValue: String, timeout: TimeInterval = 5) -> Bool { let predicate = NSPredicate(format: "value == %@", expectedValue) let expectation = XCTNSPredicateExpectation(predicate: predicate, object: self) return XCTWaiter.wait(for: [expectation], timeout: timeout) == .completed } /// Taps the element once it becomes hittable. /// - Parameter timeout: Maximum seconds to wait for hittable state. func tapWhenReady(timeout: TimeInterval = 5) { XCTAssertTrue(waitUntilHittable(timeout: timeout), "Element \(debugDescription) not hittable after \(timeout)s") tap() } } // MARK: - XCUIApplication Wait Helpers extension XCUIApplication { /// Waits for the main tab bar to appear, indicating the app launched successfully. /// - Parameter timeout: Maximum seconds to wait (default 10). @discardableResult func waitForLaunch(timeout: TimeInterval = 10) -> Bool { tabBars.firstMatch.waitForExistence(timeout: timeout) } /// Waits for any element matching the identifier to appear. /// - Parameters: /// - identifier: The accessibility identifier. /// - timeout: Maximum seconds to wait (default 5). /// - Returns: The first matching element if found. @discardableResult func waitForElement(identifier: String, timeout: TimeInterval = 5) -> XCUIElement { let element = descendants(matching: .any)[identifier] _ = element.waitForExistence(timeout: timeout) return element } }