Files
honeyDueKMP/iosApp/HoneyDueUITests/TEST_RULES.md
Trey T 4df8707b92 UI test infrastructure overhaul — 58% to 96% pass rate (231/241)
Major infrastructure changes:
- BaseUITestCase: per-suite app termination via class setUp() prevents
  stale state when parallel clones share simulators
- relaunchBetweenTests override for suites that modify login/onboarding state
- focusAndType: dedicated SecureTextField path handles iOS strong password
  autofill suggestions (Choose My Own Password / Not Now dialogs)
- LoginScreenObject: tapSignUp/tapForgotPassword use scrollIntoView for
  offscreen buttons instead of simple swipeUp
- Removed all coordinate taps from ForgotPasswordScreen, VerifyResetCodeScreen,
  ResetPasswordScreen (Rule 3 compliance)
- Removed all usleep calls from screen objects (Rule 14 compliance)

App fixes exposed by tests:
- ContractorsListView: added onDismiss to sheet for list refresh after save
- AllTasksView: added Task.RefreshButton accessibility identifier
- AccessibilityIdentifiers: added Task.refreshButton
- DocumentsWarrantiesView: onDismiss handler for document list refresh
- Various form views: textContentType, submitLabel, onSubmit for keyboard flow

Test fixes:
- PasswordResetTests: handle auto-login after reset (app skips success screen)
- AuthenticatedUITestCase: refreshTasks() helper for kanban toolbar button
- All pre-login suites use relaunchBetweenTests for test independence
- Deleted dead code: AuthenticatedTestCase, SeededTestData, SeedTests,
  CleanupTests, old Suite0/2/3, Suite1_RegistrationRebuildTests

10 remaining failures: 5 iOS strong password autofill (simulator env),
3 pull-to-refresh gesture on empty lists, 2 feature coverage edge cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:05:37 -05:00

1.9 KiB

UI Test Rules

These rules are non-negotiable. Every test, every suite, every helper must follow them.

Element Interaction

  1. All text fields use fillTextField(identifier:) — never raw tap() + typeText() in test bodies
  2. All buttons/elements found by accessibility identifier — never label CONTAINS for app elements
  3. No coordinate taps anywhereapp.coordinate(withNormalizedOffset:) is banned

Timeouts

  1. defaultTimeout = 2 seconds — if an element on the current screen isn't there in 2s, the app is broken
  2. navigationTimeout = 5 seconds — screen transitions, tab switches
  3. loginTimeout = 15 seconds — initial auth flow only (cold start)
  4. No retry loops in test helpers — tap once, check once, fail fast

Independence

  1. Every suite runs alone, in combination, or in parallel — no ordering dependencies
  2. Every test creates its own data in setUp, cleans up in tearDown
  3. No shared mutable state — no static var, no class-level properties mutated across tests

Clarity

  1. One logical assertion per test — test name describes the exact behavior
  2. XCTFail with a message that tells you what went wrong without reading the code
  3. No guard ... else { return } that silently passes — if a precondition fails, XCTFail and stop

Speed

  1. No sleep(), usleep(), or Thread.sleep in tests — condition-based waits only
  2. If focusAndType can't get focus in one tap, the test fails — no 3-attempt retry loops
  3. Target: each individual test completes in under 15 seconds (excluding setUp/tearDown)

Preconditions

  1. Every test assumption is validated before the test runs — if a task test assumes a residence exists, verify via API in setUp. If the precondition isn't met, create it via API. Preconditions are NOT what the test is testing — they're infrastructure. Use API, not UI, to establish them.