// // 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-092 // 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") } }