切换账号时以用户选中账号为准写入展示标题与业务作用域,避免沿用旧门店名称;同时将首页举报摄影师入口 URI 对齐为 report_photographer。 Co-authored-by: Cursor <cursoragent@cursor.com>
159 lines
6.0 KiB
Swift
159 lines
6.0 KiB
Swift
//
|
||
// AuthModelsTests.swift
|
||
// suixinkanTests
|
||
//
|
||
// Created by Codex on 2026/6/26.
|
||
//
|
||
|
||
import XCTest
|
||
@testable import suixinkan
|
||
|
||
/// Auth 模块模型测试,覆盖 v9 登录响应解码和账号转换规则。
|
||
final class AuthModelsTests: XCTestCase {
|
||
/// 测试多账号登录 fixture 能正确解码并合并景区、门店账号。
|
||
func testV9AuthResponseDecodesMultiAccountFixture() throws {
|
||
let response = try TestFixture.payload(V9AuthResponse.self, named: "v9_login_multi_success")
|
||
|
||
XCTAssertEqual(response.token, "person-temp-token")
|
||
XCTAssertEqual(response.scenicUsers.count, 1)
|
||
XCTAssertEqual(response.storeUsers.count, 1)
|
||
XCTAssertEqual(response.accounts.map(\.businessUserId), [101, 201])
|
||
}
|
||
|
||
/// 测试景区账号会优先使用 ss_user_id 作为业务账号 ID。
|
||
func testV9ScenicUserBusinessUserIdPrefersSsUserId() throws {
|
||
let json = """
|
||
{
|
||
"account_type": "scenic_user",
|
||
"id": 1,
|
||
"user_id": 2,
|
||
"scenic_user_id": 3,
|
||
"ss_user_id": 101,
|
||
"username": "scenic_admin",
|
||
"real_name": "张三",
|
||
"nickname": "张三",
|
||
"phone": "13800138000",
|
||
"scenic_id": 10,
|
||
"scenic_name": "示例景区",
|
||
"is_current": false
|
||
}
|
||
""".data(using: .utf8)!
|
||
let user = try JSONDecoder().decode(V9ScenicUser.self, from: json)
|
||
|
||
XCTAssertEqual(user.businessUserId, 101)
|
||
XCTAssertEqual(user.toAccountSwitchAccount().accountType, V9ScenicUser.accountTypeValue)
|
||
XCTAssertEqual(user.toAccountSwitchAccount().toSetUserRequest(), SetUserRequest(ssUserId: 101))
|
||
}
|
||
|
||
/// 测试门店账号会优先使用 store_user_id 作为业务账号 ID。
|
||
func testV9StoreUserBusinessUserIdPrefersStoreUserId() throws {
|
||
let json = """
|
||
{
|
||
"account_type": "store_user",
|
||
"id": 1,
|
||
"user_id": 2,
|
||
"store_user_id": 201,
|
||
"username": "store_admin",
|
||
"user_name": "store_admin",
|
||
"real_name": "张三",
|
||
"phone": "13800138000",
|
||
"avatar": "",
|
||
"scenic_id": 10,
|
||
"scenic_name": "示例景区",
|
||
"store_id": 20,
|
||
"store_name": "示例门店",
|
||
"is_current": false
|
||
}
|
||
""".data(using: .utf8)!
|
||
let user = try JSONDecoder().decode(V9StoreUser.self, from: json)
|
||
|
||
XCTAssertEqual(user.businessUserId, 201)
|
||
XCTAssertEqual(user.toAccountSwitchAccount().accountType, V9StoreUser.accountTypeValue)
|
||
XCTAssertEqual(user.toAccountSwitchAccount().toSetUserRequest(), SetUserRequest(storeUserId: 201))
|
||
}
|
||
|
||
/// 测试登录响应会派生景区和门店作用域,并去重。
|
||
func testV9AuthResponseDerivesScopesFromAccounts() throws {
|
||
let response = try TestFixture.payload(V9AuthResponse.self, named: "v9_login_multi_success")
|
||
|
||
XCTAssertEqual(response.scenicScopes.map(\.id), [10])
|
||
XCTAssertEqual(response.storeScopes.map(\.id), [20])
|
||
XCTAssertEqual(response.primaryProfile?.displayName, "示例门店")
|
||
}
|
||
|
||
/// 测试切换门店账号时会优先使用 isCurrent 标记校准景区和门店作用域。
|
||
func testV9AuthResponsePreferredScopeSelectionUsesCurrentStoreAccount() throws {
|
||
let scenicJSON = """
|
||
{
|
||
"account_type": "scenic_user",
|
||
"id": 101,
|
||
"user_id": 101,
|
||
"scenic_user_id": 101,
|
||
"ss_user_id": 101,
|
||
"username": "scenic_admin",
|
||
"real_name": "张三",
|
||
"nickname": "张三",
|
||
"phone": "13800138000",
|
||
"scenic_id": 1,
|
||
"scenic_name": "旧景区",
|
||
"is_current": false
|
||
}
|
||
"""
|
||
let storeJSON = """
|
||
{
|
||
"account_type": "store_user",
|
||
"id": 201,
|
||
"user_id": 201,
|
||
"store_user_id": 201,
|
||
"username": "store_admin",
|
||
"user_name": "store_admin",
|
||
"real_name": "李四",
|
||
"phone": "13800138000",
|
||
"avatar": "",
|
||
"scenic_id": 2,
|
||
"scenic_name": "新景区",
|
||
"store_id": 20,
|
||
"store_name": "新门店",
|
||
"is_current": true
|
||
}
|
||
"""
|
||
let scenicUser = try JSONDecoder().decode(V9ScenicUser.self, from: Data(scenicJSON.utf8))
|
||
let storeUser = try JSONDecoder().decode(V9StoreUser.self, from: Data(storeJSON.utf8))
|
||
let response = V9AuthResponse(token: "token", scenicUsers: [scenicUser], storeUsers: [storeUser])
|
||
|
||
XCTAssertEqual(response.currentAccountIdentity?.accountType, V9StoreUser.accountTypeValue)
|
||
XCTAssertEqual(response.currentAccountIdentity?.businessUserId, 201)
|
||
XCTAssertEqual(response.preferredScopeSelection.scenicId, 2)
|
||
XCTAssertEqual(response.preferredScopeSelection.storeId, 20)
|
||
|
||
let context = AccountContext()
|
||
context.replaceScopes(
|
||
scenic: [BusinessScope(id: 1, name: "旧景区", kind: .scenic)],
|
||
stores: [],
|
||
currentScenicId: 1,
|
||
currentStoreId: nil
|
||
)
|
||
context.replaceScopes(
|
||
scenic: response.scenicScopes,
|
||
stores: response.storeScopes,
|
||
currentScenicId: response.preferredScopeSelection.scenicId,
|
||
currentStoreId: response.preferredScopeSelection.storeId
|
||
)
|
||
|
||
XCTAssertEqual(context.currentScenic?.id, 2)
|
||
XCTAssertEqual(context.currentStore?.id, 20)
|
||
}
|
||
|
||
/// 测试 LoginRequest 会填充后端要求的默认字段。
|
||
func testLoginRequestEncodesExpectedDefaults() throws {
|
||
let request = LoginRequest(username: "18651857230", password: "secret123")
|
||
let json = try JSONSerialization.jsonObject(with: JSONEncoder().encode(request)) as? [String: Any]
|
||
|
||
XCTAssertEqual(json?["username"] as? String, "18651857230")
|
||
XCTAssertEqual(json?["password"] as? String, "secret123")
|
||
XCTAssertEqual(json?["type"] as? Int, 1)
|
||
XCTAssertEqual(json?["mobile"] as? String, "")
|
||
XCTAssertEqual(json?["code"] as? String, "")
|
||
}
|
||
}
|