Files
suixinkan_ios_new/suixinkanTests/ScenicPromotion/ScenicPromotionTests.swift
汉秋 1b1e93b9ca 新增宣传页 Mock 模块并接入首页路由。
从 xh_test 同步 ScenicPromotion 演示页,补齐 MVVM 结构、本地资源、单元测试与模块文档,注册 promotion_page 首页入口。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 15:29:25 +08:00

184 lines
6.2 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.

//
// ScenicPromotionTests.swift
// suixinkanTests
//
// Created by Codex on 2026/7/2.
//
import XCTest
@testable import suixinkan
/// ViewModel
@MainActor
final class ScenicPromotionViewModelTests: XCTestCase {
/// normal
func testApplyNormalScenarioLoadsBoardAndSelection() {
let viewModel = ScenicPromotionViewModel()
viewModel.applyScenario(.normal)
XCTAssertEqual(viewModel.pageState, .normal)
XCTAssertNotNil(viewModel.board)
XCTAssertEqual(viewModel.board?.scenicName, "那拉提景区")
XCTAssertNotNil(viewModel.selectedSpot)
XCTAssertNotNil(viewModel.selectedMedia)
XCTAssertFalse(viewModel.mediaItems.isEmpty)
}
/// empty
func testApplyEmptyScenarioClearsBoard() {
let viewModel = ScenicPromotionViewModel()
viewModel.applyScenario(.normal)
viewModel.applyScenario(.empty)
XCTAssertEqual(viewModel.pageState, .empty)
XCTAssertNil(viewModel.board)
}
/// error
func testApplyErrorScenarioSetsErrorState() {
let viewModel = ScenicPromotionViewModel()
viewModel.applyScenario(.error)
if case .error = viewModel.pageState {
XCTAssertTrue(true)
} else {
XCTFail("Expected error page state")
}
}
///
func testNoMediaScenarioHidesMediaItems() {
let viewModel = ScenicPromotionViewModel()
viewModel.applyScenario(.normal)
viewModel.applyScenario(.noMedia)
XCTAssertTrue(viewModel.mediaItems.isEmpty)
XCTAssertNil(viewModel.selectedMedia)
}
///
func testNoQueueScenarioHidesQueueInfo() {
let viewModel = ScenicPromotionViewModel()
viewModel.applyScenario(.normal)
viewModel.applyScenario(.noQueue)
XCTAssertNil(viewModel.queue)
XCTAssertFalse(viewModel.hasQueueData)
}
///
func testSelectSpotAndModeUpdatesSelectedMedia() {
let viewModel = ScenicPromotionViewModel()
viewModel.applyScenario(.normal)
guard let board = viewModel.board, board.spots.count > 1 else {
XCTFail("Expected multiple spots in mock board")
return
}
let secondSpot = board.spots[1]
viewModel.selectSpot(secondSpot)
XCTAssertEqual(viewModel.selectedSpot?.id, secondSpot.id)
viewModel.selectMode(.photo)
XCTAssertEqual(viewModel.selectedMode, .photo)
XCTAssertEqual(viewModel.selectedMedia?.mode, .photo)
}
///
func testMoveMediaCyclesSelection() {
let viewModel = ScenicPromotionViewModel()
viewModel.applyScenario(.normal)
guard viewModel.mediaItems.count > 1 else {
XCTFail("Expected multiple media items")
return
}
let firstID = viewModel.selectedMedia?.id
viewModel.moveMedia(1)
XCTAssertNotEqual(viewModel.selectedMedia?.id, firstID)
viewModel.moveMedia(-1)
XCTAssertEqual(viewModel.selectedMedia?.id, firstID)
}
}
/// ViewModel
@MainActor
final class ScenicPromotionSettingsViewModelTests: XCTestCase {
/// Mock
func testApplyNormalScenarioLoadsSettingsData() {
let viewModel = ScenicPromotionSettingsViewModel()
viewModel.applyScenario(.normal)
XCTAssertEqual(viewModel.pageState, .normal)
XCTAssertFalse(viewModel.queuePoints.isEmpty)
XCTAssertFalse(viewModel.materialPoints.isEmpty)
XCTAssertFalse(viewModel.selectedQueuePointIDs.isEmpty)
}
///
func testAddMaterialFailsWithoutMaterialPoint() {
let viewModel = ScenicPromotionSettingsViewModel()
viewModel.applyScenario(.normal)
viewModel.selectedMaterialPointID = nil
XCTAssertFalse(viewModel.addMaterial(kind: .video))
}
/// Mock
func testAddMaterialSucceedsWithMaterialPoint() {
let viewModel = ScenicPromotionSettingsViewModel()
viewModel.applyScenario(.normal)
guard let point = viewModel.materialPoints.first else {
XCTFail("Expected material points")
return
}
viewModel.selectMaterialPoint(point)
let beforeCount = viewModel.materials(for: .video).count
XCTAssertTrue(viewModel.addMaterial(kind: .video))
XCTAssertEqual(viewModel.materials(for: .video).count, beforeCount + 1)
}
///
func testDeleteMaterialRemovesItem() {
let viewModel = ScenicPromotionSettingsViewModel()
viewModel.applyScenario(.normal)
guard let point = viewModel.materialPoints.first else {
XCTFail("Expected material points")
return
}
viewModel.selectMaterialPoint(point)
guard viewModel.addMaterial(kind: .image),
let material = viewModel.materials(for: .image).last else {
XCTFail("Expected uploaded material")
return
}
viewModel.deleteMaterial(material)
XCTAssertFalse(viewModel.materials(for: .image).contains(where: { $0.id == material.id }))
}
///
func testSubmitFailsWithoutQueuePoints() {
let viewModel = ScenicPromotionSettingsViewModel()
viewModel.applyScenario(.normal)
viewModel.selectedQueuePointIDs = []
XCTAssertFalse(viewModel.submit())
}
///
func testSubmitSucceedsWithQueuePoints() {
let viewModel = ScenicPromotionSettingsViewModel()
viewModel.applyScenario(.normal)
XCTAssertTrue(viewModel.submit())
}
}