// // SuixinkanUIApplication.swift // suixinkanUITests // // Created by Codex on 2026/6/26. // import XCTest /// 封装 XCUIApplication 的常用等待、权限弹窗和全局 Loading 处理。 final class SuixinkanApp { let application: XCUIApplication private let resetState: Bool private var hasLaunched = false /// 创建并配置 UI Test 启动参数的应用实例。 init( resetState: Bool = false, openMenuTitle: String? = nil, openProfileRoute: String? = nil ) { self.resetState = resetState application = XCUIApplication() UITestLaunchConfiguration.apply( to: application, resetState: resetState, openMenu: openMenuTitle, openProfile: openProfileRoute ) } /// 启动 App 并等待首屏稳定。 @discardableResult func launch(waitForLoading: Bool = true) -> Self { if hasLaunched, application.state == .runningForeground { application.activate() } else { if application.state != .notRunning { application.terminate() Thread.sleep(forTimeInterval: 0.5) } application.launch() hasLaunched = true } dismissSystemAlertsIfNeeded() if waitForLoading { waitForGlobalLoadingToDisappear() } return self } /// 等待全局 Loading 层消失。 func waitForGlobalLoadingToDisappear(timeout: TimeInterval = 45) { let loading = application.staticTexts["加载中"] guard loading.waitForExistence(timeout: 2) else { return } let predicate = NSPredicate(format: "exists == false") let expectation = XCTNSPredicateExpectation(predicate: predicate, object: loading) _ = XCTWaiter.wait(for: [expectation], timeout: timeout) } /// 处理系统权限弹窗,尽量点允许以便页面继续加载。 func dismissSystemAlertsIfNeeded() { let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let allowButtons = ["允许", "好", "使用App时允许", "Allow", "Allow While Using App", "OK"] for title in allowButtons { let button = springboard.buttons[title] if button.waitForExistence(timeout: 1) { button.tap() } } } /// 判断当前是否仍在登录页。 var isOnLoginScreen: Bool { application.staticTexts["login.title"].exists } /// 判断主 Tab 是否已出现。 var isOnMainTabs: Bool { application.buttons[TabBarNavigator.Tab.home.identifier].exists || application.buttons[TabBarNavigator.Tab.orders.identifier].exists || application.buttons[TabBarNavigator.Tab.statistics.identifier].exists || application.buttons[TabBarNavigator.Tab.profile.identifier].exists } /// 等待冷启动后进入登录页或主 Tab。 func waitForInitialScreen(timeout: TimeInterval = 45) { if application.staticTexts["login.title"].waitForExistence(timeout: 2) { return } let deadline = Date().addingTimeInterval(timeout) while Date() < deadline { if isOnMainTabs { return } RunLoop.current.run(until: Date().addingTimeInterval(0.2)) } } }