新增 SwiftUI 桥接层与单元测试,更新 Tab 图标资源命名和多倍图,同步调整 UI Test 的 Tab/扫码定位逻辑。 Co-authored-by: Cursor <cursoragent@cursor.com>
99 lines
3.2 KiB
Swift
99 lines
3.2 KiB
Swift
//
|
||
// TabBarNavigator.swift
|
||
// suixinkanUITests
|
||
//
|
||
// Created by Codex on 2026/6/26.
|
||
//
|
||
|
||
import XCTest
|
||
|
||
/// 主 Tab 导航封装。
|
||
enum TabBarNavigator {
|
||
enum Tab: String, CaseIterable {
|
||
case home = "首页"
|
||
case orders = "订单"
|
||
case statistics = "数据"
|
||
case profile = "我的"
|
||
|
||
var identifier: String {
|
||
switch self {
|
||
case .home:
|
||
return "main.tab.home"
|
||
case .orders:
|
||
return "main.tab.orders"
|
||
case .statistics:
|
||
return "main.tab.statistics"
|
||
case .profile:
|
||
return "main.tab.profile"
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 切换到指定 Tab 并等待页面稳定。
|
||
static func select(_ tab: Tab, app: SuixinkanApp, file: StaticString = #filePath, line: UInt = #line) {
|
||
let button = bottomTabButton(named: tab.rawValue, in: app)
|
||
XCTAssertTrue(button.waitForExistence(timeout: 8), "未找到 Tab:\(tab.rawValue)", file: file, line: line)
|
||
button.tap()
|
||
app.waitForGlobalLoadingToDisappear()
|
||
}
|
||
|
||
/// 获取主界面的扫码入口按钮。
|
||
static func scannerButton(in app: SuixinkanApp) -> XCUIElement {
|
||
let identifiedButton = app.application.buttons["main.scan"]
|
||
if identifiedButton.exists {
|
||
return identifiedButton
|
||
}
|
||
|
||
let systemTabButton = app.application.tabBars.buttons["扫码核销"]
|
||
if systemTabButton.exists {
|
||
return systemTabButton
|
||
}
|
||
|
||
return bottomTabButton(named: "扫码核销", in: app)
|
||
}
|
||
|
||
/// 判断主 Tab 是否已经出现在界面上。
|
||
static func isVisible(in app: SuixinkanApp) -> Bool {
|
||
Tab.allCases.contains { tab in
|
||
app.application.tabBars.buttons[tab.rawValue].exists
|
||
|| app.application.buttons[tab.identifier].exists
|
||
|| app.application.buttons[tab.rawValue].exists
|
||
}
|
||
}
|
||
|
||
/// 在底部系统 TabBar 或旧自定义 TabBar 中定位唯一可点击的 Tab 按钮。
|
||
private static func bottomTabButton(named title: String, in app: SuixinkanApp) -> XCUIElement {
|
||
if let tab = Tab(rawValue: title) {
|
||
let identifiedButton = app.application.buttons[tab.identifier]
|
||
if identifiedButton.exists {
|
||
return identifiedButton
|
||
}
|
||
}
|
||
|
||
let systemTabButton = app.application.tabBars.buttons[title]
|
||
if systemTabButton.exists {
|
||
return systemTabButton
|
||
}
|
||
|
||
let candidates = app.application.buttons.matching(NSPredicate(format: "label == %@", title))
|
||
let screenHeight = app.application.windows.element(boundBy: 0).frame.height
|
||
var bestMatch: XCUIElement?
|
||
var bestY: CGFloat = -1
|
||
|
||
for index in 0..<candidates.count {
|
||
let candidate = candidates.element(boundBy: index)
|
||
guard candidate.exists else { continue }
|
||
|
||
let midY = candidate.frame.midY
|
||
guard midY > screenHeight * 0.72 else { continue }
|
||
|
||
if midY > bestY {
|
||
bestMatch = candidate
|
||
bestY = midY
|
||
}
|
||
}
|
||
|
||
return bestMatch ?? candidates.firstMatch
|
||
}
|
||
}
|