263 lines
9.2 KiB
Swift
263 lines
9.2 KiB
Swift
//
|
|
// 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")
|
|
XCTAssertTrue(
|
|
((searchField.value as? String) ?? "").contains("Yankees"),
|
|
"Search field should contain the typed team name"
|
|
)
|
|
|
|
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")
|
|
XCTAssertTrue(
|
|
((searchField.value as? String) ?? "").contains("Wrigley"),
|
|
"Search field should contain the typed venue name"
|
|
)
|
|
|
|
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")
|
|
|
|
// 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
|
|
|
|
waitUntil(timeout: BaseUITestCase.shortTimeout, "Empty state should appear when no games match search") {
|
|
emptyState.exists || noResults.exists
|
|
}
|
|
|
|
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")
|
|
}
|
|
}
|