Files
PlantGuide/Docs/uiTestPrompt.md
Trey t 1ae9c884c8 Rebuild UI test foundation with page objects, wait helpers, and screen objects
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>
2026-02-18 10:36:54 -06:00

2.0 KiB

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

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