field_ios

In-the-field app for Radroots on iOS
git clone https://radroots.dev/git/field_ios.git
Log | Files | Refs | README | LICENSE

commit b76add30d75a2cb3235c96d1c76fa6f519bb44d4
parent 5f81e090dfcbf48d74454ce0e01b456dd67a11b0
Author: triesap <tyson@radroots.org>
Date:   Mon, 31 Aug 2026 23:20:42 +0000

test(ios): stabilize settings navigation

- scroll the Settings row fully into the Me sheet viewport
- require the destination Settings view after the visible tap
- reuse the governed navigation for Blossom diagnostics
- preserve semantic UI actions without coordinate shortcuts

Diffstat:
MRadrootsUITests/RadrootsRemoteQualificationUITests.swift | 47+++++++++++++++++++++++++++++------------------
1 file changed, 29 insertions(+), 18 deletions(-)

diff --git a/RadrootsUITests/RadrootsRemoteQualificationUITests.swift b/RadrootsUITests/RadrootsRemoteQualificationUITests.swift @@ -688,23 +688,13 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { guard meSheet.waitForExistence(timeout: 10) else { throw QualificationError.missingProductSurface } - let meList = meSheet.descendants(matching: .collectionView).firstMatch - let settings = app.descendants(matching: .any)["radroots.support.settings"] - for _ in 0 ..< 8 where !settings.exists { - meList.swipeUp() - } - guard settings.waitForExistence(timeout: 20) else { - XCTFail("Settings was unavailable through the visible Me sheet") - throw QualificationError.missingProductSurface - } let publicKey = app.descendants(matching: .any)[ "radroots.settings.identity.public_key" ] - guard waitUntilHittable(settings, timeout: 10) else { - XCTFail("Settings did not become hittable through the visible Me sheet") + guard openSettingsFromMe(app, meSheet: meSheet) else { + XCTFail("Settings was unavailable through the visible Me sheet") throw QualificationError.missingProductSurface } - settings.tap() guard publicKey.waitForExistence(timeout: 10) else { XCTFail("Settings did not present the native identity public key") throw QualificationError.missingProductSurface @@ -734,12 +724,10 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { guard account.waitForExistence(timeout: 10) else { return "settings=unavailable" } account.tap() - let settings = app.descendants(matching: .any)["radroots.support.settings"] - for _ in 0 ..< 5 where !settings.exists { - app.swipeUp() - } - guard settings.waitForExistence(timeout: 20) else { return "settings=unavailable" } - settings.tap() + let meSheet = app.descendants(matching: .any)["radroots.support.me.sheet"] + guard meSheet.waitForExistence(timeout: 10), + openSettingsFromMe(app, meSheet: meSheet) + else { return "settings=unavailable" } let httpStatus = app.descendants(matching: .any)[ "radroots.settings.blossom.http_status" @@ -1437,6 +1425,29 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { } @MainActor + private func openSettingsFromMe( + _ app: XCUIApplication, + meSheet: XCUIElement + ) -> Bool { + let meList = meSheet.descendants(matching: .collectionView).firstMatch + guard meList.waitForExistence(timeout: 10) else { return false } + let settings = app.descendants(matching: .any)["radroots.support.settings"] + for _ in 0 ..< 8 { + if settings.exists, + settings.isHittable, + settings.frame.minY >= meSheet.frame.minY, + settings.frame.maxY <= meSheet.frame.maxY + { + settings.tap() + return app.descendants(matching: .any)["radroots.support.settings.view"] + .waitForExistence(timeout: 20) + } + meList.swipeUp() + } + return false + } + + @MainActor private func focusForTextInput(_ element: XCUIElement, timeout: TimeInterval) -> Bool { let focused = NSPredicate(format: "hasKeyboardFocus == true") for _ in 0 ..< 3 {