// // BindAcquirerViewModelTests.swift // suixinkanTests // // Created by Codex on 2026/7/3. // import XCTest @testable import suixinkan /// 绑定获客员 ViewModel 分账比例校验测试。 @MainActor final class BindAcquirerViewModelTests: XCTestCase { /// 测试分账比例输入只保留数字且最多 3 位。 func testUpdateCommissionRateDraftFiltersInput() { let viewModel = BindAcquirerViewModel() viewModel.updateCommissionRateDraft("12a3.4") XCTAssertEqual(viewModel.commissionRateDraft, "123") viewModel.updateCommissionRateDraft("1234") XCTAssertEqual(viewModel.commissionRateDraft, "123") } /// 测试未填写分账比例时提交失败。 func testAcceptBindRequiresCommissionRate() async { let viewModel = BindAcquirerViewModel() let api = BindAcquirerMockAPI() await viewModel.load(api: api, saleUserId: 101) do { try await viewModel.acceptBind(api: api) XCTFail("Expected validation error") } catch let error as CooperationOrderCommissionRateValidationError { XCTAssertEqual(error.message, "请输入分账比例") } catch { XCTFail("Unexpected error: \(error)") } XCTAssertEqual(api.acceptBindCalls.count, 0) } /// 测试分账比例超出范围时提交失败。 func testAcceptBindRejectsOutOfRangeCommissionRate() async { let viewModel = BindAcquirerViewModel() let api = BindAcquirerMockAPI() await viewModel.load(api: api, saleUserId: 101) viewModel.updateCommissionRateDraft("101") do { try await viewModel.acceptBind(api: api) XCTFail("Expected validation error") } catch let error as CooperationOrderCommissionRateValidationError { XCTAssertEqual(error.message, "分账比例需在0到100之间") } catch { XCTFail("Unexpected error: \(error)") } XCTAssertEqual(api.acceptBindCalls.count, 0) } /// 测试合法分账比例时调用 accept-bind 接口。 func testAcceptBindPassesCommissionRateToAPI() async throws { let viewModel = BindAcquirerViewModel() let api = BindAcquirerMockAPI() await viewModel.load(api: api, saleUserId: 101) viewModel.updateCommissionRateDraft("20") try await viewModel.acceptBind(api: api) XCTAssertEqual(api.acceptBindCalls.count, 1) XCTAssertEqual(api.acceptBindCalls.first?.saleUserId, 101) XCTAssertEqual(api.acceptBindCalls.first?.commissionRate, 20) } } @MainActor private final class BindAcquirerMockAPI: CooperationOrderServing { struct AcceptBindCall { let saleUserId: Int let commissionRate: Int } var acceptBindCalls: [AcceptBindCall] = [] func cooperativeSalers(storeId: Int?, page: Int, pageSize: Int) async throws -> CooperativeSalerListPayload { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserInviteInfo(saleUserId: Int) async throws -> SaleUserInviteInfo { SaleUserInviteInfo( saleUserId: saleUserId, salerName: "测试获客员", salerPhone: "13800138000" ) } func saleUserAcceptBind(saleUserId: Int, commissionRate: Int) async throws { acceptBindCalls.append(AcceptBindCall(saleUserId: saleUserId, commissionRate: commissionRate)) } func saleUserReferralLeads(page: Int, pageSize: Int) async throws -> ListPayload { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserAcquisitionOrders(keyword: String?, page: Int, pageSize: Int) async throws -> ListPayload { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserReferralOrders(saleUserId: Int, page: Int, pageSize: Int) async throws -> ReferralOrderListPayload { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserBindReferralOrder(orderNumber: String, referralOrderNo: String) async throws { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserUpdateReferralOrderStatus(id: Int, status: Int) async throws { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserUpdateRemark(saleUserId: Int, photogRemarkName: String) async throws { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserCommissionRateSendSmsCode(phone: String) async throws { fatalError("Not used in BindAcquirerViewModelTests") } func saleUserUpdateCommissionRate( saleUserId: Int, commissionRate: Int, smsCode: String ) async throws -> CooperativeSaler { fatalError("Not used in BindAcquirerViewModelTests") } }