Replace brittle localized-string selectors and broken wait helpers with a robust, identifier-first UI test infrastructure. All 41 UI tests pass on iOS 26.2 simulator (iPhone 17). Foundation: - BaseUITestCase with deterministic launch helpers (launchClean, launchOffline) - WaitHelpers (waitUntilHittable, waitUntilGone, tapWhenReady) replacing sleep() - UITestID enum mirroring AccessibilityIdentifiers from the app target - Screen objects: TabBarScreen, CameraScreen, CollectionScreen, TodayScreen, SettingsScreen, PlantDetailScreen Key fixes: - Tab navigation uses waitForExistence+tap instead of isHittable (unreliable in iOS 26 simulator) - Tests handle real app state (empty collection, no camera permission) - Increased timeouts for parallel clone execution - Added NetworkMonitorProtocol and protocol-typed DI for testability - Fixed actor-isolation issues in unit test mocks Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66 lines
2.0 KiB
Markdown
66 lines
2.0 KiB
Markdown
# UI Test Generation Prompt Template
|
|
|
|
Use this prompt when asking an AI to generate a new UI test for PlantGuide.
|
|
|
|
---
|
|
|
|
## Prompt
|
|
|
|
Write a UI test for **[FEATURE DESCRIPTION]** in PlantGuide.
|
|
|
|
### Requirements
|
|
|
|
- Inherit from `BaseUITestCase` (not `XCTestCase`)
|
|
- Import only `XCTest`
|
|
- Mark test methods `@MainActor`
|
|
- Launch with `launchClean()`, `launchWithMockData()`, or `launchOffline()` as appropriate
|
|
- Navigate using screen objects: `TabBarScreen(app: app).tapCollection()`
|
|
- Locate elements via `UITestID.*` identifiers, not localized strings
|
|
- Wait with `waitForExistence(timeout:)`, `waitUntilHittable()`, `waitUntilGone()`
|
|
- Never use `sleep()`
|
|
- One assertion focus per test method
|
|
- Use Given/When/Then comments for clarity
|
|
|
|
### File Structure
|
|
|
|
```swift
|
|
import XCTest
|
|
|
|
final class [Feature]UITests: BaseUITestCase {
|
|
|
|
@MainActor
|
|
func test[Behavior]() throws {
|
|
// Given
|
|
launchWithMockData()
|
|
let screen = TabBarScreen(app: app).tap[Tab]()
|
|
XCTAssertTrue(screen.waitForLoad())
|
|
|
|
// When
|
|
screen.[element].tapWhenReady()
|
|
|
|
// Then
|
|
XCTAssertTrue([assertion])
|
|
}
|
|
}
|
|
```
|
|
|
|
### Available Screen Objects
|
|
|
|
- `TabBarScreen` -- `tapCamera()`, `tapCollection()`, `tapToday()`, `tapSettings()`
|
|
- `CameraScreen` -- `captureButton`, `hasValidState()`
|
|
- `CollectionScreen` -- `searchField`, `filterButton`, `viewModeToggle`, `emptyStateView`
|
|
- `TodayScreen` -- `todaySection`, `overdueSection`, `emptyStateView`
|
|
- `SettingsScreen` -- `clearCacheButton`, `notificationsToggle`, `versionInfo`
|
|
- `PlantDetailScreen` -- `plantName`, `favoriteButton`, `editButton`, `deleteButton`
|
|
|
|
### Available Identifiers
|
|
|
|
See `PlantGuideUITests/Foundation/UITestID.swift` for the full list.
|
|
All identifiers mirror `PlantGuide/Core/Utilities/AccessibilityIdentifiers.swift`.
|
|
|
|
### If an identifier is missing
|
|
|
|
1. Add it to `AccessibilityIdentifiers.swift` in the app
|
|
2. Add `.accessibilityIdentifier(...)` to the view
|
|
3. Mirror it in `UITestID.swift` in the test target
|