按模块拆分 XCUITest 用例与 Support 基础设施,UI Test 运行时跳过推送与排队 WebSocket,并将 Podfile 最低版本对齐 iOS 16。 Co-authored-by: Cursor <cursoragent@cursor.com>
79 lines
2.6 KiB
Swift
79 lines
2.6 KiB
Swift
//
|
||
// SuixinkanUIApplication.swift
|
||
// suixinkanUITests
|
||
//
|
||
// Created by Codex on 2026/6/26.
|
||
//
|
||
|
||
import XCTest
|
||
|
||
/// 封装 XCUIApplication 的常用等待、权限弹窗和全局 Loading 处理。
|
||
final class SuixinkanApp {
|
||
let application: XCUIApplication
|
||
private let resetState: Bool
|
||
|
||
/// 创建并配置 UI Test 启动参数的应用实例。
|
||
init(resetState: Bool = false) {
|
||
self.resetState = resetState
|
||
application = XCUIApplication()
|
||
UITestLaunchConfiguration.apply(to: application, resetState: resetState)
|
||
}
|
||
|
||
/// 启动 App 并等待首屏稳定。
|
||
@discardableResult
|
||
func launch(waitForLoading: Bool = true) -> Self {
|
||
if application.state == .runningForeground {
|
||
application.activate()
|
||
} else {
|
||
application.launch()
|
||
}
|
||
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["首页"].waitForExistence(timeout: 1)
|
||
|| application.buttons["我的"].waitForExistence(timeout: 1)
|
||
}
|
||
|
||
/// 等待冷启动后进入登录页或主 Tab。
|
||
func waitForInitialScreen(timeout: TimeInterval = 45) {
|
||
if application.staticTexts["login.title"].waitForExistence(timeout: 2) {
|
||
return
|
||
}
|
||
_ = application.buttons["首页"].waitForExistence(timeout: timeout)
|
||
|| application.buttons["我的"].waitForExistence(timeout: 2)
|
||
}
|
||
}
|