新增完整 UI Test 回归套件,并完善启动隔离逻辑。

按模块拆分 XCUITest 用例与 Support 基础设施,UI Test 运行时跳过推送与排队 WebSocket,并将 Podfile 最低版本对齐 iOS 16。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-26 10:45:00 +08:00
parent 703078352c
commit 0c01ee26c3
39 changed files with 1533 additions and 231 deletions

View File

@ -0,0 +1,104 @@
//
// LoginFlow.swift
// suixinkanUITests
//
// Created by Codex on 2026/6/26.
//
import XCTest
///
enum LoginFlow {
///
static func loginIfNeeded(
app: SuixinkanApp,
credentials: UITestCredentials,
file: StaticString = #filePath,
line: UInt = #line
) {
guard app.isOnLoginScreen else { return }
fillLoginForm(app: app, credentials: credentials)
submitLogin(app: app)
handleAccountSelectionIfNeeded(app: app, credentials: credentials)
app.waitForGlobalLoadingToDisappear()
XCTAssertTrue(
app.isOnMainTabs,
"登录后应进入主 Tab。",
file: file,
line: line
)
}
///
static func fillLoginForm(app: SuixinkanApp, credentials: UITestCredentials) {
let usernameField = app.application.textFields["login.username"]
XCTAssertTrue(usernameField.waitForExistence(timeout: 8))
usernameField.tap()
usernameField.clearAndType(credentials.phone)
let passwordField = preferredPasswordField(in: app.application)
XCTAssertTrue(passwordField.waitForExistence(timeout: 4))
passwordField.tap()
passwordField.clearAndType(credentials.password)
let privacyToggle = app.application.buttons["login.privacy"]
if privacyToggle.exists {
privacyToggle.tap()
}
}
///
static func submitLogin(app: SuixinkanApp) {
let submitButton = app.application.buttons["login.submit"]
XCTAssertTrue(submitButton.waitForExistence(timeout: 4))
submitButton.tap()
app.waitForGlobalLoadingToDisappear()
}
/// v9
static func handleAccountSelectionIfNeeded(
app: SuixinkanApp,
credentials: UITestCredentials
) {
let accountSelectionTitle = app.application.navigationBars["选择账号"]
guard accountSelectionTitle.waitForExistence(timeout: 6) else { return }
if let accountName = credentials.accountName {
let accountCell = app.application.staticTexts[accountName]
if accountCell.waitForExistence(timeout: 4) {
accountCell.tap()
}
}
let confirmButton = app.application.buttons["进入系统"]
XCTAssertTrue(confirmButton.waitForExistence(timeout: 4))
confirmButton.tap()
app.waitForGlobalLoadingToDisappear()
}
///
private static func preferredPasswordField(in app: XCUIApplication) -> XCUIElement {
let secureField = app.secureTextFields["login.password"]
if secureField.exists {
return secureField
}
return app.textFields["login.password"]
}
}
private extension XCUIElement {
///
func clearAndType(_ text: String) {
guard let currentValue = value as? String else {
typeText(text)
return
}
tap()
let deleteString = String(repeating: XCUIKeyboardKey.delete.rawValue, count: currentValue.count)
typeText(deleteString)
typeText(text)
}
}