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>
33 lines
1.9 KiB
Markdown
33 lines
1.9 KiB
Markdown
# 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 anywhere** — `app.coordinate(withNormalizedOffset:)` is banned
|
|
|
|
## Timeouts
|
|
4. **`defaultTimeout` = 2 seconds** — if an element on the current screen isn't there in 2s, the app is broken
|
|
5. **`navigationTimeout` = 5 seconds** — screen transitions, tab switches
|
|
6. **`loginTimeout` = 15 seconds** — initial auth flow only (cold start)
|
|
7. **No retry loops in test helpers** — tap once, check once, fail fast
|
|
|
|
## Independence
|
|
8. **Every suite runs alone, in combination, or in parallel** — no ordering dependencies
|
|
9. **Every test creates its own data in setUp, cleans up in tearDown**
|
|
10. **No shared mutable state** — no `static var`, no class-level properties mutated across tests
|
|
|
|
## Clarity
|
|
11. **One logical assertion per test** — test name describes the exact behavior
|
|
12. **`XCTFail` with a message that tells you what went wrong** without reading the code
|
|
13. **No `guard ... else { return }` that silently passes** — if a precondition fails, `XCTFail` and stop
|
|
|
|
## Speed
|
|
14. **No `sleep()`, `usleep()`, or `Thread.sleep`** in tests — condition-based waits only
|
|
15. **If `focusAndType` can't get focus in one tap, the test fails** — no 3-attempt retry loops
|
|
16. **Target: each individual test completes in under 15 seconds** (excluding setUp/tearDown)
|
|
|
|
## Preconditions
|
|
17. **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.
|