From 79e735f628d833a41cd59d63ba45b9f21116f20b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=89=E7=A7=8B?= <497055328@qq.com> Date: Mon, 29 Jun 2026 09:34:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=20TabBar=20=E5=92=8C=E6=89=AB?= =?UTF-8?q?=E7=A0=81=E9=A1=B5=E8=A1=A5=E5=85=85=20accessibilityIdentifier?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=9C=A8=E6=A8=A1=E6=8B=9F=E5=99=A8/UI=20Tes?= =?UTF-8?q?t=20=E4=B8=AD=E7=A6=81=E7=94=A8=E7=9C=9F=E5=AE=9E=E7=9B=B8?= =?UTF-8?q?=E6=9C=BA=E9=87=87=E9=9B=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 预初始化各 Tab 路由容器,修正 iOS 17 ContentUnavailableView 调用,提升自定义 TabBar 与扫码流程的 UI Test 稳定性。 Co-authored-by: Cursor --- .../App/Navigation/NavigationRouter.swift | 20 ++++-- .../Design/AppContentUnavailableView.swift | 4 +- .../Main/Views/CustomMainTabBar.swift | 2 + .../Orders/Views/OrderCodeScannerView.swift | 67 ++++++++++++++++--- .../Orders/OrdersFlowUITests.swift | 2 +- .../Support/SuixinkanUIApplication.swift | 18 +++-- .../Support/TabBarNavigator.swift | 20 ++++++ 7 files changed, 105 insertions(+), 28 deletions(-) diff --git a/suixinkan/App/Navigation/NavigationRouter.swift b/suixinkan/App/Navigation/NavigationRouter.swift index ce7d7fc..ca211a8 100644 --- a/suixinkan/App/Navigation/NavigationRouter.swift +++ b/suixinkan/App/Navigation/NavigationRouter.swift @@ -81,16 +81,22 @@ final class AppRouter: ObservableObject { @Published var selectedTab: AppTab = .home @Published var selectedOrdersEntry: OrdersEntry = .storeOrders @Published private(set) var pendingOrderScanCode: String? - @Published private var routers: [AppTab: RouterPath] = [:] + private let routers: [AppTab: RouterPath] - /// 获取指定 Tab 对应的路由路径容器,不存在时自动创建。 + init() { + routers = Dictionary( + uniqueKeysWithValues: AppTab.allCases.map { tab in + (tab, RouterPath()) + } + ) + } + + /// 获取指定 Tab 对应的路由路径容器。 func router(for tab: AppTab) -> RouterPath { - if let router = routers[tab] { - return router + guard let router = routers[tab] else { + assertionFailure("Missing router path for tab: \(tab)") + return RouterPath() } - - let router = RouterPath() - routers[tab] = router return router } diff --git a/suixinkan/Core/Design/AppContentUnavailableView.swift b/suixinkan/Core/Design/AppContentUnavailableView.swift index b1ccaa6..d4be0ed 100644 --- a/suixinkan/Core/Design/AppContentUnavailableView.swift +++ b/suixinkan/Core/Design/AppContentUnavailableView.swift @@ -7,7 +7,7 @@ import SwiftUI -/// iOS 16 兼容的空状态视图;iOS 17+ 自动使用系统 AppContentUnavailableView。 +/// iOS 16 兼容的空状态视图;iOS 17+ 自动使用系统 ContentUnavailableView。 struct AppContentUnavailableView: View { private let label: LabelContent private let description: DescriptionContent @@ -25,7 +25,7 @@ struct AppContentUnavailableView Self { - if application.state == .runningForeground { + if hasLaunched, application.state == .runningForeground { application.activate() } else { + if application.state != .notRunning { + application.terminate() + Thread.sleep(forTimeInterval: 0.5) + } application.launch() + hasLaunched = true } dismissSystemAlertsIfNeeded() if waitForLoading { @@ -72,12 +78,10 @@ final class SuixinkanApp { /// 判断主 Tab 是否已出现。 var isOnMainTabs: Bool { - TabBarNavigator.Tab.allCases.contains { tab in - let button = application.buttons.matching( - NSPredicate(format: "label == %@", tab.rawValue) - ).firstMatch - return button.waitForExistence(timeout: 1) - } + application.buttons[TabBarNavigator.Tab.home.identifier].exists + || application.buttons[TabBarNavigator.Tab.orders.identifier].exists + || application.buttons[TabBarNavigator.Tab.statistics.identifier].exists + || application.buttons[TabBarNavigator.Tab.profile.identifier].exists } /// 等待冷启动后进入登录页或主 Tab。 diff --git a/suixinkanUITests/Support/TabBarNavigator.swift b/suixinkanUITests/Support/TabBarNavigator.swift index be634b5..81b2aa6 100644 --- a/suixinkanUITests/Support/TabBarNavigator.swift +++ b/suixinkanUITests/Support/TabBarNavigator.swift @@ -14,6 +14,19 @@ enum TabBarNavigator { 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 并等待页面稳定。 @@ -26,6 +39,13 @@ enum TabBarNavigator { /// 在底部自定义 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 candidates = app.application.buttons.matching(NSPredicate(format: "label == %@", title)) let screenHeight = app.application.windows.element(boundBy: 0).frame.height var bestMatch: XCUIElement?