Add 22 new UI tests across 8 test files covering Home, Schedule, Progress, Settings, TabNavigation, TripSaving, and TripOptions. Add accessibility identifiers to 11 view files for test element discovery. Fix sport chip assertion logic (all sports start selected, tap deselects), scroll container issues on iOS 26 nested ScrollViews, toggle interaction, and delete trip flow. Update QA coverage map from 32 to 54 automated test cases. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
172 lines
5.0 KiB
Swift
172 lines
5.0 KiB
Swift
//
|
|
// TripSavingTests.swift
|
|
// SportsTimeUITests
|
|
//
|
|
// Tests the end-to-end trip saving flow: plan → select → save → verify in My Trips.
|
|
// QA Sheet: F-064, F-065, F-077, F-078, F-079, F-080
|
|
//
|
|
|
|
import XCTest
|
|
|
|
final class TripSavingTests: BaseUITestCase {
|
|
|
|
// MARK: - Helpers
|
|
|
|
/// Plans a trip, saves it, navigates back to My Trips, and returns the screens.
|
|
@MainActor
|
|
private func planSaveAndReturnToMyTrips() -> (home: HomeScreen, myTrips: MyTripsScreen) {
|
|
let (wizard, detail) = TestFlows.planAndSelectFirstTrip(app: app)
|
|
|
|
detail.assertSaveState(isSaved: false)
|
|
detail.tapFavorite()
|
|
detail.assertSaveState(isSaved: true)
|
|
|
|
// Navigate back: Detail → Options → Wizard → Cancel
|
|
app.navigationBars.buttons.firstMatch.tap()
|
|
let wizardBackBtn = app.navigationBars.buttons.firstMatch
|
|
wizardBackBtn.waitUntilHittable(timeout: BaseUITestCase.shortTimeout).tap()
|
|
wizard.tapCancel()
|
|
|
|
let home = HomeScreen(app: app)
|
|
home.switchToTab(home.myTripsTab)
|
|
|
|
let myTrips = MyTripsScreen(app: app)
|
|
return (home, myTrips)
|
|
}
|
|
|
|
// MARK: - Save Trip (F-043)
|
|
|
|
/// F-043/F-044: Plans a trip, selects an option, saves it, and verifies it appears in My Trips.
|
|
@MainActor
|
|
func testF043_SaveTripAppearsInMyTrips() {
|
|
let (_, myTrips) = planSaveAndReturnToMyTrips()
|
|
myTrips.assertHasTrips()
|
|
|
|
captureScreenshot(named: "F043-TripSaving-InMyTrips")
|
|
}
|
|
|
|
// MARK: - Save/Unsave Toggle (F-048, F-049)
|
|
|
|
/// F-048: Save trip — unsaved trip shows "Save to favorites", tap changes to "Remove from favorites".
|
|
@MainActor
|
|
func testF048_SaveTrip() {
|
|
let (_, detail) = TestFlows.planAndSelectFirstTrip(app: app)
|
|
|
|
detail.assertSaveState(isSaved: false)
|
|
detail.tapFavorite()
|
|
detail.assertSaveState(isSaved: true)
|
|
|
|
captureScreenshot(named: "F048-TripSaved")
|
|
}
|
|
|
|
/// F-049: Unsave trip — saved trip can be un-favorited by tapping again.
|
|
@MainActor
|
|
func testF049_UnsaveTrip() {
|
|
let (_, detail) = TestFlows.planAndSelectFirstTrip(app: app)
|
|
|
|
// Save first
|
|
detail.assertSaveState(isSaved: false)
|
|
detail.tapFavorite()
|
|
detail.assertSaveState(isSaved: true)
|
|
|
|
// Unsave
|
|
detail.tapFavorite()
|
|
detail.assertSaveState(isSaved: false)
|
|
|
|
captureScreenshot(named: "F049-TripUnsaved")
|
|
}
|
|
|
|
// MARK: - Saved Trips List (F-059)
|
|
|
|
/// F-059: Saved trips list shows trip card after saving.
|
|
@MainActor
|
|
func testF059_SavedTripsList() {
|
|
let (_, myTrips) = planSaveAndReturnToMyTrips()
|
|
|
|
myTrips.assertHasTrips()
|
|
|
|
// First trip card should exist
|
|
let firstTrip = myTrips.tripCard(0)
|
|
XCTAssertTrue(
|
|
firstTrip.waitForExistence(timeout: BaseUITestCase.defaultTimeout),
|
|
"First saved trip card should be visible"
|
|
)
|
|
|
|
captureScreenshot(named: "F059-SavedTripsList")
|
|
}
|
|
|
|
// MARK: - Empty State (F-058)
|
|
|
|
/// F-058: My Trips empty state when no trips saved.
|
|
@MainActor
|
|
func testF058_MyTripsEmptyState() {
|
|
let home = HomeScreen(app: app)
|
|
home.waitForLoad()
|
|
home.switchToTab(home.myTripsTab)
|
|
|
|
let myTrips = MyTripsScreen(app: app)
|
|
myTrips.assertEmpty()
|
|
|
|
captureScreenshot(named: "F058-MyTrips-Empty")
|
|
}
|
|
|
|
// MARK: - Tap Saved Trip Opens Detail (F-079)
|
|
|
|
/// F-079: Tapping a saved trip card opens the detail view.
|
|
@MainActor
|
|
func testF079_TapSavedTripOpensDetail() {
|
|
let (_, myTrips) = planSaveAndReturnToMyTrips()
|
|
myTrips.assertHasTrips()
|
|
|
|
// Tap the first saved trip
|
|
myTrips.tapTrip(at: 0)
|
|
|
|
// Trip detail should open
|
|
let detail = TripDetailScreen(app: app)
|
|
detail.waitForLoad()
|
|
detail.assertItineraryVisible()
|
|
|
|
captureScreenshot(named: "F079-TapSavedTripOpensDetail")
|
|
}
|
|
|
|
// MARK: - Remove Saved Trip (F-080)
|
|
|
|
/// F-080: Unfavoriting a trip removes it from My Trips.
|
|
@MainActor
|
|
func testF080_DeleteSavedTrip() {
|
|
let (_, myTrips) = planSaveAndReturnToMyTrips()
|
|
myTrips.assertHasTrips()
|
|
|
|
// Tap into the saved trip detail
|
|
myTrips.tapTrip(at: 0)
|
|
|
|
let detail = TripDetailScreen(app: app)
|
|
detail.waitForLoad()
|
|
|
|
// Unfavorite to remove from saved trips
|
|
detail.assertSaveState(isSaved: true)
|
|
detail.tapFavorite()
|
|
detail.assertSaveState(isSaved: false)
|
|
|
|
// Navigate back to My Trips
|
|
app.navigationBars.buttons.firstMatch.tap()
|
|
|
|
// After unfavoriting, should show empty state
|
|
myTrips.assertEmpty()
|
|
|
|
captureScreenshot(named: "F080-DeleteSavedTrip")
|
|
}
|
|
|
|
// MARK: - Stats Row (F-061)
|
|
|
|
/// F-061: Trip detail stats row shows city count, game count, distance, driving time.
|
|
@MainActor
|
|
func testF061_StatsRowDisplaysCorrectly() {
|
|
let (_, detail) = TestFlows.planAndSelectFirstTrip(app: app)
|
|
|
|
detail.assertStatsRowVisible()
|
|
|
|
captureScreenshot(named: "F061-StatsRow")
|
|
}
|
|
}
|