Add scenic selection and cooperation order flows aligned with Android.

Upgrade scenic picker with search, location sorting, permission apply/status, and blocking home dialog; add cooperation order module and order source picker improvements with unit tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 10:48:43 +08:00
parent 3c4ca7eefb
commit 2bea05b1d9
50 changed files with 5603 additions and 191 deletions

View File

@ -0,0 +1,86 @@
//
// BindAcquirerViewModelTests.swift
// suixinkanTests
//
import XCTest
@testable import suixinkan
@MainActor
final class BindAcquirerViewModelTests: XCTestCase {
func testAcceptBindValidationRequiresRate() async {
let viewModel = BindAcquirerViewModel()
viewModel.initSaleUserId(1)
var message: String?
viewModel.onShowMessage = { message = $0 }
await viewModel.acceptBind(api: makeAPI(responses: []))
XCTAssertEqual(message, "请输入分账比例")
}
func testAcceptBindValidationRejectsOutOfRange() async {
let viewModel = BindAcquirerViewModel()
viewModel.initSaleUserId(1)
viewModel.updateCommissionRateDraft("120")
var message: String?
viewModel.onShowMessage = { message = $0 }
await viewModel.acceptBind(api: makeAPI(responses: []))
XCTAssertEqual(message, "分账比例需在0到100之间")
}
func testLoadInviteInfoMarksAlreadyBound() async throws {
let json = """
{"code":100000,"msg":"success","data":{"sale_user_id":7,"is_bound":true,"saler_name":"","saler_phone":"13800138000","title":""}}
""".data(using: .utf8)!
let api = makeAPI(responses: [json])
let viewModel = BindAcquirerViewModel()
viewModel.initSaleUserId(7)
await viewModel.loadInviteInfo(api: api)
XCTAssertTrue(viewModel.isAlreadyBound)
XCTAssertEqual(viewModel.inviteInfo?.salerName, "张三")
}
func testAcceptBindSuccessCallsCallback() async throws {
let inviteJSON = """
{"code":100000,"msg":"success","data":{"sale_user_id":2,"saler_name":""}}
""".data(using: .utf8)!
let bindJSON = """
{"code":100000,"msg":"success","data":{}}
""".data(using: .utf8)!
let api = makeAPI(responses: [inviteJSON, bindJSON])
let viewModel = BindAcquirerViewModel()
viewModel.initSaleUserId(2)
viewModel.updateCommissionRateDraft("30")
var didBind = false
viewModel.onBindSuccess = { didBind = true }
await viewModel.loadInviteInfo(api: api)
await viewModel.acceptBind(api: api)
XCTAssertTrue(didBind)
}
func testLoadInviteInfoAlreadyBoundMessage() async throws {
let json = try TestJSON.errorEnvelope(code: 100001, msg: "已绑定获客员")
let api = makeAPI(responses: [json])
let viewModel = BindAcquirerViewModel()
viewModel.initSaleUserId(9)
var shouldPop = false
viewModel.onShouldPop = { shouldPop = true }
await viewModel.loadInviteInfo(api: api)
XCTAssertTrue(viewModel.isAlreadyBound)
XCTAssertFalse(shouldPop)
}
private func makeAPI(responses: [Data]) -> OrderAPI {
OrderAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: responses)))
}
}