diff --git a/features/messaging/ios/LilithMessengerUITests/ScreenshotTests.swift b/features/messaging/ios/LilithMessengerUITests/ScreenshotTests.swift index bd9b1244c..78574ec1a 100644 --- a/features/messaging/ios/LilithMessengerUITests/ScreenshotTests.swift +++ b/features/messaging/ios/LilithMessengerUITests/ScreenshotTests.swift @@ -79,8 +79,7 @@ final class ScreenshotTests: XCTestCase { /// /// SwiftUI NavigationLink in a List renders as a Button in the accessibility /// tree. Items below the fold aren't rendered until scrolled into view. - /// After scrolling, ensures the element is hittable (not behind safe area) - /// before tapping. Verifies navigation via the nav bar title. + /// Uses coordinate-based tapping to reliably hit elements near viewport edges. @discardableResult private func navigateToSettingsSubScreen( accessibilityId: String, @@ -93,29 +92,34 @@ final class ScreenshotTests: XCTestCase { let navBar = app.navigationBars[expectedTitle] let link = app.buttons[accessibilityId] - // Scroll until the link is visible AND hittable (not behind safe area) - for _ in 0..<3 { + // Scroll using small drag gestures to avoid overshooting and + // deceleration interference. Each drag moves ~200pt upward. + for _ in 0..<4 { if link.exists && link.isHittable { break } if settingsList.exists { - settingsList.swipeUp() + let start = settingsList.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.7)) + let end = settingsList.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.3)) + start.press(forDuration: 0.05, thenDragTo: end) sleep(1) } _ = link.waitForExistence(timeout: 2) } - // Tap by button identifier if hittable + // Tap using the element's center coordinate for reliable hit targeting, + // especially when the element is near the viewport edge where .tap() + // can miss the NavigationLink's hit area. if link.exists && link.isHittable { - link.tap() - if navBar.waitForExistence(timeout: 3) { + link.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() + if navBar.waitForExistence(timeout: 5) { return true } } - // Fallback: tap by the label text (inside the NavigationLink row) + // Fallback: tap the label text directly let label = app.staticTexts[fallbackLabel] if label.exists && label.isHittable { - label.tap() - if navBar.waitForExistence(timeout: 3) { + label.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() + if navBar.waitForExistence(timeout: 5) { return true } } diff --git a/features/messaging/ios/screenshots/12_debug.png b/features/messaging/ios/screenshots/12_debug.png new file mode 100644 index 000000000..7a99c23ab Binary files /dev/null and b/features/messaging/ios/screenshots/12_debug.png differ