Initial commit: suixinkan_ios UIKit rewrite project.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
108
suixinkan_iosTests/PaymentViewModelTests.swift
Normal file
108
suixinkan_iosTests/PaymentViewModelTests.swift
Normal file
@ -0,0 +1,108 @@
|
||||
//
|
||||
// PaymentViewModelTests.swift
|
||||
// suixinkanTests
|
||||
//
|
||||
// Created by Codex on 2026/6/22.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import suixinkan_ios
|
||||
|
||||
@MainActor
|
||||
/// 收款模块测试,覆盖收款码、动态二维码、轮询和记录分组。
|
||||
final class PaymentViewModelTests: XCTestCase {
|
||||
/// 测试无景区时清空二维码且不请求接口。
|
||||
func testLoadPayCodeWithoutScenicClearsState() async {
|
||||
let api = PaymentMockAPI()
|
||||
let viewModel = PaymentCollectionViewModel()
|
||||
viewModel.staticPayUrl = "old"
|
||||
|
||||
await viewModel.loadPayCode(api: api, scenicId: nil)
|
||||
|
||||
XCTAssertTrue(viewModel.staticPayUrl.isEmpty)
|
||||
XCTAssertEqual(api.payCodeScenicIds, [])
|
||||
XCTAssertEqual(viewModel.errorMessage, "请先选择景区")
|
||||
}
|
||||
|
||||
/// 测试收款码接口加载后生成当前二维码 URL。
|
||||
func testLoadPayCodeUsesScenicIdAndAppliesStaticURL() async {
|
||||
let api = PaymentMockAPI()
|
||||
api.payCodeResponse = PayCodeResponse(staticPayUrl: "https://pay.example.com/static", dynamicPayUrl: "https://pay.example.com/dynamic")
|
||||
let viewModel = PaymentCollectionViewModel()
|
||||
|
||||
await viewModel.loadPayCode(api: api, scenicId: 9)
|
||||
|
||||
XCTAssertEqual(api.payCodeScenicIds, [9])
|
||||
XCTAssertEqual(viewModel.currentPayUrl, "https://pay.example.com/static")
|
||||
XCTAssertTrue(viewModel.hasStaticPayCode)
|
||||
}
|
||||
|
||||
/// 测试设置金额会校验金额并生成动态收款 URL。
|
||||
func testApplyDynamicAmountBuildsDynamicURL() async {
|
||||
let viewModel = PaymentCollectionViewModel()
|
||||
viewModel.dynamicPayUrl = "https://pay.example.com/dynamic?scenic_id=9"
|
||||
viewModel.amountText = "12.345"
|
||||
viewModel.remarkText = "茶水"
|
||||
|
||||
XCTAssertTrue(viewModel.applyDynamicAmount())
|
||||
XCTAssertTrue(viewModel.currentPayUrl.contains("amount=12.35"))
|
||||
XCTAssertTrue(viewModel.currentPayUrl.contains("remark="))
|
||||
XCTAssertEqual(viewModel.status, .waiting)
|
||||
}
|
||||
|
||||
/// 测试轮询命中新收款记录后进入成功态。
|
||||
func testPollingFindsNewPaymentRecord() async {
|
||||
let api = PaymentMockAPI()
|
||||
api.recordResponses = [
|
||||
PaymentCollectionRecordResponse(list: [
|
||||
PaymentCollectionRecordItem(orderNumber: "A", userPhone: "138", orderAmount: "8.00", createDate: "2026-06-22", createTime: "10:00")
|
||||
]),
|
||||
PaymentCollectionRecordResponse(list: [
|
||||
PaymentCollectionRecordItem(orderNumber: "A", userPhone: "138", orderAmount: "8.00", createDate: "2026-06-22", createTime: "10:00"),
|
||||
PaymentCollectionRecordItem(orderNumber: "B", userPhone: "139", orderAmount: "12.35", createDate: "2026-06-22", createTime: "10:01")
|
||||
])
|
||||
]
|
||||
let viewModel = PaymentCollectionViewModel()
|
||||
viewModel.amountText = "12.35"
|
||||
await viewModel.primePaymentRecords(api: api, scenicId: 9)
|
||||
|
||||
await viewModel.pollUntilPaymentDetected(api: api, scenicId: 9, maxAttempts: 1, intervalNanoseconds: 0)
|
||||
|
||||
XCTAssertEqual(viewModel.status, .success(PaymentCollectionRecordItem(orderNumber: "B", userPhone: "139", orderAmount: "12.35", createDate: "2026-06-22", createTime: "10:01")))
|
||||
}
|
||||
|
||||
/// 测试后端缺少日汇总时能从列表兜底生成分组。
|
||||
func testRecordGroupsFallbackFromList() {
|
||||
let response = PaymentCollectionRecordResponse(list: [
|
||||
PaymentCollectionRecordItem(orderNumber: "A", userPhone: "138", orderAmount: "8.00", createDate: "2026-06-21", createTime: "10:00"),
|
||||
PaymentCollectionRecordItem(orderNumber: "B", userPhone: "139", orderAmount: "12.00", createDate: "2026-06-21", createTime: "10:01")
|
||||
])
|
||||
|
||||
let groups = PaymentCollectionRecordViewModel.makeGroups(from: response)
|
||||
|
||||
XCTAssertEqual(groups.count, 1)
|
||||
XCTAssertEqual(groups[0].analyse.orderCount, 2)
|
||||
XCTAssertEqual(groups[0].analyse.orderAmountSum, "20")
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
/// 收款 API 测试替身。
|
||||
private final class PaymentMockAPI: PaymentServing {
|
||||
var payCodeResponse = PayCodeResponse()
|
||||
var recordResponses: [PaymentCollectionRecordResponse] = []
|
||||
private(set) var payCodeScenicIds: [Int] = []
|
||||
private(set) var recordScenicIds: [Int] = []
|
||||
|
||||
/// 记录景区 ID 并返回收款码响应。
|
||||
func payCode(scenicId: Int) async throws -> PayCodeResponse {
|
||||
payCodeScenicIds.append(scenicId)
|
||||
return payCodeResponse
|
||||
}
|
||||
|
||||
/// 记录景区 ID 并返回下一份收款记录响应。
|
||||
func paymentCollectionRecords(scenicId: Int) async throws -> PaymentCollectionRecordResponse {
|
||||
recordScenicIds.append(scenicId)
|
||||
return recordResponses.isEmpty ? PaymentCollectionRecordResponse() : recordResponses.removeFirst()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user