Add XCUITest authoring docs and reusable prompt template

This commit is contained in:
Trey t
2026-02-18 09:00:28 -06:00
parent 56ac783219
commit b58dfd5093
6 changed files with 262 additions and 29 deletions

View File

@@ -250,46 +250,51 @@ DataController.shared.add(mood: .good, forDate: date, entryType: .listView)
- **Test directory**: `Tests iOS/` (iOS), `Tests macOS/` (macOS — template only)
- **File naming**: `{SuiteName}Tests.swift`
### Existing Test Suites
### UI Test Architecture (XCUITest)
| Suite | Test Count | Covers |
|-------|-----------|--------|
| `Tests_iOS` | 2 | `Date.dates(from:toDate:)` utility — basic date range generation |
| `Tests_iOSLaunchTests` | 1 | Default launch test (template) |
For any task that adds/updates UI tests, read:
**Note**: Test coverage is minimal. Most of the app is untested. Priority areas for new tests: `DataController` CRUD operations, `MoodLogger` side effects, `IAPManager` subscription state transitions, `MoodEntryModel` initialization edge cases.
- `/Users/treyt/Desktop/code/Feels/docs/XCUITest-Authoring.md`
### Naming Convention
Use this foundation:
```
test{Component}_{Behavior}
- Base class: `/Users/treyt/Desktop/code/Feels/Tests iOS/Helpers/BaseUITestCase.swift`
- Wait + ID helpers: `/Users/treyt/Desktop/code/Feels/Tests iOS/Helpers/WaitHelpers.swift`
- Screen objects: `/Users/treyt/Desktop/code/Feels/Tests iOS/Screens/`
- Accessibility IDs: `/Users/treyt/Desktop/code/Feels/Shared/AccessibilityIdentifiers.swift`
- Test-mode fixtures: `/Users/treyt/Desktop/code/Feels/Shared/UITestMode.swift`
Mandatory UI test rules:
- Inherit from `BaseUITestCase`
- Use identifier-first selectors (`UITestID` / accessibility IDs)
- Use wait helpers and screen objects
- No `sleep(...)`
- No raw localized text selectors as primary locators
- Prefer one behavior per test method (`test<Feature>_<Behavior>`)
### UI Test Execution Commands
```bash
# Run one suite
xcodebuild -project Feels.xcodeproj -scheme "Feels (iOS)" -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:"Tests iOS/<SuiteName>" test
# Run all iOS UI tests
xcodebuild -project Feels.xcodeproj -scheme "Feels (iOS)" -destination 'platform=iOS Simulator,name=iPhone 16 Pro' -only-testing:"Tests iOS" test
```
Example: `testDatesBetween`, `testDatesIncluding`
### Unit Test Guidance
### Mocking Strategy
- **SwiftData**: Use `ModelContainer` with `isStoredInMemoryOnly: true` for test isolation
- **DataController**: The `DataControllerProtocol.swift` defines `MoodDataReading`, `MoodDataWriting`, `MoodDataDeleting`, `MoodDataPersisting` protocols — use these for protocol-based mocking
- **Analytics**: No mock needed — `AnalyticsManager` can be stubbed or ignored in tests
- **HealthKit**: Mock `HKHealthStore` or skip — not critical for unit tests
- **StoreKit**: Use StoreKit Testing in Xcode for `IAPManager` tests
Example:
```swift
// Test setup with in-memory SwiftData
let schema = Schema([MoodEntryModel.self])
let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)
let container = try ModelContainer(for: schema, configurations: [config])
let context = container.mainContext
```
- Use in-memory `ModelContainer` (`isStoredInMemoryOnly: true`) for SwiftData isolation.
- Prefer protocol-based seams from `DataControllerProtocol.swift` when mocking data access.
- StoreKit flows should use StoreKit Testing config where needed.
### Bug Fix Protocol
When fixing a bug:
1. Write a regression test that reproduces the bug BEFORE fixing it
2. Include edge cases — test boundary conditions, nil/empty inputs, related scenarios
3. Confirm all tests pass after the fix
1. Reproduce with a failing test first when practical.
2. Add edge-case assertions for related boundaries.
3. Confirm targeted tests pass; run broader suite if behavior changed outside one area.
4. Name tests descriptively: `test{Component}_{WhatWasBroken}`
## Known Edge Cases & Gotchas