完善任务流程、键盘适配与页面交互

This commit is contained in:
2026-07-10 15:56:15 +08:00
parent f88a85a807
commit ab5220e460
189 changed files with 16779 additions and 1038 deletions

View File

@ -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:))
}
}

View File

@ -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)

View File

@ -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)