升级 AppStore 缓存 Key 并在覆盖安装时强制重新登录。
统一账号作用域 Key 对齐 Android,新增缓存 schema 迁移清理旧数据,并同步更新相关模块与单元测试。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
160
suixinkanTests/AppStoreCacheMigrationTests.swift
Normal file
160
suixinkanTests/AppStoreCacheMigrationTests.swift
Normal file
@ -0,0 +1,160 @@
|
||||
//
|
||||
// AppStoreCacheMigrationTests.swift
|
||||
// suixinkanTests
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
/// 验证覆盖升级清理、强制退出以及缓存结构版本幂等性。
|
||||
final class AppStoreCacheMigrationTests: XCTestCase {
|
||||
|
||||
private var suiteName: String!
|
||||
private var defaults: UserDefaults!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
suiteName = "AppStoreCacheMigrationTests.\(UUID().uuidString)"
|
||||
defaults = UserDefaults(suiteName: suiteName)
|
||||
defaults.removePersistentDomain(forName: suiteName)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
defaults.removePersistentDomain(forName: suiteName)
|
||||
defaults = nil
|
||||
suiteName = nil
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testFirstInitializationClearsLegacyAndPreReleaseKeysAndForcesLogout() {
|
||||
let exactKeysToRemove = [
|
||||
"suixinkan.session.v1",
|
||||
"apns_device_token",
|
||||
"apns_uploaded_token",
|
||||
"home.common.menu.uris",
|
||||
"home.common.menu.android.baseline.v2",
|
||||
"home.routing.unknown.records",
|
||||
"payment.voice.broadcast.enabled",
|
||||
"key_in_token",
|
||||
"key_last_login_username",
|
||||
"key_privacy_agreement_accepted",
|
||||
"key_in_user_id",
|
||||
"key_in_user_name",
|
||||
"key_in_real_name",
|
||||
"key_in_avatar",
|
||||
"key_in_phone",
|
||||
"key_in_account_type",
|
||||
"key_in_account_display_name",
|
||||
"key_in_role_id",
|
||||
"key_in_role_code",
|
||||
"key_in_role_name",
|
||||
"key_in_current_scenic_id",
|
||||
"key_in_current_scenic_name",
|
||||
"key_in_current_store_id",
|
||||
"key_role_permission_list",
|
||||
"key_in_permission",
|
||||
"key_current_role_scenic_list",
|
||||
"key_online_status",
|
||||
"key_last_location_report_time",
|
||||
"key_location_reminder_minutes",
|
||||
"key_is_open_receive_voice",
|
||||
"scenic_queue_tts_enabled",
|
||||
"scenic_queue_background_poll_enabled",
|
||||
"scenic_queue_selected_spot_id",
|
||||
"scenic_queue_selected_spot_name",
|
||||
"scenic_queue_custom_tts_text",
|
||||
"scenic_queue_photo_estimate_seconds",
|
||||
"scenic_queue_broadcast_interval_seconds",
|
||||
"scenic_queue_countdown_threshold_seconds",
|
||||
"scenic_queue_show_start_shooting_button",
|
||||
"scenic_queue_auto_call_ahead_count",
|
||||
"scenic_queue_quick_call_button_enabled",
|
||||
"scenic_queue_prepare_call_button_enabled",
|
||||
"scenic_queue_config_logs",
|
||||
"scenic_queue_settings_snapshot",
|
||||
"scenic_queue_preset_voices",
|
||||
]
|
||||
let dynamicKeysToRemove = [
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_id",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_name",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_custom_tts_text_spot_33",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_settings_snapshot_spot_33",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_preset_voices_spot_33",
|
||||
"scenic_22_spot_33_scenic_queue_settings_snapshot",
|
||||
"scenic_22_spot_33_scenic_queue_preset_voices",
|
||||
"scenic_22_scenic_queue_settings_snapshot",
|
||||
"1001_store_user_key_in_role_id",
|
||||
"1001_store_user_key_role_permission_list",
|
||||
"1001_store_user_key_in_permission",
|
||||
"1001_store_user_key_current_role_scenic_list",
|
||||
"1001_store_user_key_online_status",
|
||||
"1001_store_user_key_last_location_report_time",
|
||||
"1001_store_user_key_location_reminder_minutes",
|
||||
"1001_store_user_key_is_open_receive_voice",
|
||||
"1001_store_user_role__common_uris",
|
||||
"1001_store_user_role_photographer_common_uris",
|
||||
"1001_store_user__scenic_queue_punch_spot_id",
|
||||
"1001_store_user__scenic_queue_punch_spot_name",
|
||||
"1001_store_user__scenic_queue_punch_spot_remark",
|
||||
"1001_store_user__scenic_queue_remark",
|
||||
"1001_store_user__scenic_queue_settings_snapshot",
|
||||
"1001_store_user__scenic_queue_offline_tts_v1",
|
||||
"1001_store_user__scenic_queue_preset_voices_v1",
|
||||
]
|
||||
let keysToPreserve = [
|
||||
"third_party.sentinel",
|
||||
"home.common.menu.uris.extra",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_selected_spot_identifier",
|
||||
"account_store_user_1001_31_22_scenic_22_scenic_queue_custom_tts_text_spot_33_backup",
|
||||
"scenic_22_spot_33_scenic_queue_settings_snapshot_backup",
|
||||
"unrelated_key_in_permission_extra",
|
||||
"scenic_user_1001_key_in_role_code",
|
||||
"scenic_user_1001_scenic_22_scenic_queue_punch_spot_id",
|
||||
"scenic_user_1001_scenic_22_spot_33_scenic_queue_settings_snapshot",
|
||||
]
|
||||
let keysToRemove = exactKeysToRemove + dynamicKeysToRemove
|
||||
keysToRemove.forEach { defaults.set("legacy", forKey: $0) }
|
||||
keysToPreserve.forEach { defaults.set("keep", forKey: $0) }
|
||||
defaults.set(true, forKey: "key_privacy_agreement_accepted")
|
||||
|
||||
let store = AppStore(defaults: defaults)
|
||||
|
||||
XCTAssertFalse(store.session.isLoggedIn)
|
||||
XCTAssertNil(store.session.lastLoginUsername)
|
||||
XCTAssertFalse(store.session.privacyAgreementAccepted)
|
||||
keysToRemove.forEach { XCTAssertNil(defaults.object(forKey: $0), "未清理 Key:\($0)") }
|
||||
keysToPreserve.forEach {
|
||||
XCTAssertEqual(defaults.string(forKey: $0), "keep", "误清理 Key:\($0)")
|
||||
}
|
||||
XCTAssertEqual(
|
||||
defaults.integer(forKey: AppStoreCacheMigrator.schemaVersionKey),
|
||||
AppStoreCacheMigrator.currentSchemaVersion
|
||||
)
|
||||
}
|
||||
|
||||
func testMigrationRunsOnlyOnceAndPreservesNewSession() {
|
||||
defaults.set("keep", forKey: "third_party.sentinel")
|
||||
var store = AppStore(defaults: defaults)
|
||||
store.session.token = "new-token"
|
||||
store.session.lastLoginUsername = "13800000000"
|
||||
store.session.privacyAgreementAccepted = true
|
||||
store.session.userId = "1001"
|
||||
store.session.accountType = .scenicUser
|
||||
store.session.roleCode = "photographer"
|
||||
store.session.currentScenicId = 22
|
||||
store.scenicQueue.punchSpotId = "33"
|
||||
store.scenicQueue.punchSpotName = "东门"
|
||||
|
||||
store = AppStore(defaults: defaults)
|
||||
|
||||
XCTAssertTrue(store.session.isLoggedIn)
|
||||
XCTAssertEqual(store.session.token, "new-token")
|
||||
XCTAssertEqual(store.session.lastLoginUsername, "13800000000")
|
||||
XCTAssertTrue(store.session.privacyAgreementAccepted)
|
||||
XCTAssertEqual(store.session.roleCode, "photographer")
|
||||
XCTAssertEqual(store.session.currentScenicId, 22)
|
||||
XCTAssertEqual(store.scenicQueue.punchSpotId, "33")
|
||||
XCTAssertEqual(store.scenicQueue.punchSpotName, "东门")
|
||||
XCTAssertEqual(defaults.string(forKey: "third_party.sentinel"), "keep")
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@ final class AppStoreModuleTests: XCTestCase {
|
||||
XCTAssertEqual(AppAccountType.unknown("future_account").rawValue, "future_account")
|
||||
}
|
||||
|
||||
func testSessionUsesExistingKeysAndPreservesUnknownAccountType() {
|
||||
func testSessionUsesGlobalIdentityAndScopedBusinessContext() {
|
||||
defaults.set("legacy-token", forKey: "key_in_token")
|
||||
defaults.set("future_account", forKey: "key_in_account_type")
|
||||
|
||||
@ -46,11 +46,37 @@ final class AppStoreModuleTests: XCTestCase {
|
||||
XCTAssertEqual(appStore.session.accountType, .unknown("future_account"))
|
||||
|
||||
appStore.session.userId = "1001"
|
||||
appStore.session.roleCode = "future_role"
|
||||
appStore.session.currentScenicId = 22
|
||||
appStore.session.currentScenicName = "测试景区"
|
||||
appStore.session.currentStoreId = 31
|
||||
|
||||
XCTAssertEqual(defaults.string(forKey: "key_in_user_id"), "1001")
|
||||
XCTAssertEqual(defaults.string(forKey: "key_in_current_scenic_id"), "22")
|
||||
XCTAssertEqual(appStore.session.accountCachePrefix, "1001_future_account")
|
||||
XCTAssertNil(defaults.object(forKey: "key_in_current_scenic_id"))
|
||||
XCTAssertEqual(defaults.string(forKey: "future_account_1001_key_in_role_code"), "future_role")
|
||||
XCTAssertEqual(defaults.string(forKey: "future_account_1001_key_in_current_scenic_id"), "22")
|
||||
XCTAssertEqual(defaults.string(forKey: "future_account_1001_key_in_current_scenic_name"), "测试景区")
|
||||
XCTAssertEqual(defaults.integer(forKey: "future_account_1001_scenic_22_scenic_store_id"), 31)
|
||||
XCTAssertEqual(appStore.session.accountCachePrefix, "future_account_1001")
|
||||
}
|
||||
|
||||
func testIncompleteAccountScopeDoesNotWriteBusinessCache() {
|
||||
appStore.session.userId = "1001"
|
||||
appStore.session.currentScenicId = 22
|
||||
appStore.session.roleCode = "photographer"
|
||||
appStore.permissions.savePermissionItems([HomePermissionItem(id: "1", name: "钱包", uri: "wallet")])
|
||||
appStore.location.onlineStatus = true
|
||||
appStore.payment.isOpenReceiveVoice = true
|
||||
appStore.scenicQueue.punchSpotId = "33"
|
||||
|
||||
XCTAssertEqual(appStore.session.accountCachePrefix, "")
|
||||
XCTAssertEqual(appStore.session.currentScenicId, 0)
|
||||
XCTAssertEqual(appStore.session.roleCode, "")
|
||||
XCTAssertTrue(appStore.permissions.permissionItems().isEmpty)
|
||||
XCTAssertFalse(appStore.location.onlineStatus)
|
||||
XCTAssertFalse(appStore.payment.isOpenReceiveVoice)
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotId, "")
|
||||
XCTAssertFalse(defaults.dictionaryRepresentation().keys.contains { $0.contains("guest") })
|
||||
}
|
||||
|
||||
func testFeatureStoresAreIsolatedByAccountAndDecodeSnapshots() {
|
||||
@ -68,8 +94,11 @@ final class AppStoreModuleTests: XCTestCase {
|
||||
appStore.payment.isOpenReceiveVoice = true
|
||||
appStore.scenicQueue.punchSpotId = "33"
|
||||
appStore.scenicQueue.punchSpotName = "东门"
|
||||
appStore.scenicQueue.remark = "请提前准备"
|
||||
appStore.scenicQueue.saveSettingsSnapshot(queueSettings)
|
||||
appStore.scenicQueue.savePresetVoices([" A ", "", "B"])
|
||||
XCTAssertTrue(appStore.scenicQueue.useOfflineTTS)
|
||||
appStore.scenicQueue.useOfflineTTS = false
|
||||
|
||||
selectAccount(userId: "2002", type: .storeUser)
|
||||
XCTAssertTrue(appStore.permissions.permissionItems().isEmpty)
|
||||
@ -80,6 +109,7 @@ final class AppStoreModuleTests: XCTestCase {
|
||||
XCTAssertFalse(appStore.payment.isOpenReceiveVoice)
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotId, "")
|
||||
XCTAssertNil(appStore.scenicQueue.settingsSnapshot())
|
||||
XCTAssertTrue(appStore.scenicQueue.useOfflineTTS)
|
||||
|
||||
selectAccount(userId: "1001", type: .scenicUser)
|
||||
XCTAssertEqual(appStore.permissions.permissionItems(), permissions)
|
||||
@ -90,24 +120,68 @@ final class AppStoreModuleTests: XCTestCase {
|
||||
XCTAssertTrue(appStore.payment.isOpenReceiveVoice)
|
||||
XCTAssertTrue(appStore.scenicQueue.hasPunchSpotSaved())
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotName, "东门")
|
||||
XCTAssertEqual(appStore.scenicQueue.remark, "请提前准备")
|
||||
XCTAssertEqual(appStore.scenicQueue.settingsSnapshot(), queueSettings)
|
||||
XCTAssertEqual(appStore.scenicQueue.presetVoices(), ["A", "B"])
|
||||
XCTAssertFalse(appStore.scenicQueue.useOfflineTTS)
|
||||
}
|
||||
|
||||
func testStoreAndQueueCachesAreIsolatedByScenicAndSpot() {
|
||||
selectAccount(userId: "1001", type: .scenicUser, scenicId: 22)
|
||||
appStore.session.currentStoreId = 220
|
||||
appStore.scenicQueue.punchSpotId = "33"
|
||||
appStore.scenicQueue.punchSpotName = "东门"
|
||||
appStore.scenicQueue.remark = "东门备注"
|
||||
appStore.scenicQueue.useOfflineTTS = false
|
||||
|
||||
appStore.scenicQueue.punchSpotId = "44"
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotName, "")
|
||||
XCTAssertEqual(appStore.scenicQueue.remark, "")
|
||||
appStore.scenicQueue.punchSpotName = "西门"
|
||||
appStore.scenicQueue.remark = "西门备注"
|
||||
|
||||
appStore.scenicQueue.punchSpotId = "33"
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotName, "东门")
|
||||
XCTAssertEqual(appStore.scenicQueue.remark, "东门备注")
|
||||
|
||||
appStore.session.currentScenicId = 23
|
||||
XCTAssertEqual(appStore.session.currentStoreId, 0)
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotId, "")
|
||||
XCTAssertTrue(appStore.scenicQueue.useOfflineTTS)
|
||||
appStore.session.currentStoreId = 230
|
||||
appStore.scenicQueue.punchSpotId = "55"
|
||||
appStore.scenicQueue.punchSpotName = "南门"
|
||||
|
||||
appStore.session.currentScenicId = 22
|
||||
XCTAssertEqual(appStore.session.currentStoreId, 220)
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotId, "33")
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotName, "东门")
|
||||
XCTAssertFalse(appStore.scenicQueue.useOfflineTTS)
|
||||
|
||||
XCTAssertEqual(defaults.string(forKey: "scenic_user_1001_scenic_22_scenic_queue_punch_spot_id"), "33")
|
||||
XCTAssertEqual(defaults.string(forKey: "scenic_user_1001_scenic_22_spot_33_scenic_queue_punch_spot_name"), "东门")
|
||||
XCTAssertEqual(defaults.string(forKey: "scenic_user_1001_scenic_22_spot_33_scenic_queue_remark"), "东门备注")
|
||||
XCTAssertFalse(defaults.dictionaryRepresentation().keys.contains { $0.contains("__scenic_queue") })
|
||||
}
|
||||
|
||||
func testLogoutClearsCurrentAccountModulesAndPreservesLoginPreferences() {
|
||||
appStore.session.lastLoginUsername = "13800000000"
|
||||
appStore.session.privacyAgreementAccepted = true
|
||||
|
||||
selectAccount(userId: "other", type: .storeUser)
|
||||
selectAccount(userId: "other", type: .storeUser, scenicId: 22)
|
||||
appStore.scenicQueue.punchSpotId = "99"
|
||||
|
||||
selectAccount(userId: "current", type: .scenicUser)
|
||||
selectAccount(userId: "current", type: .scenicUser, scenicId: 22)
|
||||
appStore.session.token = "token"
|
||||
appStore.permissions.legacyRoleId = 41
|
||||
appStore.permissions.savePermissionItems([HomePermissionItem(id: "1", name: "钱包", uri: "wallet")])
|
||||
appStore.location.onlineStatus = true
|
||||
appStore.payment.isOpenReceiveVoice = true
|
||||
appStore.scenicQueue.punchSpotId = "33"
|
||||
appStore.scenicQueue.punchSpotName = "东门"
|
||||
appStore.session.currentScenicId = 23
|
||||
appStore.scenicQueue.punchSpotId = "44"
|
||||
appStore.scenicQueue.punchSpotName = "西门"
|
||||
|
||||
appStore.logout()
|
||||
|
||||
@ -116,19 +190,22 @@ final class AppStoreModuleTests: XCTestCase {
|
||||
XCTAssertEqual(appStore.session.lastLoginUsername, "13800000000")
|
||||
XCTAssertTrue(appStore.session.privacyAgreementAccepted)
|
||||
|
||||
selectAccount(userId: "current", type: .scenicUser)
|
||||
selectAccount(userId: "current", type: .scenicUser, scenicId: 22)
|
||||
XCTAssertEqual(appStore.permissions.legacyRoleId, 0)
|
||||
XCTAssertTrue(appStore.permissions.permissionItems().isEmpty)
|
||||
XCTAssertFalse(appStore.location.onlineStatus)
|
||||
XCTAssertFalse(appStore.payment.isOpenReceiveVoice)
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotId, "")
|
||||
appStore.session.currentScenicId = 23
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotId, "")
|
||||
|
||||
selectAccount(userId: "other", type: .storeUser)
|
||||
selectAccount(userId: "other", type: .storeUser, scenicId: 22)
|
||||
XCTAssertEqual(appStore.scenicQueue.punchSpotId, "99")
|
||||
}
|
||||
|
||||
private func selectAccount(userId: String, type: AppAccountType) {
|
||||
private func selectAccount(userId: String, type: AppAccountType, scenicId: Int = 22) {
|
||||
appStore.session.userId = userId
|
||||
appStore.session.accountType = type
|
||||
appStore.session.currentScenicId = scenicId
|
||||
}
|
||||
}
|
||||
|
||||
22
suixinkanTests/AppStoreTestSupport.swift
Normal file
22
suixinkanTests/AppStoreTestSupport.swift
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// AppStoreTestSupport.swift
|
||||
// suixinkanTests
|
||||
//
|
||||
|
||||
@testable import suixinkan
|
||||
|
||||
extension AppSessionStore {
|
||||
|
||||
/// 为需要账号作用域缓存的测试建立完整且稳定的账号上下文。
|
||||
func configureTestAccount(
|
||||
userId: String = "test-user",
|
||||
accountType: AppAccountType = .scenicUser,
|
||||
scenicId: Int? = nil
|
||||
) {
|
||||
self.userId = userId
|
||||
self.accountType = accountType
|
||||
if let scenicId {
|
||||
currentScenicId = scenicId
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16,6 +16,7 @@ final class CooperationAcquirerViewModelTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "CooperationAcquirerViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "CooperationAcquirerViewModelTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.configureTestAccount(accountType: .storeUser, scenicId: 10)
|
||||
appStore.session.currentStoreId = 5
|
||||
}
|
||||
|
||||
|
||||
@ -9,9 +9,18 @@ import XCTest
|
||||
@MainActor
|
||||
final class DepositOrderListViewModelTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
AppStore.shared.logout()
|
||||
AppStore.shared.session.configureTestAccount(
|
||||
userId: "deposit-order-user",
|
||||
accountType: .storeUser,
|
||||
scenicId: 10
|
||||
)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
AppStore.shared.session.currentStoreId = 0
|
||||
AppStore.shared.session.currentScenicId = 0
|
||||
AppStore.shared.logout()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
@ -61,4 +70,4 @@ final class DepositOrderListViewModelTests: XCTestCase {
|
||||
let other = try JSONDecoder().decode(StoreOrderItem.self, from: otherJSON)
|
||||
XCTAssertFalse(viewModel.canOpenDetail(for: other))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,14 +38,26 @@ final class HomeCommonMenuStoreTests: XCTestCase {
|
||||
HomePermissionItem(id: "3", name: "任务", uri: "task_management"),
|
||||
]
|
||||
let allMenus = HomeMenuCatalog.visibleMenus(from: permissions)
|
||||
store.saveCommonURIs(["cloud_management"], accountScope: "u1_scenic_user", roleCode: "photographer")
|
||||
store.saveCommonURIs(["cloud_management"], accountScope: "scenic_user_u1", roleCode: "photographer")
|
||||
let common = store.commonMenus(
|
||||
from: allMenus,
|
||||
permissions: permissions,
|
||||
accountScope: "u1_scenic_user",
|
||||
accountScope: "scenic_user_u1",
|
||||
roleCode: "photographer"
|
||||
)
|
||||
XCTAssertEqual(common.map(\.uri), ["cloud_management"])
|
||||
XCTAssertEqual(
|
||||
defaults.stringArray(forKey: "scenic_user_u1_role_photographer_common_uris"),
|
||||
["cloud_management"]
|
||||
)
|
||||
}
|
||||
|
||||
func testIncompleteScopeDoesNotPersistCommonURIs() {
|
||||
store.saveCommonURIs(["wallet"], accountScope: "", roleCode: "photographer")
|
||||
store.saveCommonURIs(["wallet"], accountScope: "scenic_user_u1", roleCode: "")
|
||||
|
||||
XCTAssertNil(defaults.object(forKey: "_role_photographer_common_uris"))
|
||||
XCTAssertNil(defaults.object(forKey: "scenic_user_u1_role__common_uris"))
|
||||
}
|
||||
|
||||
func testSplitMenusSeparatesCommonAndMore() {
|
||||
|
||||
@ -18,6 +18,7 @@ final class LocationProviderTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "LocationProviderTests")!
|
||||
defaults.removePersistentDomain(forName: "LocationProviderTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.configureTestAccount()
|
||||
}
|
||||
|
||||
func testScenicSelectionUsesInjectedProviderSnapshot() async {
|
||||
|
||||
@ -17,8 +17,7 @@ final class LocationReportServiceTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "LocationReportServiceTests")!
|
||||
defaults.removePersistentDomain(forName: "LocationReportServiceTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.userId = "staff-1"
|
||||
appStore.session.currentScenicId = 100
|
||||
appStore.session.configureTestAccount(userId: "staff-1", scenicId: 100)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
|
||||
@ -9,10 +9,14 @@ import XCTest
|
||||
@MainActor
|
||||
final class OrderListViewModelTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
AppStore.shared.logout()
|
||||
AppStore.shared.session.configureTestAccount(userId: "order-list-user", scenicId: 10)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
AppStore.shared.session.roleCode = ""
|
||||
AppStore.shared.session.roleName = ""
|
||||
AppStore.shared.session.currentScenicId = 0
|
||||
AppStore.shared.logout()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
|
||||
@ -16,8 +16,7 @@ final class PaymentCollectionDetailsViewModelTests: XCTestCase {
|
||||
let defaults = UserDefaults(suiteName: "PaymentCollectionDetailsViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "PaymentCollectionDetailsViewModelTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.userId = "10001"
|
||||
appStore.session.currentScenicId = 10
|
||||
appStore.session.configureTestAccount(userId: "10001", scenicId: 10)
|
||||
appStore.session.currentScenicName = "测试景区"
|
||||
}
|
||||
|
||||
|
||||
@ -54,7 +54,7 @@ final class PaymentCollectionRecordViewModelTests: XCTestCase {
|
||||
let defaults = UserDefaults(suiteName: "PaymentCollectionRecordViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "PaymentCollectionRecordViewModelTests")
|
||||
let appStore = AppStore(defaults: defaults)
|
||||
appStore.session.currentScenicId = 10
|
||||
appStore.session.configureTestAccount(scenicId: 10)
|
||||
|
||||
let recordJSON = """
|
||||
{"code":100000,"msg":"success","data":{"analyse":[{"date":"2024-01-15","order_count":1,"order_amount_sum":"50.00"}],"list":[{"order_number":"NO001","user_phone":"13800138000","order_amount":"50.00","create_date":"2024-01-15","create_time":"10:00:00"}]}}
|
||||
|
||||
@ -17,6 +17,7 @@ final class PermissionApplyViewModelTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "PermissionApplyViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "PermissionApplyViewModelTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.configureTestAccount()
|
||||
appStore.permissions.saveRolePermissionList([
|
||||
RolePermissionResponse(
|
||||
role: RoleInfo(id: 10, name: "摄影师", roleCode: "PHOTOGRAPHER", notes: "拍摄"),
|
||||
|
||||
@ -20,14 +20,16 @@ final class ProfileSpaceSettingsViewModelTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "ProfileSpaceSettingsViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "ProfileSpaceSettingsViewModelTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.currentScenicId = 11
|
||||
appStore.session.configureTestAccount(scenicId: 11)
|
||||
AppStore.shared.logout()
|
||||
AppStore.shared.session.configureTestAccount(userId: "profile-space-shared", scenicId: 11)
|
||||
calendar = Calendar(identifier: .gregorian)
|
||||
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
|
||||
fixedNow = calendar.date(from: DateComponents(year: 2026, month: 7, day: 8))!
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
AppStore.shared.session.currentScenicId = 0
|
||||
AppStore.shared.logout()
|
||||
appStore.logout()
|
||||
defaults.removePersistentDomain(forName: "ProfileSpaceSettingsViewModelTests")
|
||||
super.tearDown()
|
||||
|
||||
@ -9,6 +9,18 @@ import XCTest
|
||||
@MainActor
|
||||
/// 个人信息页 ViewModel 测试。
|
||||
final class ProfileViewModelTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
AppStore.shared.logout()
|
||||
AppStore.shared.session.configureTestAccount(userId: "profile-user")
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
AppStore.shared.logout()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testDisplayNicknameUsesFallbackWhenEmpty() {
|
||||
let viewModel = ProfileViewModel()
|
||||
XCTAssertEqual(viewModel.displayNickname, "未设置昵称")
|
||||
|
||||
@ -250,6 +250,7 @@ final class ScenicQueueFeatureTests: XCTestCase {
|
||||
|
||||
store.session.userId = "1"
|
||||
store.session.accountType = .unknown("photog")
|
||||
store.session.currentScenicId = 11
|
||||
store.scenicQueue.punchSpotId = "22"
|
||||
store.scenicQueue.punchSpotName = "东门打卡点"
|
||||
store.scenicQueue.remark = "播报"
|
||||
@ -258,16 +259,19 @@ final class ScenicQueueFeatureTests: XCTestCase {
|
||||
|
||||
store.session.userId = "2"
|
||||
store.session.accountType = .unknown("photog")
|
||||
store.session.currentScenicId = 11
|
||||
XCTAssertEqual(store.scenicQueue.punchSpotId, "")
|
||||
XCTAssertNil(store.scenicQueue.settingsSnapshot())
|
||||
|
||||
store.session.userId = "1"
|
||||
store.session.accountType = .unknown("photog")
|
||||
store.session.currentScenicId = 11
|
||||
XCTAssertEqual(store.scenicQueue.punchSpotId, "22")
|
||||
XCTAssertEqual(store.scenicQueue.presetVoices(), ["a", "b", "c", "d", "e"])
|
||||
store.logout()
|
||||
store.session.userId = "1"
|
||||
store.session.accountType = .unknown("photog")
|
||||
store.session.currentScenicId = 11
|
||||
XCTAssertEqual(store.scenicQueue.punchSpotId, "")
|
||||
XCTAssertNil(store.scenicQueue.settingsSnapshot())
|
||||
}
|
||||
@ -323,6 +327,8 @@ final class ScenicQueueFeatureTests: XCTestCase {
|
||||
let store = AppStore(defaults: defaults)
|
||||
store.session.userId = "u1"
|
||||
store.session.accountType = .unknown("photog")
|
||||
store.session.currentScenicId = 11
|
||||
XCTAssertTrue(store.scenicQueue.useOfflineTTS)
|
||||
let tts = MockScenicQueueTTSManager()
|
||||
let viewModel = ScenicQueueSettingsViewModel(appStore: store, ttsManager: tts)
|
||||
var messages: [String] = []
|
||||
|
||||
@ -16,6 +16,7 @@ final class ScenicSelectionViewModelTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "ScenicSelectionViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "ScenicSelectionViewModelTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.configureTestAccount()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
|
||||
@ -10,11 +10,14 @@ import XCTest
|
||||
/// 数据统计 ViewModel 测试。
|
||||
final class StatisticsViewModelTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
AppStore.shared.logout()
|
||||
AppStore.shared.session.configureTestAccount(userId: "statistics-user", scenicId: 10)
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
AppStore.shared.session.roleCode = ""
|
||||
AppStore.shared.session.roleName = ""
|
||||
AppStore.shared.session.currentScenicId = 0
|
||||
AppStore.shared.session.currentStoreId = 0
|
||||
AppStore.shared.logout()
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ final class TaskAddViewModelTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "TaskAddViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "TaskAddViewModelTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.currentScenicId = 10
|
||||
appStore.session.configureTestAccount(scenicId: 10)
|
||||
}
|
||||
|
||||
func testValidateRequiresTaskName() async {
|
||||
|
||||
@ -17,7 +17,7 @@ final class TaskOrderSelectViewModelTests: XCTestCase {
|
||||
defaults = UserDefaults(suiteName: "TaskOrderSelectViewModelTests")!
|
||||
defaults.removePersistentDomain(forName: "TaskOrderSelectViewModelTests")
|
||||
appStore = AppStore(defaults: defaults)
|
||||
appStore.session.currentScenicId = 10
|
||||
appStore.session.configureTestAccount(scenicId: 10)
|
||||
}
|
||||
|
||||
func testToggleSelectionSelectsAndDeselects() {
|
||||
|
||||
Reference in New Issue
Block a user