// // MainScanTabItemTests.swift // suixinkanTests // import XCTest @testable import suixinkan_ios /// 主 TabBar 中间扫码入口测试,覆盖系统 TabBar 槽位配置。 @MainActor final class MainScanTabItemTests: XCTestCase { /// 测试主 Tab 容器加载后包含四个业务 Tab 和中间扫码入口。 func testMainTabBarControllerLoadsFiveSystemTabItems() { let services = AppServices(apiClient: APIClient(session: MainTabRecordingURLSession())) let controller = MainTabBarController(services: services) controller.loadViewIfNeeded() XCTAssertEqual(controller.viewControllers?.count, 5) for tab in AppTab.allCases { XCTAssertNotNil(controller.navigationController(for: tab)) XCTAssertEqual( controller.navigationController(for: tab)?.tabBarItem.accessibilityIdentifier, "main.tab.\(tab.rawValue)" ) } } /// 测试扫码入口位于订单与数据之间,并保留指定无障碍标识。 func testScanTabItemIsCenteredBetweenOrdersAndStatistics() throws { let services = AppServices(apiClient: APIClient(session: MainTabRecordingURLSession())) let controller = MainTabBarController(services: services) controller.loadViewIfNeeded() let scanItem = try XCTUnwrap(controller.viewControllers?[2].tabBarItem) XCTAssertEqual(scanItem.title, "扫码") XCTAssertEqual(scanItem.accessibilityIdentifier, "main.scan") XCTAssertEqual(scanItem.accessibilityLabel, "扫码核销") XCTAssertNotNil(scanItem.image) XCTAssertNotNil(scanItem.selectedImage) } /// 测试点击扫码槽位会被拦截且不改变当前选中页面。 func testSelectingScanTabPresentsScannerWithoutSelectingPlaceholder() throws { let services = AppServices(apiClient: APIClient(session: MainTabRecordingURLSession())) let controller = MainTabBarController(services: services) var scanTapCount = 0 controller.onScanTabSelected = { scanTapCount += 1 } controller.loadViewIfNeeded() controller.selectedIndex = 1 let scanController = try XCTUnwrap(controller.viewControllers?[2]) XCTAssertFalse(controller.tabBarController(controller, shouldSelect: scanController)) XCTAssertEqual(scanTapCount, 1) XCTAssertEqual(controller.selectedIndex, 1) } /// 测试业务 Tab 仍允许系统 TabBar 正常选中。 func testSelectingBusinessTabIsAllowed() throws { let services = AppServices(apiClient: APIClient(session: MainTabRecordingURLSession())) let controller = MainTabBarController(services: services) controller.loadViewIfNeeded() let ordersController = try XCTUnwrap(controller.viewControllers?[1]) XCTAssertTrue(controller.tabBarController(controller, shouldSelect: ordersController)) } /// 测试各 Tab 的图标资源可被加载并挂载到 tabBarItem。 func testMainTabBarControllerTabBarItemsHaveImages() { let services = AppServices(apiClient: APIClient(session: MainTabRecordingURLSession())) let controller = MainTabBarController(services: services) controller.loadViewIfNeeded() for tab in AppTab.allCases { let item = controller.navigationController(for: tab)?.tabBarItem XCTAssertNotNil(item?.image, "tab \(tab.rawValue) image should not be nil") XCTAssertNotNil(item?.selectedImage, "tab \(tab.rawValue) selectedImage should not be nil") XCTAssertGreaterThan(item?.image?.size.width ?? 0, 0) XCTAssertGreaterThan(item?.selectedImage?.size.width ?? 0, 0) } } /// 测试订单角标仍挂载在订单业务导航控制器的系统 TabBarItem 上。 func testOrderBadgeUsesOrdersNavigationTabBarItem() throws { let services = AppServices(apiClient: APIClient(session: MainTabRecordingURLSession())) let controller = MainTabBarController(services: services) controller.loadViewIfNeeded() let ordersNavigationController = try XCTUnwrap(controller.navigationController(for: .orders)) ordersNavigationController.tabBarItem.badgeValue = "3" XCTAssertEqual(controller.viewControllers?[1].tabBarItem.badgeValue, "3") } } /// 主 Tab 测试使用的空网络会话,确保容器加载不触发真实请求。 private final class MainTabRecordingURLSession: 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) } }