// // TripWizardViewModelTests.swift // SportsTimeTests // import XCTest @testable import SportsTime final class TripWizardViewModelTests: XCTestCase { func test_initialState_onlyPlanningModeStepVisible() { let viewModel = TripWizardViewModel() XCTAssertTrue(viewModel.isPlanningModeStepVisible) XCTAssertFalse(viewModel.isSportsStepVisible) XCTAssertFalse(viewModel.isDatesStepVisible) XCTAssertFalse(viewModel.isRegionsStepVisible) } func test_selectingPlanningMode_revealsSportsStep() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange XCTAssertTrue(viewModel.isSportsStepVisible) } func test_selectingSport_revealsDatesStep() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb] XCTAssertTrue(viewModel.isDatesStepVisible) } func test_changingPlanningMode_resetsDownstreamSelections() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb, .nba] viewModel.hasSetDates = true viewModel.planningMode = .gameFirst XCTAssertTrue(viewModel.selectedSports.isEmpty) XCTAssertFalse(viewModel.hasSetDates) } // MARK: - Full Flow Integration Tests func test_fullWizardFlow_reachesReviewStep() { let viewModel = TripWizardViewModel() // Step 1: Select planning mode viewModel.planningMode = .dateRange XCTAssertTrue(viewModel.isSportsStepVisible) // Step 2: Select sport viewModel.selectedSports = [.mlb] XCTAssertTrue(viewModel.isDatesStepVisible) // Step 3: Set dates viewModel.hasSetDates = true XCTAssertTrue(viewModel.isRegionsStepVisible) // Step 4: Select regions viewModel.selectedRegions = [.east] XCTAssertTrue(viewModel.isRoutePreferenceStepVisible) // Step 5: Set route preference viewModel.hasSetRoutePreference = true XCTAssertTrue(viewModel.isRepeatCitiesStepVisible) // Step 6: Set repeat cities preference viewModel.hasSetRepeatCities = true XCTAssertTrue(viewModel.isMustStopsStepVisible) XCTAssertTrue(viewModel.isReviewStepVisible) } func test_regionSelection_revealsRoutePreference() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.nba] viewModel.hasSetDates = true XCTAssertFalse(viewModel.isRoutePreferenceStepVisible) viewModel.selectedRegions = [.central, .west] XCTAssertTrue(viewModel.isRoutePreferenceStepVisible) } func test_routePreference_revealsRepeatCities() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb] viewModel.hasSetDates = true viewModel.selectedRegions = [.east] XCTAssertFalse(viewModel.isRepeatCitiesStepVisible) viewModel.hasSetRoutePreference = true XCTAssertTrue(viewModel.isRepeatCitiesStepVisible) } func test_repeatCities_revealsMustStopsAndReview() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb] viewModel.hasSetDates = true viewModel.selectedRegions = [.east] viewModel.hasSetRoutePreference = true XCTAssertFalse(viewModel.isMustStopsStepVisible) XCTAssertFalse(viewModel.isReviewStepVisible) viewModel.hasSetRepeatCities = true XCTAssertTrue(viewModel.isMustStopsStepVisible) XCTAssertTrue(viewModel.isReviewStepVisible) } // MARK: - Reset Behavior Tests func test_changingPlanningMode_resetsAllDownstreamState() { let viewModel = TripWizardViewModel() // Set up full wizard state viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb, .nba] viewModel.hasSetDates = true viewModel.selectedRegions = [.east, .central] viewModel.hasSetRoutePreference = true viewModel.hasSetRepeatCities = true viewModel.mustStopLocations = [LocationInput(name: "Test", coordinates: nil)] // Change planning mode viewModel.planningMode = .locations // Verify all downstream state is reset XCTAssertTrue(viewModel.selectedSports.isEmpty) XCTAssertFalse(viewModel.hasSetDates) XCTAssertTrue(viewModel.selectedRegions.isEmpty) XCTAssertFalse(viewModel.hasSetRoutePreference) XCTAssertFalse(viewModel.hasSetRepeatCities) XCTAssertTrue(viewModel.mustStopLocations.isEmpty) } func test_settingSamePlanningMode_doesNotResetState() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb] viewModel.hasSetDates = true // Re-set the same mode viewModel.planningMode = .dateRange // State should NOT be reset XCTAssertEqual(viewModel.selectedSports, [.mlb]) XCTAssertTrue(viewModel.hasSetDates) } // MARK: - Edge Cases func test_emptyRegionSelection_hidesRoutePreference() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb] viewModel.hasSetDates = true viewModel.selectedRegions = [.west] XCTAssertTrue(viewModel.isRoutePreferenceStepVisible) viewModel.selectedRegions = [] XCTAssertFalse(viewModel.isRoutePreferenceStepVisible) } func test_multipleSports_canBeSelected() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb, .nba, .nhl] XCTAssertEqual(viewModel.selectedSports.count, 3) XCTAssertTrue(viewModel.isDatesStepVisible) } func test_multipleRegions_canBeSelected() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb] viewModel.hasSetDates = true viewModel.selectedRegions = [.east, .central, .west] XCTAssertEqual(viewModel.selectedRegions.count, 3) XCTAssertTrue(viewModel.isRoutePreferenceStepVisible) } // MARK: - Reveal State Bitmask Tests func test_revealState_initialValue() { let viewModel = TripWizardViewModel() XCTAssertEqual(viewModel.revealState, 0) } func test_revealState_incrementsWithProgress() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange XCTAssertEqual(viewModel.revealState, 1) // Sports visible viewModel.selectedSports = [.mlb] XCTAssertEqual(viewModel.revealState, 3) // Sports + Dates viewModel.hasSetDates = true XCTAssertEqual(viewModel.revealState, 7) // Sports + Dates + Regions } func test_revealState_fullFlow() { let viewModel = TripWizardViewModel() viewModel.planningMode = .dateRange viewModel.selectedSports = [.mlb] viewModel.hasSetDates = true viewModel.selectedRegions = [.east] viewModel.hasSetRoutePreference = true viewModel.hasSetRepeatCities = true // 1 + 2 + 4 + 8 + 16 + 32 + 64 = 127 XCTAssertEqual(viewModel.revealState, 127) } // MARK: - Sport Availability Tests func test_canSelectSport_defaultsToTrue() { let viewModel = TripWizardViewModel() XCTAssertTrue(viewModel.canSelectSport(.mlb)) XCTAssertTrue(viewModel.canSelectSport(.nba)) XCTAssertTrue(viewModel.canSelectSport(.nhl)) } func test_canSelectSport_respectsAvailability() { let viewModel = TripWizardViewModel() viewModel.sportAvailability = [.mlb: true, .nba: false, .nhl: true] XCTAssertTrue(viewModel.canSelectSport(.mlb)) XCTAssertFalse(viewModel.canSelectSport(.nba)) XCTAssertTrue(viewModel.canSelectSport(.nhl)) } // MARK: - Planning State Tests func test_isPlanning_defaultsToFalse() { let viewModel = TripWizardViewModel() XCTAssertFalse(viewModel.isPlanning) } func test_mustStopLocations_canBeAdded() { let viewModel = TripWizardViewModel() let location = LocationInput(name: "Chicago, IL", coordinates: nil) viewModel.mustStopLocations.append(location) XCTAssertEqual(viewModel.mustStopLocations.count, 1) XCTAssertEqual(viewModel.mustStopLocations.first?.name, "Chicago, IL") } }