新增完整 UI Test 回归套件,并完善启动隔离逻辑。
按模块拆分 XCUITest 用例与 Support 基础设施,UI Test 运行时跳过推送与排队 WebSocket,并将 Podfile 最低版本对齐 iOS 16。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
104
suixinkanUITests/Support/LoginFlow.swift
Normal file
104
suixinkanUITests/Support/LoginFlow.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user