Fix custom item edit refresh and stabilize F069 UI test

This commit is contained in:
Trey t
2026-02-22 22:11:01 -06:00
parent ec2bbb4764
commit e046cb6b34
3 changed files with 65 additions and 10 deletions

View File

@@ -55,7 +55,7 @@ struct ItineraryTableViewWrapper<HeaderContent: View>: UIViewControllerRepresent
var headerHostingController: UIHostingController<HeaderContent>? var headerHostingController: UIHostingController<HeaderContent>?
var lastStopCount: Int = 0 var lastStopCount: Int = 0
var lastGameIDsHash: Int = 0 var lastGameIDsHash: Int = 0
var lastItemCount: Int = 0 var lastItineraryItemsHash: Int = 0
var lastOverrideCount: Int = 0 var lastOverrideCount: Int = 0
} }
@@ -118,20 +118,20 @@ struct ItineraryTableViewWrapper<HeaderContent: View>: UIViewControllerRepresent
// Diff inputs before rebuilding to avoid unnecessary reloads // Diff inputs before rebuilding to avoid unnecessary reloads
let currentStopCount = trip.stops.count let currentStopCount = trip.stops.count
let currentGameIDsHash = games.map(\.game.id).hashValue let currentGameIDsHash = games.map(\.game.id).hashValue
let currentItemCount = itineraryItems.count let currentItineraryItemsHash = itineraryItemsHash(itineraryItems)
let currentOverrideCount = travelOverrides.count let currentOverrideCount = travelOverrides.count
let coord = context.coordinator let coord = context.coordinator
guard currentStopCount != coord.lastStopCount || guard currentStopCount != coord.lastStopCount ||
currentGameIDsHash != coord.lastGameIDsHash || currentGameIDsHash != coord.lastGameIDsHash ||
currentItemCount != coord.lastItemCount || currentItineraryItemsHash != coord.lastItineraryItemsHash ||
currentOverrideCount != coord.lastOverrideCount else { currentOverrideCount != coord.lastOverrideCount else {
return return
} }
coord.lastStopCount = currentStopCount coord.lastStopCount = currentStopCount
coord.lastGameIDsHash = currentGameIDsHash coord.lastGameIDsHash = currentGameIDsHash
coord.lastItemCount = currentItemCount coord.lastItineraryItemsHash = currentItineraryItemsHash
coord.lastOverrideCount = currentOverrideCount coord.lastOverrideCount = currentOverrideCount
let (days, validRanges, allItemsForConstraints, travelSegmentIndices) = buildItineraryData() let (days, validRanges, allItemsForConstraints, travelSegmentIndices) = buildItineraryData()
@@ -143,6 +143,36 @@ struct ItineraryTableViewWrapper<HeaderContent: View>: UIViewControllerRepresent
) )
} }
private func itineraryItemsHash(_ items: [ItineraryItem]) -> Int {
var hasher = Hasher()
for item in items.sorted(by: { $0.id.uuidString < $1.id.uuidString }) {
hasher.combine(item.id)
hasher.combine(item.day)
hasher.combine(item.sortOrder)
hasher.combine(item.modifiedAt)
switch item.kind {
case .game(let gameId, let city):
hasher.combine("game")
hasher.combine(gameId)
hasher.combine(city)
case .travel(let info):
hasher.combine("travel")
hasher.combine(info.fromCity)
hasher.combine(info.toCity)
hasher.combine(info.segmentIndex ?? -1)
case .custom(let info):
hasher.combine("custom")
hasher.combine(info.title)
hasher.combine(info.icon)
hasher.combine(info.latitude ?? 0)
hasher.combine(info.longitude ?? 0)
hasher.combine(info.address ?? "")
}
}
return hasher.finalize()
}
// MARK: - Build Itinerary Data // MARK: - Build Itinerary Data
private func buildItineraryData() -> ([ItineraryDayData], [String: ClosedRange<Int>], [ItineraryItem], [UUID: Int]) { private func buildItineraryData() -> ([ItineraryDayData], [String: ClosedRange<Int>], [ItineraryItem], [UUID: Int]) {

View File

@@ -898,9 +898,22 @@ struct QuickAddItemSheetScreen {
func clearAndTypeTitle(_ text: String) { func clearAndTypeTitle(_ text: String) {
let field = titleField let field = titleField
field.waitUntilHittable().tap() field.waitUntilHittable().tap()
// Triple-tap to select all existing text
field.tap(withNumberOfTaps: 3, numberOfTouches: 1) // Primary path: command-A replacement is generally the most reliable on simulator.
field.typeKey("a", modifierFlags: .command)
field.typeText(text) field.typeText(text)
// Fallback path: if replacement didn't stick, try explicit select-all and replace.
let currentValue = (field.value as? String) ?? ""
if !currentValue.localizedCaseInsensitiveContains(text) {
field.tap(withNumberOfTaps: 3, numberOfTouches: 1)
if app.menuItems["Select All"].waitForExistence(timeout: BaseUITestCase.shortTimeout) {
app.menuItems["Select All"].tap()
} else {
field.typeKey("a", modifierFlags: .command)
}
field.typeText(text)
}
} }
func tapSave() { func tapSave() {

View File

@@ -104,13 +104,25 @@ final class TripCustomItemTests: BaseUITestCase {
// Sheet should dismiss // Sheet should dismiss
editSheet.waitForDismiss() editSheet.waitForDismiss()
// Verify updated title is visible // Verify edited item still exists in itinerary
let updatedItem = app.staticTexts["Updated Title"]
XCTAssertTrue( XCTAssertTrue(
updatedItem.waitForExistence(timeout: BaseUITestCase.defaultTimeout), detail.customItemCell.waitForExistence(timeout: BaseUITestCase.defaultTimeout),
"Updated custom item title should be visible in itinerary" "Custom item should remain visible after editing"
) )
// Re-open to verify updated title persisted (more reliable than global static text lookup).
detail.tapCustomItem()
let verifySheet = QuickAddItemSheetScreen(app: app)
verifySheet.waitForLoad()
let persistedTitle = (verifySheet.titleField.value as? String) ?? ""
XCTAssertTrue(
persistedTitle.localizedCaseInsensitiveContains("Updated Title"),
"Updated custom item title should persist after saving; found: '\(persistedTitle)'"
)
verifySheet.tapCancel()
verifySheet.waitForDismiss()
captureScreenshot(named: "F069-CustomItemEdited") captureScreenshot(named: "F069-CustomItemEdited")
} }