Stabilize UI test suite — 39% → 98%+ pass rate

Fix root causes uncovered across repeated parallel runs:

- Admin seed password "test1234" failed backend complexity (needs
  uppercase). Bumped to "Test1234" across every hard-coded reference
  (AuthenticatedUITestCase default, TestAccountManager seeded-login
  default, Tests/*Integration suites, Tests/DataLayer, OnboardingTests).

- dismissKeyboard() tapped the Return key first, which races SwiftUI's
  TextField binding on numeric keyboards (postal, year built) and
  complex forms. KeyboardDismisser now prefers the keyboard-toolbar
  Done button, falls back to tap-above-keyboard, then keyboard Return.
  BaseUITestCase.clearAndEnterText uses the same helper.

- Form page-object save() helpers (task / residence / contractor /
  document) now dismiss the keyboard and scroll the submit button
  into view before tapping, eliminating Suite4/6/7/8 "save button
  stayed visible" timeouts.

- Suite6 createTask was producing a disabled-save race: under
  parallel contention the SwiftUI title binding lagged behind
  XCUITest typing. Rewritten to inline Suite5's proven pattern with
  a retry that nudges the title binding via a no-op edit when Add is
  disabled, and an explicit refreshTasks after creation.

- Suite8 selectProperty now picks the residence by name (works with
  menu, list, or wheel picker variants) — avoids bad form-cell taps
  when the picker hasn't fully rendered.

- run_ui_tests.sh uses 2 workers instead of 4 (4-worker contention
  caused XCUITest typing races across Suite5/7/8) and isolates Suite6
  in its own 2-worker phase after the main parallel phase.

- Add AAA_SeedTests / SuiteZZ_CleanupTests: the runner's Phase 1
  (seed) and Phase 3 (cleanup) depend on these and they were missing
  from version control.
This commit is contained in:
Trey T
2026-04-15 08:38:31 -05:00
parent 9ececfa48a
commit a4d66c6ed1
17 changed files with 388 additions and 59 deletions

View File

@@ -113,6 +113,9 @@ struct TaskFormScreen {
}
func save() {
KeyboardDismisser.dismiss(app: app)
// Scroll the form so any focused-field state commits before the
// submit action reads it. Without this the title binding can lag.
app.swipeUp()
saveButton.waitForExistenceOrFail(timeout: 10)
saveButton.forceTap()
@@ -232,7 +235,8 @@ struct ContractorFormScreen {
}
func save() {
app.swipeUp()
KeyboardDismisser.dismiss(app: app)
if !saveButton.exists || !saveButton.isHittable { app.swipeUp() }
saveButton.waitForExistenceOrFail(timeout: 10)
saveButton.forceTap()
_ = saveButton.waitForNonExistence(timeout: 15)
@@ -399,13 +403,10 @@ struct DocumentFormScreen {
}
func save() {
// Dismiss keyboard first
app.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.15)).tap()
_ = app.keyboards.firstMatch.waitForNonExistence(timeout: 3)
if !saveButton.exists || !saveButton.isHittable {
app.swipeUp()
}
KeyboardDismisser.dismiss(app: app)
// Unconditional swipe-up matches the task form fix forces SwiftUI
// state to commit before the submit button reads it.
app.swipeUp()
saveButton.waitForExistenceOrFail(timeout: 10)
if saveButton.isHittable {
saveButton.tap()