Add F-010, F-017 UI tests and update QA test plan with 24 automation mappings
- F-010: Tap active tab scrolls to top (TabNavigationTests) - F-017: Recent trips section with saved trips (HomeTests) - Update SportsTime_QA_Test_Plan.xlsx with all 60 automated test mappings - Green highlight on automated cells for visual tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
// HomeTests.swift
|
// HomeTests.swift
|
||||||
// SportsTimeUITests
|
// SportsTimeUITests
|
||||||
//
|
//
|
||||||
// Tests for the Home tab: hero card, start planning, and toolbar button.
|
// Tests for the Home tab: hero card, start planning, toolbar button, and recent trips.
|
||||||
// QA Sheet: F-012, F-013, F-020
|
// QA Sheet: F-012, F-013, F-014, F-017, F-019, F-020
|
||||||
//
|
//
|
||||||
|
|
||||||
import XCTest
|
import XCTest
|
||||||
@@ -79,6 +79,48 @@ final class HomeTests: BaseUITestCase {
|
|||||||
captureScreenshot(named: "F014-FeaturedTrips")
|
captureScreenshot(named: "F014-FeaturedTrips")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// F-017: Recent trips section shows saved trips with "See All" link on Home tab.
|
||||||
|
@MainActor
|
||||||
|
func testF017_RecentTripsSectionWithSavedTrips() {
|
||||||
|
// Plan a trip and select the first option
|
||||||
|
let (_, detail) = TestFlows.planAndSelectFirstTrip(app: app)
|
||||||
|
|
||||||
|
// Save the trip
|
||||||
|
detail.assertSaveState(isSaved: false)
|
||||||
|
detail.tapFavorite()
|
||||||
|
detail.assertSaveState(isSaved: true)
|
||||||
|
|
||||||
|
captureScreenshot(named: "F017-TripSaved")
|
||||||
|
|
||||||
|
// Navigate back: Detail → Options → Wizard → Cancel (dismiss sheet)
|
||||||
|
app.navigationBars.buttons.firstMatch.tap()
|
||||||
|
app.navigationBars.buttons.firstMatch
|
||||||
|
.waitUntilHittable(timeout: BaseUITestCase.shortTimeout).tap()
|
||||||
|
TripWizardScreen(app: app).tapCancel()
|
||||||
|
|
||||||
|
// We're back on Home tab. Wait for it to load.
|
||||||
|
let home = HomeScreen(app: app)
|
||||||
|
home.waitForLoad()
|
||||||
|
|
||||||
|
// Scroll to find the recent trips section
|
||||||
|
let recentTrips = home.recentTripsSection
|
||||||
|
var scrollAttempts = 0
|
||||||
|
while !recentTrips.exists && scrollAttempts < 15 {
|
||||||
|
app.swipeUp(velocity: .slow)
|
||||||
|
scrollAttempts += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
XCTAssertTrue(recentTrips.exists,
|
||||||
|
"Recent trips section should appear after saving a trip")
|
||||||
|
|
||||||
|
// Verify "See All" link is visible
|
||||||
|
let seeAllText = app.staticTexts["See All"]
|
||||||
|
XCTAssertTrue(seeAllText.exists,
|
||||||
|
"'See All' link should be visible in recent trips section")
|
||||||
|
|
||||||
|
captureScreenshot(named: "F017-RecentTripsSection")
|
||||||
|
}
|
||||||
|
|
||||||
/// F-019: Planning tips section is visible at bottom of home tab.
|
/// F-019: Planning tips section is visible at bottom of home tab.
|
||||||
@MainActor
|
@MainActor
|
||||||
func testF019_PlanningTipsSectionVisible() {
|
func testF019_PlanningTipsSectionVisible() {
|
||||||
|
|||||||
@@ -44,6 +44,39 @@ final class TabNavigationTests: BaseUITestCase {
|
|||||||
captureScreenshot(named: "F008-TabNavigation-ReturnHome")
|
captureScreenshot(named: "F008-TabNavigation-ReturnHome")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// F-010: Tapping the active tab scrolls the view back to the top.
|
||||||
|
@MainActor
|
||||||
|
func testF010_TapActiveTabScrollsToTop() {
|
||||||
|
let home = HomeScreen(app: app)
|
||||||
|
home.waitForLoad()
|
||||||
|
|
||||||
|
// Verify "Adventure Awaits" hero card is hittable at the top
|
||||||
|
XCTAssertTrue(home.adventureAwaitsText.isHittable,
|
||||||
|
"Adventure Awaits should be hittable initially")
|
||||||
|
|
||||||
|
// Scroll down until the hero card is off-screen
|
||||||
|
for _ in 0..<8 {
|
||||||
|
app.swipeUp(velocity: .slow)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the hero card is no longer hittable (scrolled off-screen)
|
||||||
|
XCTAssertFalse(home.adventureAwaitsText.isHittable,
|
||||||
|
"Adventure Awaits should not be hittable after scrolling down")
|
||||||
|
|
||||||
|
captureScreenshot(named: "F010-ScrolledDown")
|
||||||
|
|
||||||
|
// Tap the Home tab (already the active tab) to trigger scroll-to-top
|
||||||
|
home.homeTab.waitUntilHittable(timeout: BaseUITestCase.shortTimeout).tap()
|
||||||
|
|
||||||
|
// Hero card should scroll back into view and become hittable
|
||||||
|
home.adventureAwaitsText.waitUntilHittable(
|
||||||
|
timeout: BaseUITestCase.defaultTimeout,
|
||||||
|
"Adventure Awaits should be hittable after tapping active tab (scroll to top)"
|
||||||
|
)
|
||||||
|
|
||||||
|
captureScreenshot(named: "F010-ScrolledToTop")
|
||||||
|
}
|
||||||
|
|
||||||
/// F-009: Tab state preserved — Schedule filters survive tab switch.
|
/// F-009: Tab state preserved — Schedule filters survive tab switch.
|
||||||
@MainActor
|
@MainActor
|
||||||
func testF009_TabStatePreservedOnSwitch() {
|
func testF009_TabStatePreservedOnSwitch() {
|
||||||
|
|||||||
Binary file not shown.
120
uiTestPrompt.md
120
uiTestPrompt.md
@@ -1,49 +1,105 @@
|
|||||||
# UI Test Prompt Template
|
# SportsTime UI Test Prompt (Paste Into Claude)
|
||||||
|
|
||||||
Use this prompt when asking an agent to add or modify SportsTime UI tests.
|
Use this when you want Claude to pick and implement the 3 easiest UI tests from QA IDs/names you provide.
|
||||||
|
|
||||||
|
Replace the `INPUT` section, then paste the whole prompt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
You are updating SportsTime UI tests.
|
You are an iOS UI test engineer working in the SportsTime repo.
|
||||||
|
|
||||||
## Goal
|
## Mission
|
||||||
|
|
||||||
- [Describe the behavior to test or fix.]
|
From the provided QA cases (IDs/names from `docs/SportsTime_QA_Test_Plan.xlsx`), pick the **3 easiest, lowest-flake cases** and implement solid UI tests for them using the **existing SportsTime UI test architecture**.
|
||||||
|
|
||||||
## Scope
|
## Non-Negotiable Rules
|
||||||
|
|
||||||
- Update/add tests under `SportsTimeUITests/Tests/`.
|
1. Do not reinvent the test framework.
|
||||||
- Reuse page objects in `SportsTimeUITests/Framework/Screens.swift`.
|
2. Reuse existing architecture:
|
||||||
- Reuse shared setup in `SportsTimeUITests/Framework/BaseUITestCase.swift`.
|
- `SportsTimeUITests/Framework/BaseUITestCase.swift`
|
||||||
- Reuse existing `TestFlows` where possible.
|
- `SportsTimeUITests/Framework/Screens.swift`
|
||||||
|
- existing `TestFlows` helpers
|
||||||
|
- existing suites under `SportsTimeUITests/Tests/`
|
||||||
|
3. Prefer updating existing suites over creating new ones.
|
||||||
|
4. Use stable accessibility IDs already used in the app/tests (`home.*`, `wizard.*`, `tripOptions.*`, `tripDetail.*`, `schedule.*`, `settings.*`, `progress.*`, etc.).
|
||||||
|
5. Prefer robust waits (`waitForExistenceOrFail`, `waitUntilHittable`) and page-object methods.
|
||||||
|
6. Avoid `sleep` unless there is no reliable alternative; if used, justify it.
|
||||||
|
7. Keep tests deterministic with current local test data.
|
||||||
|
8. Follow naming conventions (`testF###_...`, `testP###_...`, etc.).
|
||||||
|
9. Do not change product code unless absolutely required for testability (and explain why).
|
||||||
|
10. Change only what is needed for these 3 tests.
|
||||||
|
|
||||||
## Required Changes
|
## Required Reading Before Coding
|
||||||
|
|
||||||
- [List test suites to modify.]
|
1. `AGENTS.md`
|
||||||
- [List new test names.]
|
2. `XCUITest-Authoring.md`
|
||||||
- [List selectors/page-object methods to add if needed.]
|
3. Existing tests in `SportsTimeUITests/Tests/` for patterns and style
|
||||||
|
|
||||||
## Constraints
|
## Selection Strategy (Pick Exactly 3)
|
||||||
|
|
||||||
- Do not add raw sleeps unless strictly necessary.
|
Choose the 3 easiest cases using this priority order:
|
||||||
- Prefer `waitForExistenceOrFail` and `waitUntilHittable`.
|
|
||||||
- Keep tests deterministic with current local test data.
|
|
||||||
- Keep existing naming style (`testF###_...`, `testP###_...`, etc.).
|
|
||||||
|
|
||||||
## Validation
|
1. Already mostly covered by existing screen objects/flows.
|
||||||
|
2. Requires minimal or no new selectors.
|
||||||
|
3. No unstable backend/timing dependency.
|
||||||
|
4. No complex multi-screen setup unless reusable via existing `TestFlows`.
|
||||||
|
5. Highest confidence of passing consistently on current simulator baseline.
|
||||||
|
|
||||||
Run these before finishing:
|
If a candidate looks flaky/high-risk, skip it and explain why.
|
||||||
|
|
||||||
1. Targeted class or test:
|
## Implementation Workflow
|
||||||
- `xcodebuild test-without-building -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' -parallel-testing-enabled NO -only-testing:SportsTimeUITests/<SuiteOrTest>`
|
|
||||||
2. Full UI suite:
|
|
||||||
- `xcodebuild test-without-building -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' -parallel-testing-enabled NO -only-testing:SportsTimeUITests`
|
|
||||||
3. If requested, full scheme:
|
|
||||||
- `xcodebuild test-without-building -project SportsTime.xcodeproj -scheme SportsTime -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' -parallel-testing-enabled NO`
|
|
||||||
|
|
||||||
## Output Format
|
1. Evaluate all candidate QA cases.
|
||||||
|
2. Output a short ranked list with reason for each.
|
||||||
|
3. Confirm the chosen 3.
|
||||||
|
4. Implement tests:
|
||||||
|
- Put tests in existing or appropriate suite(s) in `SportsTimeUITests/Tests/`.
|
||||||
|
- Add page-object helpers in `Screens.swift` only when reusable.
|
||||||
|
- Keep assertions behavior-focused and explicit.
|
||||||
|
- Capture screenshots at key checkpoints for longer flows.
|
||||||
|
5. Run only the 3 selected tests first.
|
||||||
|
6. Fix failures.
|
||||||
|
7. Re-run each selected test at least 2 times to catch flake.
|
||||||
|
8. Stop only when all 3 are green and stable, or clearly blocked.
|
||||||
|
|
||||||
- Summarize files changed.
|
## Validation Commands
|
||||||
- Summarize root causes fixed.
|
|
||||||
- Include exact commands run and pass/fail outcomes.
|
Use this destination:
|
||||||
- Call out any remaining flaky behavior or follow-up work.
|
|
||||||
|
`-destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2'`
|
||||||
|
|
||||||
|
Run each selected test explicitly:
|
||||||
|
|
||||||
|
`xcodebuild test-without-building -project SportsTime.xcodeproj -scheme SportsTime -parallel-testing-enabled NO -only-testing:SportsTimeUITests/<SuiteName>/test<ID>_<Name> <destination>`
|
||||||
|
|
||||||
|
If needed, run selected suite only:
|
||||||
|
|
||||||
|
`xcodebuild test-without-building -project SportsTime.xcodeproj -scheme SportsTime -parallel-testing-enabled NO -only-testing:SportsTimeUITests/<SuiteName> <destination>`
|
||||||
|
|
||||||
|
Do not run the full suite unless I ask.
|
||||||
|
|
||||||
|
## Output Contract
|
||||||
|
|
||||||
|
Return:
|
||||||
|
|
||||||
|
1. Chosen 3 QA cases and why they were selected.
|
||||||
|
2. Files changed and what changed in each.
|
||||||
|
3. Exact commands run.
|
||||||
|
4. Test results for each selected test (including repeat runs).
|
||||||
|
5. Any residual risk or blocker.
|
||||||
|
6. Optional next 2-3 QA cases to implement next (ranked by ease/confidence).
|
||||||
|
|
||||||
|
## INPUT (Replace This Block)
|
||||||
|
|
||||||
|
Candidate QA cases from `docs/SportsTime_QA_Test_Plan.xlsx`:
|
||||||
|
|
||||||
|
- [F-___]
|
||||||
|
- [F-___]
|
||||||
|
- [F-___]
|
||||||
|
- [F-___]
|
||||||
|
- [F-___]
|
||||||
|
|
||||||
|
Extra constraints:
|
||||||
|
|
||||||
|
- [Example: Do not edit `SportsTimeUITests/Tests/TripSavingTests.swift`]
|
||||||
|
- [Example: Only use existing `TestFlows`]
|
||||||
|
|||||||
Reference in New Issue
Block a user