Files
Sportstime/SportsTimeUITests/Tests/ProgressTests.swift
Trey t 8421b23f0c Add F-100, F-101, F-106 UI tests and page objects for Progress feature
Adds 3 new UI tests covering stadium visit manual entry, required field
validation, and games history navigation. Includes accessibility IDs on
StadiumVisitSheet/ProgressTabView and new page objects (StadiumVisitSheetScreen,
GamesHistoryScreen) in the test framework.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 23:02:52 -06:00

207 lines
7.1 KiB
Swift

//
// ProgressTests.swift
// SportsTimeUITests
//
// Tests for the Progress tab (Pro-gated).
// QA Sheet: F-066, F-097, F-100, F-101, F-106, F-110
//
import XCTest
final class ProgressTests: BaseUITestCase {
/// F-066: Progress tab loads for Pro user stadium quest and navigation visible.
@MainActor
func testF066_ProgressTabLoads() {
let home = HomeScreen(app: app)
home.waitForLoad()
home.switchToTab(home.progressTab)
let progress = ProgressScreen(app: app)
progress.waitForLoad()
// Stadium Quest label should be visible (proves data loaded)
XCTAssertTrue(
progress.stadiumQuestLabel.waitForExistence(
timeout: BaseUITestCase.longTimeout),
"Stadium Quest label should appear on Progress tab"
)
captureScreenshot(named: "F066-ProgressTab-Loaded")
}
/// F-097: League/sport selector toggles between sports.
@MainActor
func testF097_LeagueSportSelector() {
let home = HomeScreen(app: app)
home.waitForLoad()
home.switchToTab(home.progressTab)
let progress = ProgressScreen(app: app)
progress.waitForLoad()
// Sport buttons inherit the parent's identifier (progress.sportSelector),
// so find them by their accessibility label which includes the sport name.
let mlbButton = app.buttons.matching(NSPredicate(
format: "label BEGINSWITH 'MLB'"
)).firstMatch
XCTAssertTrue(mlbButton.waitForExistence(timeout: BaseUITestCase.longTimeout),
"MLB sport button should exist in sport selector")
mlbButton.tap()
captureScreenshot(named: "F097-SportSelector-MLB")
// Switch to NBA
let nbaButton = app.buttons.matching(NSPredicate(
format: "label BEGINSWITH 'NBA'"
)).firstMatch
if nbaButton.waitForExistence(timeout: BaseUITestCase.shortTimeout) {
nbaButton.tap()
captureScreenshot(named: "F097-SportSelector-NBA")
}
}
/// F-101: Add visit Save button disabled until stadium is selected.
@MainActor
func testF101_AddVisitRequiredFields() {
let home = HomeScreen(app: app)
home.waitForLoad()
home.switchToTab(home.progressTab)
let progress = ProgressScreen(app: app)
progress.waitForLoad()
progress.tapAddManualVisit()
let visitSheet = StadiumVisitSheetScreen(app: app)
visitSheet.waitForLoad()
// Save button should exist but be disabled (no stadium selected)
XCTAssertTrue(
visitSheet.saveButton.waitForExistence(timeout: BaseUITestCase.shortTimeout),
"Save button should exist"
)
XCTAssertFalse(
visitSheet.saveButton.isEnabled,
"Save button should be disabled without a stadium selected"
)
captureScreenshot(named: "F101-SaveDisabledNoStadium")
}
/// F-100: Add visit full manual entry flow (select stadium, save).
@MainActor
func testF100_AddVisitManualEntry() {
let home = HomeScreen(app: app)
home.waitForLoad()
home.switchToTab(home.progressTab)
let progress = ProgressScreen(app: app)
progress.waitForLoad()
progress.tapAddManualVisit()
let visitSheet = StadiumVisitSheetScreen(app: app)
visitSheet.waitForLoad()
// Pick a stadium
visitSheet.pickFirstStadium()
// Save button should now be enabled
XCTAssertTrue(
visitSheet.saveButton.waitForExistence(timeout: BaseUITestCase.shortTimeout),
"Save button should exist after picking a stadium"
)
XCTAssertTrue(
visitSheet.saveButton.isEnabled,
"Save button should be enabled after selecting a stadium"
)
// Save the visit
visitSheet.tapSave()
// Sheet should dismiss nav bar disappears
visitSheet.navigationBar.waitForNonExistence(
timeout: BaseUITestCase.defaultTimeout,
"Visit sheet should dismiss after save"
)
captureScreenshot(named: "F100-ManualEntryComplete")
}
/// F-106: View Games History add a visit, then navigate to history view.
@MainActor
func testF106_ViewGamesHistory() {
let home = HomeScreen(app: app)
home.waitForLoad()
home.switchToTab(home.progressTab)
let progress = ProgressScreen(app: app)
progress.waitForLoad()
// Add a visit first (prerequisite: Recent Visits section only shows with visits)
progress.tapAddManualVisit()
let visitSheet = StadiumVisitSheetScreen(app: app)
visitSheet.waitForLoad()
visitSheet.pickFirstStadium()
visitSheet.tapSave()
visitSheet.navigationBar.waitForNonExistence(timeout: BaseUITestCase.defaultTimeout)
// Wait for data reload Recent Visits section should appear in hierarchy
XCTAssertTrue(
progress.recentVisitsTitle.waitForExistence(timeout: BaseUITestCase.longTimeout),
"Recent Visits section should appear after adding a visit"
)
// Scroll to Recent Visits (same pattern as F-110 which uses app.swipeUp)
var scrollAttempts = 0
while !progress.recentVisitsTitle.isHittable && scrollAttempts < 20 {
app.swipeUp(velocity: .slow)
scrollAttempts += 1
}
// Find and tap "See All" try button, link, then generic element
let seeAllPredicate = NSPredicate(format: "label CONTAINS[c] 'See All'")
let seeAllButton = app.buttons.matching(seeAllPredicate).firstMatch
let seeAllGeneric = app.descendants(matching: .any).matching(seeAllPredicate).firstMatch
if seeAllButton.exists && seeAllButton.isHittable {
seeAllButton.tap()
} else if seeAllGeneric.exists {
// One more scroll to ensure it's on screen
if !seeAllGeneric.isHittable {
app.swipeUp(velocity: .slow)
}
seeAllGeneric.tap()
} else {
XCTFail("Could not find 'See All' link in Recent Visits section")
}
// Verify Games History view loads
let gamesHistory = GamesHistoryScreen(app: app)
gamesHistory.waitForLoad()
captureScreenshot(named: "F106-GamesHistory")
}
/// F-110: Achievements gallery is visible with badge grid.
@MainActor
func testF110_AchievementsGalleryVisible() {
let home = HomeScreen(app: app)
home.waitForLoad()
home.switchToTab(home.progressTab)
let progress = ProgressScreen(app: app)
progress.waitForLoad()
// Achievements section is below the fold swipe up to find it
let achievementsTitle = progress.achievementsTitle
var scrollAttempts = 0
while !achievementsTitle.exists && scrollAttempts < 15 {
app.swipeUp(velocity: .slow)
scrollAttempts += 1
}
XCTAssertTrue(achievementsTitle.exists, "Achievements section should be visible")
captureScreenshot(named: "F110-AchievementsGallery")
}
}