182 lines
7.3 KiB
Swift
182 lines
7.3 KiB
Swift
//
|
|
// 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 testNalatiAccountInfoUsesLoggedInPhotographerAndAllPermissionStores() {
|
|
appStore.session.userName = "摄影师小王"
|
|
appStore.permissions.saveRolePermissionList([
|
|
RolePermissionResponse(
|
|
role: RoleInfo(id: 41, name: "摄影师", roleCode: "photographer"),
|
|
store: [
|
|
RolePermissionStoreInfo(id: 1, name: "空中草原店"),
|
|
RolePermissionStoreInfo(id: 2, name: "河谷草原店"),
|
|
]
|
|
),
|
|
])
|
|
|
|
let viewModel = PaymentCollectionDetailsViewModel(appStore: appStore)
|
|
|
|
XCTAssertEqual(viewModel.displayPhotographerName, "摄影师小王")
|
|
XCTAssertEqual(viewModel.displayStoreNames, "空中草原店、河谷草原店")
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
func testNalatiLoadsCachedConfigBeforeRefreshingRemoteConfig() async throws {
|
|
let defaults = UserDefaults(suiteName: "PaymentCollectionDetailsViewModelTests.Config")!
|
|
defaults.removePersistentDomain(forName: "PaymentCollectionDetailsViewModelTests.Config")
|
|
let cache = PayPageConfigCache(defaults: defaults, environment: .testing)
|
|
let cached = PayPageConfig(
|
|
background: "https://cache.example.com/background.png",
|
|
logo: "https://cache.example.com/logo.png",
|
|
title: "缓存标题",
|
|
subtitle: "缓存副标题"
|
|
)
|
|
cache.save(cached, scenicId: 128)
|
|
appStore.session.currentScenicId = 128
|
|
appStore.session.currentScenicName = "那拉提景区"
|
|
|
|
let responseJSON = """
|
|
{"code":100000,"msg":"success","data":{
|
|
"background":"https://new.example.com/background.png",
|
|
"logo":"",
|
|
"title":"最新标题",
|
|
"subtitle":""
|
|
}}
|
|
""".data(using: .utf8)!
|
|
let session = MockURLSession(responses: [responseJSON])
|
|
let api = PaymentAPI(client: APIClient(environment: .testing, session: session))
|
|
let viewModel = PaymentCollectionDetailsViewModel(
|
|
appStore: appStore,
|
|
payPageConfigCache: cache
|
|
)
|
|
|
|
XCTAssertEqual(viewModel.payPageConfig, cached)
|
|
await viewModel.loadPayPageConfig(api: api)
|
|
|
|
XCTAssertEqual(viewModel.payPageConfig.background, "https://new.example.com/background.png")
|
|
XCTAssertEqual(viewModel.payPageConfig.logo, cached.logo)
|
|
XCTAssertEqual(viewModel.payPageConfig.title, "最新标题")
|
|
XCTAssertEqual(viewModel.payPageConfig.subtitle, cached.subtitle)
|
|
XCTAssertEqual(viewModel.brandingRefreshVersion, 1)
|
|
XCTAssertEqual(session.requests.first?.url?.path, "/api/yf-handset-app/photog/pay-page-config")
|
|
XCTAssertEqual(
|
|
URLComponents(url: try XCTUnwrap(session.requests.first?.url), resolvingAgainstBaseURL: false)?
|
|
.queryItems?
|
|
.first(where: { $0.name == "scenic_id" })?
|
|
.value,
|
|
"128"
|
|
)
|
|
}
|
|
|
|
func testNonNalatiDoesNotRequestPayPageConfig() async {
|
|
let session = MockURLSession(responses: [])
|
|
let api = PaymentAPI(client: APIClient(environment: .testing, session: session))
|
|
let viewModel = PaymentCollectionDetailsViewModel(appStore: appStore)
|
|
|
|
await viewModel.loadPayPageConfig(api: api)
|
|
|
|
XCTAssertFalse(viewModel.usesNalatiBranding)
|
|
XCTAssertEqual(session.requests.count, 0)
|
|
}
|
|
|
|
func testPayPageConfigCacheIsEnvironmentScoped() {
|
|
let defaults = UserDefaults(suiteName: "PaymentCollectionDetailsViewModelTests.Environment")!
|
|
defaults.removePersistentDomain(forName: "PaymentCollectionDetailsViewModelTests.Environment")
|
|
let production = PayPageConfigCache(defaults: defaults, environment: .production)
|
|
let testing = PayPageConfigCache(defaults: defaults, environment: .testing)
|
|
|
|
production.save(.nalatiDefault, scenicId: 128)
|
|
|
|
XCTAssertEqual(production.config(scenicId: 128), .nalatiDefault)
|
|
XCTAssertNil(testing.config(scenicId: 128))
|
|
}
|
|
}
|