Add F-068, F-069, F-070 UI tests for custom itinerary item lifecycle
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -456,6 +456,54 @@ struct TripDetailScreen {
|
||||
XCTAssertEqual(favoriteButton.label, expected,
|
||||
"Favorite button label should reflect saved state")
|
||||
}
|
||||
|
||||
// MARK: - Custom Item Elements
|
||||
|
||||
/// The "Add" button on any day header row (first match).
|
||||
var addItemButton: XCUIElement {
|
||||
app.buttons["tripDetail.addItemButton"].firstMatch
|
||||
}
|
||||
|
||||
/// A custom item cell in the itinerary (first match).
|
||||
var customItemCell: XCUIElement {
|
||||
app.cells["tripDetail.customItem"].firstMatch
|
||||
}
|
||||
|
||||
// MARK: - Custom Item Actions
|
||||
|
||||
/// Scrolls to and taps the first "Add" button on a day header.
|
||||
func tapAddItem() {
|
||||
let button = addItemButton
|
||||
var scrollAttempts = 0
|
||||
while !(button.exists && button.isHittable) && scrollAttempts < 15 {
|
||||
app.swipeUp(velocity: .slow)
|
||||
scrollAttempts += 1
|
||||
}
|
||||
button.waitUntilHittable().tap()
|
||||
}
|
||||
|
||||
/// Taps a custom item cell to open the edit sheet.
|
||||
func tapCustomItem() {
|
||||
let cell = customItemCell
|
||||
var scrollAttempts = 0
|
||||
while !(cell.exists && cell.isHittable) && scrollAttempts < 15 {
|
||||
app.swipeUp(velocity: .slow)
|
||||
scrollAttempts += 1
|
||||
}
|
||||
cell.waitUntilHittable().tap()
|
||||
}
|
||||
|
||||
/// Long-presses a custom item to show the context menu.
|
||||
func longPressCustomItem() {
|
||||
let cell = customItemCell
|
||||
var scrollAttempts = 0
|
||||
while !(cell.exists && cell.isHittable) && scrollAttempts < 15 {
|
||||
app.swipeUp(velocity: .slow)
|
||||
scrollAttempts += 1
|
||||
}
|
||||
cell.waitUntilHittable()
|
||||
cell.press(forDuration: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - My Trips Screen
|
||||
@@ -792,6 +840,68 @@ struct StadiumVisitSheetScreen {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Quick Add Item Sheet Screen
|
||||
|
||||
struct QuickAddItemSheetScreen {
|
||||
let app: XCUIApplication
|
||||
|
||||
// MARK: Elements
|
||||
|
||||
var titleField: XCUIElement {
|
||||
app.textFields["quickAdd.titleField"]
|
||||
}
|
||||
|
||||
var saveButton: XCUIElement {
|
||||
app.buttons["quickAdd.saveButton"]
|
||||
}
|
||||
|
||||
var cancelButton: XCUIElement {
|
||||
app.navigationBars.buttons["Cancel"]
|
||||
}
|
||||
|
||||
// MARK: Actions
|
||||
|
||||
@discardableResult
|
||||
func waitForLoad() -> QuickAddItemSheetScreen {
|
||||
titleField.waitForExistenceOrFail(
|
||||
timeout: BaseUITestCase.defaultTimeout,
|
||||
"Quick add item sheet should appear with title field"
|
||||
)
|
||||
return self
|
||||
}
|
||||
|
||||
/// Waits for the sheet to dismiss by checking the title field disappears.
|
||||
func waitForDismiss() {
|
||||
titleField.waitForNonExistence(
|
||||
timeout: BaseUITestCase.defaultTimeout,
|
||||
"Quick add item sheet should dismiss"
|
||||
)
|
||||
}
|
||||
|
||||
/// Types a title into the description field.
|
||||
func typeTitle(_ text: String) {
|
||||
titleField.waitUntilHittable().tap()
|
||||
titleField.typeText(text)
|
||||
}
|
||||
|
||||
/// Clears existing text and types a new title (for edit mode).
|
||||
func clearAndTypeTitle(_ text: String) {
|
||||
let field = titleField
|
||||
field.waitUntilHittable().tap()
|
||||
// Triple-tap to select all existing text
|
||||
field.tap(withNumberOfTaps: 3, numberOfTouches: 1)
|
||||
field.typeText(text)
|
||||
}
|
||||
|
||||
func tapSave() {
|
||||
saveButton.waitUntilHittable().tap()
|
||||
}
|
||||
|
||||
func tapCancel() {
|
||||
cancelButton.waitUntilHittable().tap()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Games History Screen
|
||||
|
||||
struct GamesHistoryScreen {
|
||||
@@ -980,4 +1090,36 @@ enum TestFlows {
|
||||
|
||||
return (wizard, detail)
|
||||
}
|
||||
|
||||
/// Plans a trip, saves it, navigates back to My Trips, and opens the saved trip.
|
||||
/// Returns a TripDetailScreen with `allowCustomItems` enabled.
|
||||
@MainActor @discardableResult
|
||||
static func planSaveAndOpenFromMyTrips(
|
||||
app: XCUIApplication
|
||||
) -> TripDetailScreen {
|
||||
let (wizard, detail) = planAndSelectFirstTrip(app: app)
|
||||
|
||||
// Save the trip
|
||||
detail.assertSaveState(isSaved: false)
|
||||
detail.tapFavorite()
|
||||
detail.assertSaveState(isSaved: true)
|
||||
|
||||
// Navigate back: Detail → Options → Wizard → Cancel
|
||||
app.navigationBars.buttons.firstMatch.tap()
|
||||
let optionsBackBtn = app.navigationBars.buttons.firstMatch
|
||||
optionsBackBtn.waitUntilHittable(timeout: BaseUITestCase.shortTimeout).tap()
|
||||
wizard.tapCancel()
|
||||
|
||||
// Switch to My Trips tab and open the saved trip
|
||||
let home = HomeScreen(app: app)
|
||||
home.switchToTab(home.myTripsTab)
|
||||
|
||||
let myTrips = MyTripsScreen(app: app)
|
||||
myTrips.assertHasTrips()
|
||||
myTrips.tapTrip(at: 0)
|
||||
|
||||
let savedDetail = TripDetailScreen(app: app)
|
||||
savedDetail.waitForLoad()
|
||||
return savedDetail
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user