// // PaymentCollectionDetailsViewModelTests.swift // suixinkanTests // import XCTest @testable import suixinkan /// 收款详情 ViewModel 测试。 @MainActor final class PaymentCollectionDetailsViewModelTests: XCTestCase { private var appStore: AppStore! override func setUp() { let defaults = UserDefaults(suiteName: "PaymentCollectionDetailsViewModelTests")! defaults.removePersistentDomain(forName: "PaymentCollectionDetailsViewModelTests") appStore = AppStore(defaults: defaults) appStore.session.configureTestAccount(userId: "10001", scenicId: 10) appStore.session.currentScenicName = "测试景区" } override func tearDown() { appStore.logout() super.tearDown() } func testPaymentAmountValidatorRejectsEmptyAmount() { XCTAssertEqual(PaymentAmountValidator.validationMessage(for: ""), "请输入收款金额") } func testPaymentAmountValidatorRejectsZeroAmount() { XCTAssertEqual(PaymentAmountValidator.validationMessage(for: "0"), "请输入有效的收款金额") } func testPaymentAmountValidatorRejectsMoreThanTwoDecimals() { XCTAssertEqual(PaymentAmountValidator.validationMessage(for: "1.234"), "金额最多支持两位小数") } func testPaymentAmountValidatorAcceptsValidAmount() { XCTAssertNil(PaymentAmountValidator.validationMessage(for: "12.50")) } func testShowSetAmountDialogRequiresPayCode() { let viewModel = PaymentCollectionDetailsViewModel(appStore: appStore) var message: String? viewModel.onShowMessage = { message = $0 } viewModel.showSetAmountDialog() XCTAssertEqual(message, "请先获取收款码") XCTAssertFalse(viewModel.showAmountDialog) } func testConfirmAmountBuildsDynamicURL() async throws { let payCodeJSON = """ {"code":100000,"msg":"success","data":{"static_pay_url":"https://pay.example.com/static","dynamic_pay_url":"https://pay.example.com/dynamic"}} """.data(using: .utf8)! let session = MockURLSession(responses: [payCodeJSON]) let api = PaymentAPI(client: APIClient(environment: .testing, session: session)) let viewModel = PaymentCollectionDetailsViewModel(appStore: appStore) await viewModel.loadPayCode(api: api) viewModel.updateAmount("88.50") viewModel.updateRemark("测试备注") viewModel.confirmAmount() XCTAssertTrue(viewModel.hasPayCode) XCTAssertFalse(viewModel.showAmountDialog) } func testToggleReceiveVoicePersistsInAppStore() { let viewModel = PaymentCollectionDetailsViewModel(appStore: appStore) viewModel.refreshLocalState() XCTAssertFalse(viewModel.isVoiceBroadcastOpen) viewModel.toggleReceiveVoice() XCTAssertTrue(appStore.payment.isOpenReceiveVoice) XCTAssertTrue(viewModel.isVoiceBroadcastOpen) } func testLoadPayCodeClearsQRWhenScenicMissing() async { appStore.session.currentScenicId = 0 let session = MockURLSession(responses: []) let api = PaymentAPI(client: APIClient(environment: .testing, session: session)) let viewModel = PaymentCollectionDetailsViewModel(appStore: appStore) await viewModel.loadPayCode(api: api) XCTAssertFalse(viewModel.hasPayCode) XCTAssertEqual(session.requests.count, 0) } }