新增完整 UI Test 回归套件,并完善启动隔离逻辑。
按模块拆分 XCUITest 用例与 Support 基础设施,UI Test 运行时跳过推送与排队 WebSocket,并将 Podfile 最低版本对齐 iOS 16。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
115
suixinkanUITests/Support/UITestLaunchConfiguration.swift
Normal file
115
suixinkanUITests/Support/UITestLaunchConfiguration.swift
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// UITestLaunchConfiguration.swift
|
||||
// suixinkanUITests
|
||||
//
|
||||
// Created by Codex on 2026/6/26.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
/// UI Test 启动参数与环境变量,需与 App 侧 `AppUITestLaunchState` 保持同名。
|
||||
enum UITestLaunchConfiguration {
|
||||
static let uiTestsArgument = "-suixinkan-ui-tests"
|
||||
static let resetArgument = "-suixinkan-ui-tests-reset-state"
|
||||
|
||||
static let phoneEnvironmentKey = "SUI_TEST_PHONE"
|
||||
static let passwordEnvironmentKey = "SUI_TEST_PASSWORD"
|
||||
static let accountNameEnvironmentKey = "SUI_TEST_ACCOUNT_NAME"
|
||||
|
||||
/// 为 XCUIApplication 注入 UI Test 启动参数;仅在需要冷启动空白态时传入 resetState。
|
||||
static func apply(to app: XCUIApplication, resetState: Bool = false) {
|
||||
if !app.launchArguments.contains(uiTestsArgument) {
|
||||
app.launchArguments.append(uiTestsArgument)
|
||||
}
|
||||
|
||||
if resetState {
|
||||
if !app.launchArguments.contains(resetArgument) {
|
||||
app.launchArguments.append(resetArgument)
|
||||
}
|
||||
} else {
|
||||
app.launchArguments.removeAll { $0 == resetArgument }
|
||||
}
|
||||
}
|
||||
|
||||
/// 从 Scheme / xcodebuild 环境变量或本地 plist 读取测试账号。
|
||||
static var credentials: UITestCredentials? {
|
||||
if let environmentCredentials = credentialsFromEnvironment() {
|
||||
return environmentCredentials
|
||||
}
|
||||
return credentialsFromLocalPlist()
|
||||
}
|
||||
|
||||
/// 缺少测试账号时跳过需要真实登录的用例。
|
||||
static func requireCredentials(file: StaticString = #filePath, line: UInt = #line) throws -> UITestCredentials {
|
||||
guard let credentials else {
|
||||
throw XCTSkip(
|
||||
"缺少 UI Test 账号。请配置环境变量 \(phoneEnvironmentKey) / \(passwordEnvironmentKey),或在本机创建 UITestCredentials.local.plist。"
|
||||
)
|
||||
}
|
||||
return credentials
|
||||
}
|
||||
|
||||
/// 从 Scheme / xcodebuild 环境变量读取测试账号。
|
||||
private static func credentialsFromEnvironment() -> UITestCredentials? {
|
||||
let environment = ProcessInfo.processInfo.environment
|
||||
guard
|
||||
let phone = environment[phoneEnvironmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!phone.isEmpty,
|
||||
let password = environment[passwordEnvironmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!password.isEmpty
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let accountName = environment[accountNameEnvironmentKey]?
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return UITestCredentials(
|
||||
phone: phone,
|
||||
password: password,
|
||||
accountName: accountName?.isEmpty == false ? accountName : nil
|
||||
)
|
||||
}
|
||||
|
||||
/// 从 gitignore 的本地 plist 读取测试账号,便于本机开发配置。
|
||||
private static func credentialsFromLocalPlist() -> UITestCredentials? {
|
||||
let plistURL = localCredentialsURL
|
||||
guard
|
||||
FileManager.default.fileExists(atPath: plistURL.path),
|
||||
let dictionary = NSDictionary(contentsOf: plistURL) as? [String: String]
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard
|
||||
let phone = dictionary[phoneEnvironmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!phone.isEmpty,
|
||||
let password = dictionary[passwordEnvironmentKey]?.trimmingCharacters(in: .whitespacesAndNewlines),
|
||||
!password.isEmpty
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let accountName = dictionary[accountNameEnvironmentKey]?
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return UITestCredentials(
|
||||
phone: phone,
|
||||
password: password,
|
||||
accountName: accountName?.isEmpty == false ? accountName : nil
|
||||
)
|
||||
}
|
||||
|
||||
/// 本地测试账号 plist 路径。
|
||||
private static var localCredentialsURL: URL {
|
||||
URL(fileURLWithPath: #filePath)
|
||||
.deletingLastPathComponent()
|
||||
.deletingLastPathComponent()
|
||||
.appendingPathComponent("UITestCredentials.local.plist")
|
||||
}
|
||||
}
|
||||
|
||||
/// UI Test 登录账号实体。
|
||||
struct UITestCredentials: Equatable {
|
||||
let phone: String
|
||||
let password: String
|
||||
let accountName: String?
|
||||
}
|
||||
Reference in New Issue
Block a user