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 92b7b5528150afc41e4d0b91f09b98a217a4c0f5
parent 7afbc3b60046362e6f12eb677ab202e9768e91d5
Author: triesap <tyson@radroots.org>
Date:   Fri, 28 Aug 2026 18:32:15 +0000

test: bind persona submission to status

- Observe the ordinary Add status lifecycle instead of virtualized row presence.
- Use one visible submit tap so qualification cannot introduce duplicate events.
- Scroll to the terminal submit control before reading its safe result value.
- Keep failure diagnostics from dereferencing absent XCUITest elements.

Diffstat:
MRadrootsUITests/RadrootsRemoteQualificationUITests.swift | 57++++++++++++++++++++++++++-------------------------------
1 file changed, 26 insertions(+), 31 deletions(-)

diff --git a/RadrootsUITests/RadrootsRemoteQualificationUITests.swift b/RadrootsUITests/RadrootsRemoteQualificationUITests.swift @@ -1067,12 +1067,14 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { @MainActor private func submitAndWait(_ app: XCUIApplication, submit: XCUIElement) -> String? { - let priorSubmitValue = submit.value as? String + let status = app.staticTexts.matching(identifier: "radroots.add.status").firstMatch + let priorStatusLabel = status.exists ? status.label : nil guard tapSubmitUntilWorkStarts( app, submit: submit, - priorSubmitValue: priorSubmitValue + status: status, + priorStatusLabel: priorStatusLabel ) else { XCTFail( @@ -1084,8 +1086,8 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { guard waitForWorkToFinish( app, - submit: submit, - priorSubmitValue: priorSubmitValue + status: status, + priorStatusLabel: priorStatusLabel ) else { XCTFail( @@ -1094,6 +1096,11 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { ) return nil } + scrollTo(app, element: submit) + guard submit.waitForExistence(timeout: 10) else { + XCTFail("The terminal Add submission control was unavailable") + return nil + } return submit.value as? String ?? "missing" } @@ -1123,18 +1130,13 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { @MainActor private func waitForWorkToFinish( _ app: XCUIApplication, - submit: XCUIElement, - priorSubmitValue: String? + status: XCUIElement, + priorStatusLabel: String? ) -> Bool { let progress = app.descendants(matching: .any)["radroots.add.progress"] let finished = NSPredicate { _, _ in - guard !progress.exists else { return false } - guard submit.exists else { - return app.buttons["radroots.add.new"].exists - } - let submitValue = submit.value as? String - return submitValue != priorSubmitValue - && submitValue != "Working" + guard !progress.exists, status.exists else { return false } + return !status.label.isEmpty && status.label != priorStatusLabel } let expectation = XCTNSPredicateExpectation(predicate: finished, object: app) return XCTWaiter.wait(for: [expectation], timeout: 180) == .completed @@ -1144,29 +1146,19 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { private func tapSubmitUntilWorkStarts( _ app: XCUIApplication, submit: XCUIElement, - priorSubmitValue: String? + status: XCUIElement, + priorStatusLabel: String? ) -> Bool { let progress = app.descendants(matching: .any)["radroots.add.progress"] let started = NSPredicate { _, _ in - guard !progress.exists else { return true } - guard submit.exists else { return true } - let submitValue = submit.value as? String - return submitValue != priorSubmitValue + if progress.exists { return true } + if status.exists { return status.label != priorStatusLabel } + return priorStatusLabel != nil } - for _ in 0..<3 { - submit.tap() - let expectation = XCTNSPredicateExpectation(predicate: started, object: app) - if XCTWaiter.wait(for: [expectation], timeout: 5) == .completed { - return true - } - guard waitUntilHittable(submit, timeout: 5), - isUnobscured(submit, above: app.tabBars.firstMatch) - else { - return false - } - } - return false + submit.tap() + let expectation = XCTNSPredicateExpectation(predicate: started, object: app) + return XCTWaiter.wait(for: [expectation], timeout: 10) == .completed } @MainActor @@ -1188,6 +1180,9 @@ final class RadrootsRemoteQualificationUITests: XCTestCase { let progress = app.descendants(matching: .any)["radroots.add.progress"] let status = app.staticTexts.matching(identifier: "radroots.add.status").firstMatch let statusLabel = status.exists ? status.label : "missing" + guard submit.exists else { + return "submit.exists=false, progress.exists=\(progress.exists), status=\(statusLabel)" + } let tabBar = app.tabBars.firstMatch return "submit.exists=\(submit.exists), submit.enabled=\(submit.isEnabled), " + "submit.hittable=\(submit.isHittable), submit.value=\(String(describing: submit.value)), "