fix: route payment pushes to orders and prevent refresh crash

This commit is contained in:
2026-09-08 09:59:51 +08:00
parent 10249776ad
commit c4b0e7798b
10 changed files with 333 additions and 47 deletions
@@ -72,3 +72,88 @@ private extension UIColor {
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)
}
}