完善任务流程、键盘适配与页面交互
This commit is contained in:
@ -3,6 +3,7 @@
|
||||
// suixinkanTests
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import XCTest
|
||||
@testable import suixinkan
|
||||
|
||||
@ -144,3 +145,36 @@ final class AllFunctionsViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(viewModel.commonMenus.map(\.uri), ["location_report", "report_photographer"])
|
||||
}
|
||||
}
|
||||
|
||||
/// 全部功能菜单卡片交互语义测试。
|
||||
@MainActor
|
||||
final class AllFunctionMenuCellTests: XCTestCase {
|
||||
|
||||
func testAddStyleUsesWholeCellAsAccessibleActionWithoutNestedButton() {
|
||||
let cell = AllFunctionMenuCell(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
|
||||
let menu = HomeMenuItem(uri: "wallet", title: "钱包", iconName: "wallet.pass")
|
||||
|
||||
cell.apply(menu: menu, actionStyle: .add)
|
||||
|
||||
XCTAssertTrue(cell.isAccessibilityElement)
|
||||
XCTAssertEqual(cell.accessibilityLabel, "钱包")
|
||||
XCTAssertEqual(cell.accessibilityHint, "添加到常用应用")
|
||||
XCTAssertTrue(cell.accessibilityTraits.contains(.button))
|
||||
XCTAssertFalse(containsButton(in: cell.contentView))
|
||||
}
|
||||
|
||||
func testRemoveStyleDescribesWholeCellRemoveAction() {
|
||||
let cell = AllFunctionMenuCell(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
|
||||
let menu = HomeMenuItem(uri: "wallet", title: "钱包", iconName: "wallet.pass")
|
||||
|
||||
cell.apply(menu: menu, actionStyle: .remove)
|
||||
|
||||
XCTAssertEqual(cell.accessibilityHint, "移出常用应用")
|
||||
XCTAssertTrue(cell.accessibilityTraits.contains(.button))
|
||||
XCTAssertFalse(containsButton(in: cell.contentView))
|
||||
}
|
||||
|
||||
private func containsButton(in view: UIView) -> Bool {
|
||||
view is UIButton || view.subviews.contains(where: containsButton(in:))
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,6 +56,17 @@ final class TaskAddViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(message, "文件正在上传中,请稍后添加!")
|
||||
}
|
||||
|
||||
func testClearingCustomUrgentHourKeepsConfirmedValue() {
|
||||
let viewModel = TaskAddViewModel(appStore: appStore)
|
||||
viewModel.setUrgentHour(6)
|
||||
|
||||
viewModel.updateCustomUrgentHourText("")
|
||||
XCTAssertEqual(viewModel.urgentHour, 6)
|
||||
|
||||
viewModel.updateCustomUrgentHourText("0")
|
||||
XCTAssertEqual(viewModel.urgentHour, 6)
|
||||
}
|
||||
|
||||
func testBuildAddTaskRequestSplitsCloudAndUploadFiles() {
|
||||
let viewModel = TaskAddViewModel(appStore: appStore)
|
||||
viewModel.updateTaskName("任务A")
|
||||
@ -76,6 +87,26 @@ final class TaskAddViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(request.uploadFile[0].fileUrl, "https://cdn/a.jpg")
|
||||
}
|
||||
|
||||
func testPreparedUploadKeepsOriginalFileNameAndPreview() {
|
||||
let viewModel = TaskAddViewModel(appStore: appStore)
|
||||
let previewData = Data([1, 2, 3])
|
||||
viewModel.addUploadPlaceholder(fileName: "temporary.jpg", fileType: 2, uploadTaskId: "task1")
|
||||
|
||||
viewModel.prepareUpload(uploadTaskId: "task1", fileName: "IMG_1001.HEIC", localPreviewData: previewData)
|
||||
viewModel.markUploadSucceeded(
|
||||
uploadTaskId: "task1",
|
||||
fileURL: "https://cdn/image.heic",
|
||||
fileName: "IMG_1001.HEIC",
|
||||
localPreviewData: previewData,
|
||||
autoRemarkWhenSingle: true
|
||||
)
|
||||
|
||||
XCTAssertEqual(viewModel.selectedFiles[0].uploadFileName, "IMG_1001.HEIC")
|
||||
XCTAssertEqual(viewModel.selectedFiles[0].localPreviewData, previewData)
|
||||
XCTAssertEqual(viewModel.buildAddTaskRequest().uploadFile[0].fileName, "IMG_1001.HEIC")
|
||||
XCTAssertEqual(viewModel.consumePendingRemarkFileID(), viewModel.selectedFiles[0].id)
|
||||
}
|
||||
|
||||
func testTaskFileSourceBadgeTextMatchesAndroidLabels() {
|
||||
let cloudItem = TaskFileItem(source: .cloud, cloudFile: CloudFile(id: 1, name: "云文件", type: 2))
|
||||
let uploadItem = TaskFileItem(source: .upload, uploadFileName: "a.jpg", uploadFileType: 2)
|
||||
|
||||
@ -1269,6 +1269,53 @@ final class WildPhotographerReportTests: XCTestCase {
|
||||
XCTAssertEqual(viewModel.errorMessage, URLError(.badServerResponse).localizedDescription)
|
||||
}
|
||||
|
||||
func testRiskMapViewModelSharesSelectedReportMarker() async {
|
||||
let viewModel = WildReportRiskMapViewModel()
|
||||
let api = MockWildPhotographerReportAPI()
|
||||
api.riskMapResponses = [makeRiskMapResponse()]
|
||||
api.reportShareResponse = WildReportMiniProgramShareData(
|
||||
userName: "gh_test",
|
||||
path: "/pages/report/detail?id=32",
|
||||
title: "举报线索",
|
||||
description: "请协助处理",
|
||||
webpageURL: "https://example.com/report/32",
|
||||
miniProgramTypeValue: WeChatMiniProgramType.preview.rawValue
|
||||
)
|
||||
|
||||
await viewModel.loadInitial(
|
||||
api: api,
|
||||
locationProvider: MockRiskMapLocationProvider(.success(latitude: 43.3779, longitude: 84.0217)),
|
||||
scenicId: 128
|
||||
)
|
||||
let redMarker = try! XCTUnwrap(viewModel.markers.first { $0.kind == .wildPhotographer })
|
||||
await viewModel.selectMarker(redMarker)
|
||||
|
||||
let payload = await viewModel.shareSelectedClue(api: api)
|
||||
|
||||
XCTAssertEqual(api.reportShareRequests, ["32"])
|
||||
XCTAssertEqual(payload?.title, "举报线索")
|
||||
XCTAssertEqual(payload?.path, "/pages/report/detail?id=32")
|
||||
XCTAssertEqual(payload?.miniProgramType, .preview)
|
||||
}
|
||||
|
||||
func testRiskMapViewModelDoesNotShareCurrentLocationMarker() async {
|
||||
let viewModel = WildReportRiskMapViewModel()
|
||||
let api = MockWildPhotographerReportAPI()
|
||||
api.riskMapResponses = [makeRiskMapResponse()]
|
||||
|
||||
await viewModel.loadInitial(
|
||||
api: api,
|
||||
locationProvider: MockRiskMapLocationProvider(.success(latitude: 43.3779, longitude: 84.0217)),
|
||||
scenicId: 128
|
||||
)
|
||||
|
||||
let payload = await viewModel.shareSelectedClue(api: api)
|
||||
|
||||
XCTAssertNil(payload)
|
||||
XCTAssertTrue(api.reportShareRequests.isEmpty)
|
||||
XCTAssertEqual(viewModel.errorMessage, "请选择可分享的举报线索")
|
||||
}
|
||||
|
||||
func testDetailViewModelLoadsRemoteDetailWhenServerIDExists() async {
|
||||
let record = makeReportListItem(complaintNo: "JB20260708917", handleStatus: 0).toRecord()
|
||||
let viewModel = WildPhotographerReportDetailViewModel(record: record)
|
||||
|
||||
Reference in New Issue
Block a user