新增景区权限模块,集成 AMap CocoaPods 并支持模拟器

将景区选择与权限申请流程接入首页路由,集成高德 SDK 用于真机构建,并通过 Podfile post_install 钩子保证 arm64 模拟器可编译。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-23 10:15:26 +08:00
parent 5d4613f317
commit b61bf0d070
416 changed files with 18641 additions and 38 deletions

View File

@ -0,0 +1,119 @@
//
// ScenicSelectionViewModelTests.swift
// suixinkanTests
//
// Created by Codex on 2026/6/23.
//
import XCTest
@testable import suixinkan
@MainActor
/// ViewModel
final class ScenicSelectionViewModelTests: XCTestCase {
///
func testCurrentScenicMovesToFirstItem() {
let context = AccountContext()
context.replaceScopes(
scenic: [
BusinessScope(id: 1, name: "西湖景区", kind: .scenic),
BusinessScope(id: 2, name: "东湖景区", kind: .scenic)
],
stores: [],
currentScenicId: 2
)
let viewModel = ScenicSelectionViewModel()
viewModel.reload(from: context)
XCTAssertEqual(viewModel.items.map(\.id), [2, 1])
XCTAssertTrue(viewModel.items[0].isClosest)
}
///
func testSearchFiltersByNameAndAddress() {
let viewModel = ScenicSelectionViewModel()
let context = AccountContext()
context.replaceScopes(
scenic: [
BusinessScope(id: 1, name: "西湖景区", kind: .scenic, address: "杭州"),
BusinessScope(id: 2, name: "东湖景区", kind: .scenic, address: "武汉")
],
stores: []
)
viewModel.reload(from: context)
viewModel.searchQuery = "武汉"
XCTAssertEqual(viewModel.filteredItems.map(\.id), [2])
}
///
func testLocationSuccessMarksClosestScenic() {
let context = AccountContext()
context.replaceScopes(
scenic: [
BusinessScope(id: 1, name: "远景区", kind: .scenic, address: "远处", latitude: 31.0, longitude: 121.0),
BusinessScope(id: 2, name: "近景区", kind: .scenic, address: "附近", latitude: 30.0001, longitude: 120.0001)
],
stores: []
)
let viewModel = ScenicSelectionViewModel()
viewModel.reload(from: context)
viewModel.applyCurrentLocation(latitude: 30.0, longitude: 120.0)
XCTAssertEqual(viewModel.items.first(where: \.isClosest)?.id, 2)
XCTAssertEqual(viewModel.currentLocationText, "附近")
XCTAssertNotNil(viewModel.items.first(where: { $0.id == 2 })?.distanceMeters)
}
///
func testLocationFailureKeepsItemsAndWarning() {
let context = AccountContext()
context.replaceScopes(scenic: [BusinessScope(id: 1, name: "西湖景区", kind: .scenic, address: "杭州")], stores: [])
let viewModel = ScenicSelectionViewModel()
viewModel.reload(from: context)
viewModel.applyLocationFailure("定位权限未开启")
XCTAssertEqual(viewModel.items.map(\.id), [1])
XCTAssertEqual(viewModel.locationWarning, "定位权限未开启")
}
///
func testSelectScenicUpdatesStoreAndPersistsSnapshot() {
let suiteName = "ScenicSelectionViewModelTests.\(UUID().uuidString)"
let defaults = UserDefaults(suiteName: suiteName)!
defer { defaults.removePersistentDomain(forName: suiteName) }
let snapshotStore = AccountSnapshotStore(defaults: defaults)
let accountContext = AccountContext()
let permissionContext = PermissionContext()
accountContext.replaceScopes(
scenic: [
BusinessScope(id: 1, name: "西湖景区", kind: .scenic),
BusinessScope(id: 2, name: "东湖景区", kind: .scenic)
],
stores: [
BusinessScope(id: 10, name: "西湖门店", kind: .store, parentScenicId: 1),
BusinessScope(id: 20, name: "东湖门店", kind: .store, parentScenicId: 2)
],
currentScenicId: 1,
currentStoreId: 10
)
permissionContext.replaceRolePermissions([RolePermissionResponse(role: RoleInfo(id: 7, name: "运营"), scenic: [])])
ScenicSelectionViewModel().select(
scenicId: 2,
accountContext: accountContext,
permissionContext: permissionContext,
snapshotStore: snapshotStore
)
XCTAssertEqual(accountContext.currentScenic?.id, 2)
XCTAssertEqual(accountContext.currentStore?.id, 20)
XCTAssertEqual(snapshotStore.load()?.currentScenicId, 2)
XCTAssertEqual(snapshotStore.load()?.currentStoreId, 20)
XCTAssertEqual(snapshotStore.load()?.currentRoleId, 7)
}
}