Files
suixinkan_ios_new/suixinkanTests/TaskAPITests.swift
汉秋 ffb16eca29 新增任务模块,并接入首页任务管理路由
实现任务列表、详情与创建页面,对接 API,支持云端/本地附件,并添加单元测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-23 15:26:13 +08:00

146 lines
6.0 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// TaskAPITests.swift
// suixinkanTests
//
// Created by Codex on 2026/6/23.
//
import XCTest
@testable import suixinkan
@MainActor
/// API
final class TaskAPITests: XCTestCase {
/// 使 path query
func testTaskListUsesExpectedPathAndQuery() async throws {
let session = TaskRecordingURLSession(data: try TestFixture.data(named: "task_list_success"))
let api = TaskAPI(client: APIClient(session: session))
_ = try await api.taskList(
scenicId: 88,
page: 0,
pageSize: 0,
taskStatus: -2,
taskName: " 精修 ",
startTime: "2026-06-01",
endTime: "2026-06-30"
)
let request = try XCTUnwrap(session.requests.first)
XCTAssertEqual(request.url?.path, "/api/yf-handset-app/photog/task/list")
let query = taskQueryItems(from: request)
XCTAssertEqual(query["scenic_id"], "88")
XCTAssertEqual(query["page"], "1")
XCTAssertEqual(query["page_size"], "1")
XCTAssertEqual(query["task_status"], "0")
XCTAssertEqual(query["task_name"], "精修")
XCTAssertEqual(query["start_time"], "2026-06-01")
XCTAssertEqual(query["end_time"], "2026-06-30")
}
/// 使 path id
func testTaskDetailUsesExpectedPath() async throws {
let session = TaskRecordingURLSession(data: try TestFixture.data(named: "task_detail_success"))
let api = TaskAPI(client: APIClient(session: session))
let detail = try await api.taskDetail(id: 101)
let request = try XCTUnwrap(session.requests.first)
XCTAssertEqual(request.url?.path, "/api/yf-handset-app/photog/task/info")
XCTAssertEqual(taskQueryItems(from: request)["id"], "101")
XCTAssertEqual(detail.urgentHour, 24)
XCTAssertEqual(detail.taskResult.first?.isVideo, true)
}
/// 使
func testAvailableOrderUsesScenicId() async throws {
let session = TaskRecordingURLSession(data: try TestFixture.data(named: "available_order_success"))
let api = TaskAPI(client: APIClient(session: session))
let orders = try await api.availableOrderList(scenicId: 88)
let request = try XCTUnwrap(session.requests.first)
XCTAssertEqual(request.url?.path, "/api/yf-handset-app/photog/task/available-order")
XCTAssertEqual(taskQueryItems(from: request)["scenic_id"], "88")
XCTAssertEqual(orders.first?.orderNumber, "ORD-TASK-001")
}
/// body
func testAddTaskUsesExpectedBody() async throws {
let session = TaskRecordingURLSession(data: try TestFixture.data(named: "empty_success"))
let api = TaskAPI(client: APIClient(session: session))
let request = AddTaskRequest(
scenicId: "88",
name: "任务",
orderNumber: "ORD001",
remark: "备注",
urgentHour: 12,
cloudFile: [CloudFileItem(fileId: 1, remark: "")],
uploadFile: [UploadFileItem(fileUrl: "https://cdn.example.com/a.jpg", fileName: "a.jpg", remark: "")]
)
try await api.addTask(request)
let urlRequest = try XCTUnwrap(session.requests.first)
XCTAssertEqual(urlRequest.url?.path, "/api/yf-handset-app/photog/task/create")
let body = try XCTUnwrap(urlRequest.httpBody)
let object = try XCTUnwrap(JSONSerialization.jsonObject(with: body) as? [String: Any])
XCTAssertEqual(object["scenic_id"] as? String, "88")
XCTAssertEqual(object["name"] as? String, "任务")
XCTAssertEqual(object["order_number"] as? String, "ORD001")
XCTAssertEqual(object["photog_remark"] as? String, "备注")
XCTAssertEqual(object["urgent_hour"] as? Int, 12)
XCTAssertEqual((object["cloud_file"] as? [[String: Any]])?.first?["file_id"] as? Int, 1)
XCTAssertEqual((object["upload_file"] as? [[String: Any]])?.first?["file_url"] as? String, "https://cdn.example.com/a.jpg")
}
/// 使 path query
func testCloudFileListUsesExpectedQuery() async throws {
let session = TaskRecordingURLSession(data: try TestFixture.data(named: "cloud_file_list_success"))
let api = TaskAPI(client: APIClient(session: session))
let payload = try await api.cloudFileList(parentFolderId: 501, name: "photo", type: 2, orderBy: 2, page: 0, pageSize: 0)
let request = try XCTUnwrap(session.requests.first)
XCTAssertEqual(request.url?.path, "/api/yf-handset-app/photog/cloud-driver/list")
let query = taskQueryItems(from: request)
XCTAssertEqual(query["parent_folder_id"], "501")
XCTAssertEqual(query["name"], "photo")
XCTAssertEqual(query["type"], "2")
XCTAssertEqual(query["page"], "1")
XCTAssertEqual(query["page_size"], "1")
XCTAssertEqual(payload.list.first?.isFolder, true)
}
}
/// API URLSession
private final class TaskRecordingURLSession: URLSessionProtocol {
let data: Data
private(set) var requests: [URLRequest] = []
/// Session
init(data: Data) {
self.data = data
}
///
func data(for request: URLRequest) async throws -> (Data, URLResponse) {
requests.append(request)
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!
return (data, response)
}
}
/// query
private func taskQueryItems(from request: URLRequest) -> [String: String] {
guard
let url = request.url,
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
else {
return [:]
}
return Dictionary(uniqueKeysWithValues: (components.queryItems ?? []).compactMap { item in
item.value.map { (item.name, $0) }
})
}