160 lines
6.6 KiB
Swift
160 lines
6.6 KiB
Swift
//
|
|
// OrderListUITokensTests.swift
|
|
// suixinkanTests
|
|
//
|
|
|
|
import UIKit
|
|
import XCTest
|
|
@testable import suixinkan
|
|
|
|
/// 订单列表 UI Token 与 badge 映射校验。
|
|
final class OrderListUITokensTests: XCTestCase {
|
|
|
|
func testOrderTokensMatchAndroid() {
|
|
XCTAssertEqual(OrderTokens.filterBackground.hexRGB, 0xF4F4F4)
|
|
XCTAssertEqual(OrderTokens.label563.hexRGB, 0x4B5563)
|
|
XCTAssertEqual(OrderTokens.timestamp.hexRGB, 0x6B7280)
|
|
XCTAssertEqual(OrderTokens.depositSuccess.hexRGB, 0x27AE60)
|
|
XCTAssertEqual(OrderTokens.depositRefunded.hexRGB, 0x6B7280)
|
|
XCTAssertEqual(OrderTokens.searchHeight, 36)
|
|
XCTAssertEqual(OrderTokens.filterPillHeight, 35)
|
|
XCTAssertEqual(OrderTokens.actionButtonHeight, 48)
|
|
XCTAssertEqual(OrderTokens.cardRadius, 12)
|
|
}
|
|
|
|
func testPhotographerOrderStatusBadgeMapping() {
|
|
let badge = AppStatusBadge()
|
|
badge.applyOrderStatus(18, text: "已付定金")
|
|
badge.applyOrderStatus(30, text: "已完成")
|
|
badge.applyOrderStatus(50, text: "已退款")
|
|
XCTAssertFalse(badge.isHidden)
|
|
}
|
|
|
|
func testDepositOrderStatus50UsesNeutralGray() {
|
|
let badge = AppStatusBadge()
|
|
badge.applyDepositOrderStatus(50, text: "已退款")
|
|
XCTAssertEqual(badge.backgroundColor?.hexRGB, OrderTokens.depositRefundedBackground.hexRGB)
|
|
}
|
|
|
|
func testDepositOrderStatus30UsesDepositGreen() {
|
|
let badge = AppStatusBadge()
|
|
badge.applyDepositOrderStatus(30, text: "已完成")
|
|
XCTAssertEqual(badge.backgroundColor?.hexRGB, OrderTokens.depositSuccessBackground.hexRGB)
|
|
}
|
|
|
|
func testPhotographerStatus50UsesDangerNotGray() {
|
|
let badge = AppStatusBadge()
|
|
badge.applyOrderStatus(50, text: "已退款")
|
|
XCTAssertEqual(badge.backgroundColor?.hexRGB, AppColor.dangerBackground.hexRGB)
|
|
}
|
|
|
|
func testOrderTypeChipIntrinsicSizeWrapsTextWithPadding() {
|
|
let chip = OrderTypeChipView()
|
|
chip.apply(text: "订单类型")
|
|
|
|
let size = chip.intrinsicContentSize
|
|
XCTAssertGreaterThan(size.width, "订单类型".size(withAttributes: [.font: UIFont.app(.caption)]).width)
|
|
XCTAssertGreaterThan(size.height, UIFont.app(.caption).lineHeight)
|
|
XCTAssertFalse(chip.isHidden)
|
|
}
|
|
}
|
|
|
|
private extension UIColor {
|
|
var hexRGB: UInt {
|
|
var red: CGFloat = 0
|
|
var green: CGFloat = 0
|
|
var blue: CGFloat = 0
|
|
var alpha: CGFloat = 0
|
|
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
|
|
let r = Int(round(red * 255))
|
|
let g = Int(round(green * 255))
|
|
let b = Int(round(blue * 255))
|
|
return UInt(r << 16 | g << 8 | b)
|
|
}
|
|
}
|
|
|
|
/// 回归通知刷新时表格仍请求旧行的场景,使用 mock 数据覆盖两种订单页面。
|
|
@MainActor
|
|
final class OrderNotificationListSnapshotTests: XCTestCase {
|
|
private var appStore: AppStore!
|
|
private var suiteName: String!
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
suiteName = "OrderNotificationListSnapshotTests.\(UUID().uuidString)"
|
|
appStore = AppStore(defaults: UserDefaults(suiteName: suiteName)!)
|
|
appStore.session.configureTestAccount(userId: "push-list-test", accountType: .storeUser, scenicId: 10)
|
|
appStore.session.currentStoreId = 20
|
|
}
|
|
|
|
override func tearDown() {
|
|
UserDefaults.standard.removePersistentDomain(forName: suiteName)
|
|
appStore = nil
|
|
super.tearDown()
|
|
}
|
|
|
|
func testPhotographerRowsRemainReadableWhileNotificationRefreshClearsModel() async throws {
|
|
try await verifyRefreshUsesSnapshot(storeMode: false)
|
|
}
|
|
|
|
func testDepositRowsRemainReadableWhileNotificationRefreshClearsModel() async throws {
|
|
try await verifyRefreshUsesSnapshot(storeMode: true)
|
|
}
|
|
|
|
private func verifyRefreshUsesSnapshot(storeMode: Bool) async throws {
|
|
appStore.session.roleCode = storeMode ? AppRoleCode.storeAdmin.rawValue : AppRoleCode.photographer.rawValue
|
|
let initial = Data(#"{"code":100000,"msg":"success","data":{"list":[{"order_number":"push-order-a","order_status":30},{"order_number":"push-order-b","order_status":30}],"total":2}}"#.utf8)
|
|
let empty = Data(#"{"code":100000,"msg":"success","data":{"list":[],"total":0}}"#.utf8)
|
|
let session = MockURLSession(responses: [initial, empty, initial])
|
|
let api = OrderAPI(client: APIClient(environment: .testing, session: session))
|
|
let orders = OrderListViewModel(appStore: appStore)
|
|
let deposits = DepositOrderListViewModel(appStore: appStore)
|
|
let controller = OrdersViewController(orderAPI: api, orderListViewModel: orders, depositViewModel: deposits, appStore: appStore)
|
|
controller.openFromOrderNotification()
|
|
let list = try XCTUnwrap(controller.view.subviews.first { $0 is OrderListView } as? OrderListView)
|
|
let table = list.tableView
|
|
await waitForRows(2, in: table)
|
|
let source = try XCTUnwrap(table.dataSource)
|
|
|
|
// 保持表格的旧快照,精确模拟模型已清空、主线程 UI 回调尚未执行的窗口。
|
|
let notify = storeMode ? deposits.onStateChange : orders.onStateChange
|
|
if storeMode {
|
|
deposits.onStateChange = nil
|
|
deposits.resetFiltersForOrderNotification()
|
|
await deposits.refreshOrderList(api: api)
|
|
XCTAssertTrue(deposits.orderList.isEmpty)
|
|
} else {
|
|
orders.onStateChange = nil
|
|
orders.resetFiltersForOrderNotification()
|
|
await orders.refreshOrderList(api: api)
|
|
XCTAssertTrue(orders.orderList.isEmpty)
|
|
}
|
|
XCTAssertEqual(source.tableView(table, numberOfRowsInSection: 0), 2)
|
|
for index in 0..<2 {
|
|
let cell = source.tableView(table, cellForRowAt: IndexPath(row: index, section: 0))
|
|
if storeMode {
|
|
XCTAssertTrue(cell is DepositOrderCardCell)
|
|
} else {
|
|
XCTAssertTrue(cell is OrderCardCell)
|
|
}
|
|
}
|
|
if storeMode { deposits.onStateChange = notify } else { orders.onStateChange = notify }
|
|
notify?()
|
|
await waitForRows(0, in: table)
|
|
|
|
// 已打开的订单页再次点击通知,仍能加载完整列表。
|
|
controller.openFromOrderNotification()
|
|
await waitForRows(2, in: table)
|
|
XCTAssertEqual(session.requests.count, 3)
|
|
}
|
|
|
|
private func waitForRows(_ count: Int, in table: UITableView) async {
|
|
let applied = expectation(for: NSPredicate { _, _ in
|
|
MainActor.assumeIsolated {
|
|
table.numberOfRows(inSection: 0) == count
|
|
}
|
|
}, evaluatedWith: nil)
|
|
await fulfillment(of: [applied], timeout: 3)
|
|
}
|
|
}
|