Files
suixinkan_ios_uikit/suixinkan_iosTests/NavigationRouterTests.swift
汉秋 a1c031c9b7 Integrate CYLTabBar center scan button and unify UIKit navigation.
Add CYLTabBarController with a global scan entry, promote MainTabBarController to the window root after login, replace RouterPath-based navigation with AppNavigator, and fix Profile diffable cell reconfiguration crashes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-26 16:36:18 +08:00

172 lines
7.0 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// NavigationRouterTests.swift
// suixinkanTests
//
// Created by Codex on 2026/6/22.
//
import UIKit
import XCTest
@testable import suixinkan_ios
/// UIKit Tab 宿 push
@MainActor
final class AppNavigatorTests: XCTestCase {
/// push TabBar
func testPushUsesCurrentNavigationStack() {
let services = AppServices(apiClient: APIClient(session: AppNavigatorRecordingURLSession()))
let host = AppNavigatorTestHost(services: services)
let navigator = AppNavigator()
navigator.attach(host: host)
navigator.push(.home(.paymentCollection), from: nil, animated: false)
let homeStack = host.navigationController(for: .home)!
XCTAssertEqual(homeStack.viewControllers.count, 2)
XCTAssertTrue(homeStack.viewControllers.last?.hidesBottomBarWhenPushed == true)
XCTAssertTrue(homeStack.viewControllers.last is PaymentCollectionViewController)
}
/// tabRoot Tab
func testTabRootSelectsTabResetsStackAndPushesRoute() {
let services = AppServices(apiClient: APIClient(session: AppNavigatorRecordingURLSession()))
let host = AppNavigatorTestHost(services: services)
let navigator = AppNavigator()
navigator.attach(host: host)
host.navigationController(for: .home)?.push(route: .home(.wallet), animated: false)
navigator.openHome(.taskManagement, policy: .tabRoot(.home), animated: false)
let homeStack = host.navigationController(for: .home)!
XCTAssertEqual(host.selectedTab, .home)
XCTAssertEqual(homeStack.viewControllers.count, 2)
XCTAssertTrue(homeStack.viewControllers.last is TaskManagementViewController)
}
/// preserveTab Tab
func testPreserveTabKeepsExistingStack() {
let services = AppServices(apiClient: APIClient(session: AppNavigatorRecordingURLSession()))
let host = AppNavigatorTestHost(services: services)
let navigator = AppNavigator()
navigator.attach(host: host)
host.navigationController(for: .profile)?.push(route: .profile(.settings), animated: false)
navigator.openProfile(.realNameAuth, policy: .preserveTab(.profile), animated: false)
let profileStack = host.navigationController(for: .profile)!
XCTAssertEqual(host.selectedTab, .profile)
XCTAssertEqual(profileStack.viewControllers.count, 3)
XCTAssertTrue(profileStack.viewControllers[1] is SettingsViewController)
XCTAssertTrue(profileStack.viewControllers.last is RealNameAuthViewController)
}
/// 宿 attach
func testPendingActionsRunAfterAttachInFIFOOrder() {
let services = AppServices(apiClient: APIClient(session: AppNavigatorRecordingURLSession()))
let host = AppNavigatorTestHost(services: services)
let navigator = AppNavigator()
navigator.openHome(.paymentCollection, policy: .tabRoot(.home), animated: false)
navigator.openHome(.messageCenter, policy: .preserveTab(.home), animated: false)
navigator.attach(host: host)
let homeStack = host.navigationController(for: .home)!
XCTAssertEqual(homeStack.viewControllers.count, 3)
XCTAssertTrue(homeStack.viewControllers[1] is PaymentCollectionViewController)
XCTAssertTrue(homeStack.viewControllers.last is MessageCenterViewController)
}
/// resetAllStacks 宿
func testResetAllStacksClearsPendingAndMountedStacks() {
let services = AppServices(apiClient: APIClient(session: AppNavigatorRecordingURLSession()))
let host = AppNavigatorTestHost(services: services)
let navigator = AppNavigator()
navigator.openHome(.paymentCollection, policy: .tabRoot(.home), animated: false)
navigator.resetAllStacks()
navigator.attach(host: host)
XCTAssertEqual(host.navigationController(for: .home)?.viewControllers.count, 1)
navigator.openHome(.wallet, policy: .tabRoot(.home), animated: false)
navigator.resetAllStacks()
XCTAssertEqual(host.navigationController(for: .home)?.viewControllers.count, 1)
XCTAssertEqual(host.selectedTab, .home)
}
/// Tab
func testOpenOrdersEntryAppliesRootStateAndScanCode() {
let services = AppServices(apiClient: APIClient(session: AppNavigatorRecordingURLSession()))
let host = AppNavigatorTestHost(services: services)
let navigator = AppNavigator()
navigator.attach(host: host)
navigator.openOrdersEntry(.verificationOrders, scannedCode: "VERIFY001")
XCTAssertEqual(host.selectedTab, .orders)
XCTAssertEqual(host.appliedOrdersEntry, .verificationOrders)
XCTAssertEqual(host.appliedScanCode, "VERIFY001")
XCTAssertEqual(host.navigationController(for: .orders)?.viewControllers.count, 1)
}
}
/// AppNavigator 宿 Tab
@MainActor
private final class AppNavigatorTestHost: AppNavigationHost {
private let services: AppServices
private var controllers: [AppTab: TabNavigationController] = [:]
var selectedTab: AppTab = .home
var appliedOrdersEntry: OrdersEntry?
var appliedScanCode: String?
/// Tab
init(services: AppServices) {
self.services = services
for tab in AppTab.allCases {
controllers[tab] = TabNavigationController(tab: tab, services: services)
}
}
/// Tab
func selectTab(_ tab: AppTab) {
selectedTab = tab
}
/// Tab
func navigationController(for tab: AppTab) -> TabNavigationController? {
controllers[tab]
}
/// Tab
func selectedNavigationController() -> TabNavigationController? {
controllers[selectedTab]
}
/// Tab
func resetAllStacks() {
for controller in controllers.values {
controller.popToRootViewController(animated: false)
}
selectedTab = .home
}
///
func applyOrdersEntry(_ entry: OrdersEntry, scannedCode: String?) {
appliedOrdersEntry = entry
appliedScanCode = scannedCode
}
}
///
private final class AppNavigatorRecordingURLSession: URLSessionProtocol {
///
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
let response = HTTPURLResponse(
url: request.url ?? URL(string: "https://example.com")!,
statusCode: 200,
httpVersion: nil,
headerFields: nil
)!
return (Data(), response)
}
}