// // ScheduleTests.swift // SportsTimeUITests // // Verifies the Schedule tab loads and displays content. // QA Sheet: F-085, F-086, F-087, F-088, F-089, F-090, F-091, F-092, F-094 // import XCTest final class ScheduleTests: BaseUITestCase { /// F-047: Schedule tab loads and shows filter button. @MainActor func testF047_ScheduleTabLoads() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() captureScreenshot(named: "F047-Schedule-Loaded") } /// F-055: Sport filter chips are visible and tappable. @MainActor func testF055_SportFilterChips() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // Verify at least MLB chip is present and tappable let mlbChip = schedule.sportChip("mlb") XCTAssertTrue( mlbChip.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "MLB sport filter chip should exist" ) // All sports start selected. Tap MLB chip to DESELECT it. mlbChip.tap() // After tap, MLB is deselected (removed from selectedSports) XCTAssertEqual(mlbChip.value as? String, "Not selected", "MLB chip should be deselected after tap (starts selected, tap toggles off)") captureScreenshot(named: "F055-SportChip-MLB-Selected") } /// F-087: Multiple sport filter chips can be selected simultaneously. @MainActor func testF087_MultipleSportFilters() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // All sports start selected. Tap MLB to DESELECT it. let mlbChip = schedule.sportChip("mlb") XCTAssertTrue(mlbChip.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "MLB chip should exist") mlbChip.tap() XCTAssertEqual(mlbChip.value as? String, "Not selected", "MLB chip should be deselected after tap") // Also deselect NBA let nbaChip = schedule.sportChip("nba") if nbaChip.waitForExistence(timeout: BaseUITestCase.shortTimeout) { nbaChip.tap() XCTAssertEqual(nbaChip.value as? String, "Not selected", "NBA chip should be deselected after tap") } // MLB should still be deselected (independent toggle) XCTAssertEqual(mlbChip.value as? String, "Not selected", "MLB chip should remain deselected when NBA is also toggled") captureScreenshot(named: "F087-MultipleSportFilters") } /// F-088: Clear/reset filters returns schedule to default state. @MainActor func testF088_ClearAllFilters() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // All sports start selected. Tap MLB to deselect it. let mlbChip = schedule.sportChip("mlb") XCTAssertTrue(mlbChip.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "MLB chip should exist") mlbChip.tap() XCTAssertEqual(mlbChip.value as? String, "Not selected", "MLB chip should be deselected after first tap") // Tap again to re-select it (restoring to original state) mlbChip.tap() // Chip should be back to "Selected" XCTAssertEqual(mlbChip.value as? String, "Selected", "MLB chip should be re-selected after second tap") captureScreenshot(named: "F088-FiltersCleared") } /// F-089: Search by team name filters schedule results. @MainActor func testF089_SearchByTeamName() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // Tap search field and type team name let searchField = schedule.searchField XCTAssertTrue(searchField.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "Search field should exist") searchField.tap() searchField.typeText("Yankees") // Wait for results to filter sleep(1) captureScreenshot(named: "F089-SearchByTeam") } /// F-090: Search by venue name filters schedule results. @MainActor func testF090_SearchByVenueName() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // Tap search field and type venue name let searchField = schedule.searchField XCTAssertTrue(searchField.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "Search field should exist") searchField.tap() searchField.typeText("Wrigley") // Wait for results to filter sleep(1) captureScreenshot(named: "F090-SearchByVenue") } /// F-092: Empty state appears when filters match no games. @MainActor func testF092_ScheduleEmptyState() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // Type a nonsensical search term to get no results let searchField = schedule.searchField XCTAssertTrue(searchField.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "Search field should exist") searchField.tap() searchField.typeText("ZZZZNONEXISTENTTEAMZZZZ") // Wait for empty state sleep(1) // Empty state or "no results" text should appear let emptyState = schedule.emptyState let noResults = app.staticTexts.matching(NSPredicate( format: "label CONTAINS[c] 'no' AND label CONTAINS[c] 'game'" )).firstMatch let hasEmptyIndicator = emptyState.waitForExistence(timeout: BaseUITestCase.shortTimeout) || noResults.waitForExistence(timeout: BaseUITestCase.shortTimeout) XCTAssertTrue(hasEmptyIndicator, "Empty state should appear when no games match search") captureScreenshot(named: "F092-ScheduleEmptyState") } // MARK: - Date Range Filter (F-091) /// F-091: Date range filter sheet opens and applies. @MainActor func testF091_DateRangeFilter() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // Open filter menu schedule.filterButton.tap() // Tap "Date Range" in the menu let dateRangeButton = app.buttons["Date Range"] XCTAssertTrue(dateRangeButton.waitForExistence(timeout: BaseUITestCase.shortTimeout), "Date Range menu item should exist") dateRangeButton.tap() // Date range picker sheet should appear let sheetTitle = app.staticTexts["Select Dates"] XCTAssertTrue(sheetTitle.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "Date range picker sheet should appear") // Tap "Next 7 Days" quick option let next7Days = app.buttons["Next 7 Days"] XCTAssertTrue(next7Days.exists, "Next 7 Days button should exist") next7Days.tap() // Apply the filter let applyButton = app.buttons["Apply"] XCTAssertTrue(applyButton.exists, "Apply button should exist") applyButton.tap() // Schedule should still function after applying date filter schedule.assertLoaded() captureScreenshot(named: "F091-DateRangeFilter") } // MARK: - Diagnostics (F-094) /// F-094: Diagnostics button opens the diagnostics sheet. @MainActor func testF094_ScheduleDiagnostics() { let home = HomeScreen(app: app) home.waitForLoad() home.switchToTab(home.scheduleTab) let schedule = ScheduleScreen(app: app) schedule.assertLoaded() // Tap the filter menu button to open the menu schedule.filterButton.tap() // Tap "Diagnostics" in the menu let diagnosticsButton = app.buttons["Diagnostics"] XCTAssertTrue(diagnosticsButton.waitForExistence(timeout: BaseUITestCase.shortTimeout), "Diagnostics menu item should exist") diagnosticsButton.tap() // Diagnostics sheet should appear with game count info let sheetContent = app.navigationBars.firstMatch XCTAssertTrue(sheetContent.waitForExistence(timeout: BaseUITestCase.defaultTimeout), "Diagnostics sheet should appear") captureScreenshot(named: "F094-ScheduleDiagnostics") } }