Files
suixinkan_ios_uikit/suixinkan_iosTests/ScenicSettlement/ScenicSettlementViewModelTests.swift
2026-06-26 14:33:31 +08:00

213 lines
8.0 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// ScenicSettlementViewModelTests.swift
// suixinkanTests
//
// Created by Codex on 2026/6/25.
//
import XCTest
@testable import suixinkan_ios
@MainActor
///
final class ScenicSettlementViewModelTests: XCTestCase {
///
func testSettlementLoadExcludesExistingScenics() async {
let permissionAPI = ScenicSettlementPermissionMock()
permissionAPI.scenicList = ScenicListAllResponse(total: 3, list: [
ScenicListItem(id: 1, name: "已有景区"),
ScenicListItem(id: 2, name: "新增景区"),
ScenicListItem(id: 3, name: "另一个景区")
])
let viewModel = ScenicSettlementViewModel()
await viewModel.load(
api: permissionAPI,
existingScenics: [BusinessScope(id: 1, name: "已有景区", kind: .scenic)]
)
XCTAssertEqual(viewModel.options.map(\.id), [2, 3])
}
/// 0
func testSettlementAmountValidation() {
let viewModel = ScenicSettlementViewModel()
XCTAssertEqual(viewModel.amountValidation, .empty)
viewModel.amountText = "0"
XCTAssertEqual(viewModel.amountValidation, .notPositive)
viewModel.amountText = "-1"
XCTAssertEqual(viewModel.amountValidation, .invalidFormat)
viewModel.amountText = "1.234"
XCTAssertEqual(viewModel.amountValidation, .invalidFormat)
viewModel.amountText = "12.30"
XCTAssertEqual(viewModel.amountValidation, .valid)
}
/// body
func testSettlementSubmitMultipleScenicsAndClearsForm() async {
let submitAPI = ScenicSettlementSubmitMock()
let viewModel = ScenicSettlementViewModel()
viewModel.options = [
ScenicSettlementOption(id: 3, name: "三号", selected: false),
ScenicSettlementOption(id: 2, name: "二号", selected: false)
]
viewModel.toggleScenic(id: 3)
viewModel.toggleScenic(id: 2)
viewModel.amountText = "99"
viewModel.remarkText = " 活动结算 "
let success = await viewModel.submit(api: submitAPI)
XCTAssertTrue(success)
XCTAssertEqual(submitAPI.requests, [
ScenicSettlementSubmitRequest(scenicId: 2, applyAmount: "99.00", applyRemark: "活动结算"),
ScenicSettlementSubmitRequest(scenicId: 3, applyAmount: "99.00", applyRemark: "活动结算")
])
XCTAssertTrue(viewModel.selectedScenicIds.isEmpty)
XCTAssertEqual(viewModel.amountText, "")
XCTAssertEqual(viewModel.remarkText, "")
XCTAssertEqual(viewModel.message, "提交成功,等待审核")
}
///
func testSettlementSubmitFailureKeepsForm() async {
let submitAPI = ScenicSettlementSubmitMock()
submitAPI.errorAfterRequestCount = 1
let viewModel = ScenicSettlementViewModel()
viewModel.options = [
ScenicSettlementOption(id: 1, name: "一号", selected: false),
ScenicSettlementOption(id: 2, name: "二号", selected: false)
]
viewModel.toggleScenic(id: 1)
viewModel.toggleScenic(id: 2)
viewModel.amountText = "10"
let success = await viewModel.submit(api: submitAPI)
XCTAssertFalse(success)
XCTAssertEqual(viewModel.selectedScenicIds, [1, 2])
XCTAssertEqual(viewModel.amountText, "10")
XCTAssertEqual(viewModel.message, TestError.sample.localizedDescription)
}
///
func testReviewLoadSuccessAggregatesRecords() async {
let permissionAPI = ScenicSettlementPermissionMock()
permissionAPI.scenicPendings = ScenicApplicationPendingsResponse(items: [
ScenicApplicationPendingResponse(id: 1, scenicName: "景区", status: 1)
])
permissionAPI.roleApplies = [
RoleApplyPendingResponse(id: 2, roleId: 1, roleName: "摄影师", status: 2)
]
let viewModel = ScenicSettlementReviewViewModel()
await viewModel.load(api: permissionAPI)
XCTAssertEqual(viewModel.scenicApplications.count, 1)
XCTAssertEqual(viewModel.roleApplications.count, 1)
XCTAssertEqual(viewModel.pendingCount, 1)
XCTAssertFalse(viewModel.loadFailedAll)
}
///
func testReviewSingleChannelFailureKeepsOtherChannel() async {
let permissionAPI = ScenicSettlementPermissionMock()
permissionAPI.scenicPendingsError = TestError.sample
permissionAPI.roleApplies = [
RoleApplyPendingResponse(id: 2, roleId: 1, roleName: "摄影师", status: 1)
]
let viewModel = ScenicSettlementReviewViewModel()
await viewModel.load(api: permissionAPI)
XCTAssertTrue(viewModel.scenicLoadFailed)
XCTAssertFalse(viewModel.roleLoadFailed)
XCTAssertFalse(viewModel.loadFailedAll)
XCTAssertEqual(viewModel.roleApplications.count, 1)
}
///
func testReviewBothChannelsFailureMarksFullFailure() async {
let permissionAPI = ScenicSettlementPermissionMock()
permissionAPI.scenicPendingsError = TestError.sample
permissionAPI.roleAppliesError = TestError.sample
let viewModel = ScenicSettlementReviewViewModel()
await viewModel.load(api: permissionAPI)
XCTAssertTrue(viewModel.loadFailedAll)
XCTAssertTrue(viewModel.scenicApplications.isEmpty)
XCTAssertTrue(viewModel.roleApplications.isEmpty)
}
///
func testReviewStatusMapping() {
let viewModel = ScenicSettlementReviewViewModel()
XCTAssertEqual(viewModel.statusText(1), "待审核")
XCTAssertEqual(viewModel.statusText(2), "已通过")
XCTAssertEqual(viewModel.statusText(3), "已驳回")
XCTAssertEqual(viewModel.statusText(9), "已取消")
XCTAssertEqual(viewModel.statusText(99), "未知")
XCTAssertEqual(viewModel.statusIcon(2), "checkmark.circle.fill")
}
}
@MainActor
private final class ScenicSettlementPermissionMock: ScenicPermissionServing {
var scenicList = ScenicListAllResponse(total: 0, list: [])
var scenicListError: Error?
var scenicPendings = ScenicApplicationPendingsResponse()
var scenicPendingsError: Error?
var roleApplies: [RoleApplyPendingResponse] = []
var roleAppliesError: Error?
func scenicListAll() async throws -> ScenicListAllResponse {
if let scenicListError { throw scenicListError }
return scenicList
}
func areas() async throws -> [ScenicAreaNode] { [] }
func scenicApplicationPendingAll() async throws -> ScenicApplicationPendingsResponse {
if let scenicPendingsError { throw scenicPendingsError }
return scenicPendings
}
func scenicSubmit(_ request: ScenicApplicationSubmitRequest) async throws {}
func scenicApplicationUploadPlaceholder(_ items: [ScenicApplicationUploadPlaceholder]) async throws {}
func roleApplyAll() async throws -> [RoleApplyPendingResponse] {
if let roleAppliesError { throw roleAppliesError }
return roleApplies
}
func roleApplySubmit(roleId: Int, scenicIds: [Int]) async throws {}
}
@MainActor
private final class ScenicSettlementSubmitMock: ScenicSettlementServing {
var requests: [ScenicSettlementSubmitRequest] = []
var errorAfterRequestCount: Int?
func scenicSettlementSubmit(_ request: ScenicSettlementSubmitRequest) async throws {
requests.append(request)
if let errorAfterRequestCount, requests.count >= errorAfterRequestCount {
throw TestError.sample
}
}
}
private enum TestError: LocalizedError {
case sample
var errorDescription: String? {
"测试错误"
}
}