Add XCUITest authoring docs and reusable prompt template
This commit is contained in:
63
CLAUDE.md
63
CLAUDE.md
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user