// // ScenicApplicationViewModelTests.swift // suixinkanTests // import XCTest @testable import suixinkan @MainActor /// 景区申请 ViewModel 测试。 final class ScenicApplicationViewModelTests: XCTestCase { func testCanSubmitRequiresRequiredFields() { let viewModel = ScenicApplicationViewModel() XCTAssertFalse(viewModel.canSubmit) viewModel.onProvinceSelected("浙江省") viewModel.onCitySelected("杭州市") viewModel.onRemarksChange("合作备注") XCTAssertFalse(viewModel.canSubmit) viewModel.toggleAgreement() XCTAssertTrue(viewModel.canSubmit) } func testRemarksMaxLengthShowsMessage() { let viewModel = ScenicApplicationViewModel() var message: String? viewModel.onShowMessage = { message = $0 } let longText = String(repeating: "a", count: 51) viewModel.onRemarksChange(longText) XCTAssertEqual(viewModel.remarks.count, 0) XCTAssertEqual(message, "备注信息最多50字") } func testProvinceSelectionClearsCity() { let viewModel = ScenicApplicationViewModel() viewModel.onProvinceSelected("浙江省") viewModel.onCitySelected("杭州市") XCTAssertEqual(viewModel.selectedCity, "杭州市") viewModel.onProvinceSelected("江苏省") XCTAssertEqual(viewModel.selectedProvince, "江苏省") XCTAssertEqual(viewModel.selectedCity, "") } func testInitWithPendingApplicationStatus1() async throws { let pendingJSON = """ {"code":100000,"msg":"success","data":{"items":[{"id":1,"scenic_name":"测试景区","scenic_images":"https://a.com/1.jpg,https://a.com/2.jpg","scenic_province":"浙江省","scenic_city":"杭州市","coop_type":2,"remark":"备注","status":1}]}} """.data(using: .utf8)! let areasJSON = """ {"code":100000,"msg":"success","data":[{"id":1,"name":"浙江省","children":[{"id":2,"name":"杭州市"}]}]} """.data(using: .utf8)! let homeAPI = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [pendingJSON]))) let profileAPI = ProfileAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [areasJSON]))) let viewModel = ScenicApplicationViewModel() await viewModel.loadAreas(profileAPI: profileAPI) await viewModel.loadPendingApplication(homeAPI: homeAPI) XCTAssertEqual(viewModel.scenicName, "测试景区") XCTAssertEqual(viewModel.selectedProvince, "浙江省") XCTAssertEqual(viewModel.selectedCity, "杭州市") XCTAssertEqual(viewModel.selectedCooperationType, .resourceProvider) XCTAssertEqual(viewModel.remarks, "备注") XCTAssertEqual(viewModel.selectedImages.count, 2) XCTAssertTrue(viewModel.isReadOnly) XCTAssertTrue(viewModel.shouldShowAuditCard) } func testSubmitValidationShowsIncompleteMessage() async { let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: []))) let viewModel = ScenicApplicationViewModel() var message: String? viewModel.onShowMessage = { message = $0 } await viewModel.submit(homeAPI: api) XCTAssertEqual(message, "请完善必填信息") } func testSubmitSuccessCallsCallback() async throws { let submitJSON = """ {"code":100000,"msg":"success","data":{}} """.data(using: .utf8)! let pendingJSON = """ {"code":100000,"msg":"success","data":{"items":[]}} """.data(using: .utf8)! let api = HomeAPI(client: APIClient(environment: .testing, session: MockURLSession(responses: [submitJSON, pendingJSON]))) let viewModel = ScenicApplicationViewModel() viewModel.onProvinceSelected("浙江省") viewModel.onCitySelected("杭州市") viewModel.onRemarksChange("合作") viewModel.toggleAgreement() var didSubmit = false viewModel.onSubmitSuccess = { didSubmit = true } var messages: [String] = [] viewModel.onShowMessage = { messages.append($0) } await viewModel.submit(homeAPI: api) XCTAssertTrue(didSubmit) XCTAssertEqual(messages.first, "提交成功") } }