Rewrote 60+ test files to follow honeydue-style test guidelines:
- defaultTimeout=2s, navigationTimeout=5s — fail fast, no long waits
- No coordinate taps (except onboarding paged TabView swipes)
- No sleep(), no retry loops
- No guard...else { return } silent passes — XCTFail everywhere
- All elements by accessibility ID via UITestID constants
- Screen objects for all navigation/actions/assertions
- One logical assertion per test method
Added missing accessibility identifiers to app views:
- MonthView.swift: added AccessibilityID.MonthView.grid to ScrollView
- YearView.swift: added AccessibilityID.YearView.heatmap to ScrollView
Framework rewrites:
- BaseUITestCase: added session ID, localeArguments, extraLaunchArguments
- WaitHelpers: waitForExistenceOrFail, waitUntilHittableOrFail,
waitForNonExistence, scrollIntoView, forceTap
- All 7 screen objects rewritten with fail-fast semantics
- TEST_RULES.md added with non-negotiable rules
Known remaining issues:
- OnboardingTests: paged TabView swipes unreliable on iOS 26 simulator
- SettingsLegalLinksTests: EULA/Privacy buttons too deep in DEBUG scroll
- Customization horizontal picker scrolling needs further tuning
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- AppLaunchTests/StabilityTests: Increase assertTabSelected timeout to
8s for iOS 26 Liquid Glass delayed isSelected state updates
- DeepLinkTests: Detect SubscriptionStoreView container instead of text
labels, since Apple's native view shows "Subscription Unavailable" in
test storefront
- SettingsActionTests: Check for empty state after clearing data, bump
Settings header timeout to 8s
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace removePersistentDomain with key-by-key removal in resetAppState
(removePersistentDomain is unreliable on app group UserDefaults suites)
- Add explicit cache clearing in IAPManager.resetForTesting() to prevent
stale cachedSubscriptionExpiration from restoring .subscribed state
- Use descendants(matching: .any) for upgrade_banner and subscribe_button
queries (VStack may not match otherElements in SwiftUI)
- Add multiple swipe attempts for icon pack horizontal scroll
- Use coordinate-based drag for onboarding paged TabView advancement
- Add longer wait for Day view refresh after theme change
- Add multiple scroll attempts to find clear data button in Settings
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
App fixes:
- Remove empty_state identifier from EmptyHomeView VStack (was overriding mood_header)
- Fix resetAppState to set needsOnboarding=true (fresh state) instead of false
- Set bypassSubscription explicitly based on launch arg presence (was defaulting to true in DEBUG)
Test fixes:
- TabBarScreen: use coordinate tap to avoid iOS 26 Liquid Glass hittability issues
- SettingsScreen: use coordinate tap for segments, handle Settings label ambiguity with tab bar
- EntryDetailScreen: use mood_button_ identifiers instead of label matching (was matching entry rows)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The screens/ gitignore rule was matching Tests iOS/Screens/ on
case-insensitive macOS. Anchored to /screens/ (repo root only) so
the 7 UI test page object files are no longer ignored.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>