Implement profile tab with Android-aligned flows and OSS upload.

Add personal info page, account switch, real-name auth, withdrawal settings, session cache extensions, AlibabaCloudOSS SPM, and unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-06 16:01:05 +08:00
parent 02a80764ea
commit 005cac3f78
36 changed files with 4077 additions and 57 deletions

View File

@ -0,0 +1,77 @@
//
// AccountSwitchViewModelTests.swift
// suixinkanTests
//
import XCTest
@testable import suixinkan
@MainActor
/// ViewModel
final class AccountSwitchViewModelTests: XCTestCase {
func testLoadFiltersInvalidAccounts() async throws {
let json = """
{
"code": 100000,
"msg": "success",
"data": {
"token": "token",
"scenic_users": [
{
"account_type": "scenic_user",
"id": 1,
"user_id": 1,
"scenic_user_id": 1,
"ss_user_id": 9001,
"username": "u1",
"real_name": "",
"nickname": "",
"phone": "13800138000",
"scenic_id": 10,
"scenic_name": "A",
"is_current": true
}
],
"store_users": []
}
}
""".data(using: .utf8)!
let session = MockURLSession(responses: [json])
let api = ProfileAPI(client: APIClient(environment: .testing, session: session))
let viewModel = AccountSwitchViewModel()
try await viewModel.load(api: api, force: true)
XCTAssertEqual(viewModel.accounts.count, 1)
XCTAssertEqual(viewModel.selectedAccount?.businessUserId, 9001)
}
func testSwitchAccountThrowsWhenBusinessUserIdInvalid() async {
let viewModel = AccountSwitchViewModel()
let account = AccountSwitchAccount(
accountType: V9ScenicUser.accountTypeValue,
businessUserId: 0,
title: "景区A",
subtitle: "张三",
phone: "13800138000",
avatar: "",
scenicName: "景区A",
storeId: nil,
storeName: "",
scenicId: 10,
isCurrent: false
)
let authAPI = AuthAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [])))
do {
_ = try await viewModel.switchAccount(account, api: authAPI)
XCTFail("无效账号应失败")
} catch {
guard let switchError = error as? AccountSwitchError else {
return XCTFail("期望 AccountSwitchError实际为 \(error)")
}
XCTAssertEqual(switchError, .invalidAccount)
}
}
}