新增订单长尾流程,并迁移排队、消息、结算与审核模块
将定金订单、历史拍摄与多行程上传接入 Orders,并以真实页面替换首页排队管理、消息中心、景区结算与提现审核占位入口。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@ -0,0 +1,125 @@
|
||||
//
|
||||
// WithdrawalAuditViewModelTests.swift
|
||||
// suixinkanTests
|
||||
//
|
||||
// Created by Codex on 2026/6/25.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
@MainActor
|
||||
/// 提现审核测试,覆盖分页、筛选和失败清理。
|
||||
final class WithdrawalAuditViewModelTests: XCTestCase {
|
||||
/// 测试首次加载、筛选统计和分页加载。
|
||||
func testLoadFilterAndLoadMore() async throws {
|
||||
let api = WithdrawalAuditWalletMock()
|
||||
api.withdrawResponses = [
|
||||
WalletWithdrawListResponse(total: 3, item: [
|
||||
try record(id: 1, status: "审核中"),
|
||||
try record(id: 2, status: "已到账")
|
||||
]),
|
||||
WalletWithdrawListResponse(total: 3, item: [
|
||||
try record(id: 3, status: "待打款")
|
||||
])
|
||||
]
|
||||
let viewModel = WithdrawalAuditViewModel()
|
||||
|
||||
await viewModel.reload(api: api)
|
||||
|
||||
XCTAssertEqual(api.withdrawPages, [1])
|
||||
XCTAssertEqual(viewModel.totalCount, 3)
|
||||
XCTAssertEqual(viewModel.processingCount, 1)
|
||||
XCTAssertEqual(viewModel.completedCount, 1)
|
||||
XCTAssertTrue(viewModel.hasMore)
|
||||
|
||||
viewModel.selectFilter(.processing)
|
||||
XCTAssertEqual(viewModel.filteredRecords.map(\.id), [1])
|
||||
|
||||
await viewModel.loadMore(api: api)
|
||||
|
||||
XCTAssertEqual(api.withdrawPages, [1, 2])
|
||||
XCTAssertEqual(viewModel.records.map(\.id), [1, 2, 3])
|
||||
XCTAssertEqual(viewModel.processingCount, 2)
|
||||
XCTAssertFalse(viewModel.hasMore)
|
||||
}
|
||||
|
||||
/// 测试刷新失败会清空旧记录和分页状态。
|
||||
func testReloadFailureClearsStaleRecordsAndPaging() async throws {
|
||||
let api = WithdrawalAuditWalletMock()
|
||||
api.withdrawResponses = [
|
||||
WalletWithdrawListResponse(total: 2, item: [try record(id: 1, status: "审核中")])
|
||||
]
|
||||
let viewModel = WithdrawalAuditViewModel()
|
||||
|
||||
await viewModel.reload(api: api)
|
||||
XCTAssertEqual(viewModel.records.map(\.id), [1])
|
||||
XCTAssertTrue(viewModel.hasMore)
|
||||
|
||||
api.withdrawError = TestError.sample
|
||||
await viewModel.reload(api: api)
|
||||
|
||||
XCTAssertTrue(viewModel.records.isEmpty)
|
||||
XCTAssertFalse(viewModel.hasMore)
|
||||
XCTAssertTrue(viewModel.loadFailed)
|
||||
XCTAssertEqual(viewModel.loadFailureReason, TestError.sample.localizedDescription)
|
||||
}
|
||||
|
||||
/// 测试空列表和尾页边界不会继续加载。
|
||||
func testEmptyListAndLastPageDoNotLoadMore() async {
|
||||
let api = WithdrawalAuditWalletMock()
|
||||
api.withdrawResponses = [WalletWithdrawListResponse(total: 0, item: [])]
|
||||
let viewModel = WithdrawalAuditViewModel()
|
||||
|
||||
await viewModel.reload(api: api)
|
||||
await viewModel.loadMore(api: api)
|
||||
|
||||
XCTAssertTrue(viewModel.records.isEmpty)
|
||||
XCTAssertEqual(api.withdrawPages, [1])
|
||||
XCTAssertFalse(viewModel.hasMore)
|
||||
}
|
||||
|
||||
private func record(id: Int64, amount: String = "10", status: String) throws -> WalletWithdrawRecord {
|
||||
let data = """
|
||||
{"id":\(id),"amount":"\(amount)","created_at":"2026-06-25 10:00","status_label":"\(status)","expected_at":"2026-06-26","audit_time":"2026-06-25 11:00","completed_at":""}
|
||||
""".data(using: .utf8)!
|
||||
return try JSONDecoder().decode(WalletWithdrawRecord.self, from: data)
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private final class WithdrawalAuditWalletMock: WalletServing {
|
||||
var withdrawResponses: [WalletWithdrawListResponse] = []
|
||||
var withdrawError: Error?
|
||||
private(set) var withdrawPages: [Int] = []
|
||||
|
||||
func walletSummary(type: Int) async throws -> WalletSummaryResponse { WalletSummaryResponse() }
|
||||
func walletEarningDetail(startDate: String, endDate: String, page: Int, pageSize: Int) async throws -> WalletEarningDetailResponse { WalletEarningDetailResponse() }
|
||||
func walletWithdrawList(page: Int, pageSize: Int) async throws -> WalletWithdrawListResponse {
|
||||
withdrawPages.append(page)
|
||||
if let withdrawError { throw withdrawError }
|
||||
return withdrawResponses.isEmpty ? WalletWithdrawListResponse() : withdrawResponses.removeFirst()
|
||||
}
|
||||
func withdrawInfo() async throws -> WithdrawInfoResponse {
|
||||
let data = #"{"amount_withdrawable":"0","min_withdraw_amount":"1","max_single_withdraw_amount":"100","max_daily_withdraw_amount":"100","user_phone":"13800000000","bank_card":{},"withdraw_info":[]}"#.data(using: .utf8)!
|
||||
return try JSONDecoder().decode(WithdrawInfoResponse.self, from: data)
|
||||
}
|
||||
func withdrawSendSms() async throws {}
|
||||
func withdrawApply(amount: String, smsCode: String) async throws {}
|
||||
func bankCardInfo() async throws -> BankCardInfoResponse { BankCardInfoResponse(bankCard: nil) }
|
||||
func bankList() async throws -> BankListResponse { BankListResponse() }
|
||||
func areas() async throws -> [AreaNode] { [] }
|
||||
func bankCardVerifyCode() async throws {}
|
||||
func updateBankInfo(_ request: UpdateBankInfoRequest) async throws {}
|
||||
func pointOverview(staffId: Int) async throws -> PointOverviewResponse { PointOverviewResponse() }
|
||||
func pointWithdrawApply(points: Int, remark: String) async throws {}
|
||||
func pointWithdrawList(status: Int?, page: Int, pageSize: Int) async throws -> PointWithdrawListResponse { PointWithdrawListResponse() }
|
||||
}
|
||||
|
||||
private enum TestError: LocalizedError {
|
||||
case sample
|
||||
|
||||
var errorDescription: String? {
|
||||
"测试错误"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user