Fix 23 failing UI tests: accessibility hierarchy, test mode, and interaction issues

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>
This commit is contained in:
Trey t
2026-02-17 16:14:16 -06:00
parent 79a16fb476
commit 44b46f88e2
5 changed files with 50 additions and 25 deletions

View File

@@ -18,9 +18,9 @@ struct EntryDetailScreen {
var moodGrid: XCUIElement { app.otherElements["entry_detail_mood_grid"] }
/// Mood buttons inside the detail sheet's mood grid.
/// These use accessibilityLabel (the mood name text), not identifiers.
func moodButton(label: String) -> XCUIElement {
app.buttons.matching(NSPredicate(format: "label CONTAINS[cd] %@", label)).firstMatch
/// Match by the mood_button_ identifier prefix to avoid matching entry rows.
func moodButton(for mood: MoodChoice) -> XCUIElement {
app.buttons["mood_button_\(mood.rawValue)"]
}
// MARK: - Actions
@@ -30,7 +30,7 @@ struct EntryDetailScreen {
}
func selectMood(_ mood: MoodChoice) {
let button = moodButton(label: mood.rawValue.capitalized)
let button = moodButton(for: mood)
button.tapWhenReady()
}

View File

@@ -14,7 +14,6 @@ struct SettingsScreen {
var settingsHeader: XCUIElement { app.staticTexts["settings_header"] }
var customizeSegment: XCUIElement { app.buttons["Customize"] }
var settingsSegment: XCUIElement { app.buttons["Settings"] }
var upgradeBanner: XCUIElement { app.otherElements["upgrade_banner"] }
var subscribeButton: XCUIElement { app.buttons["subscribe_button"] }
var whyUpgradeButton: XCUIElement { app.buttons["why_upgrade_button"] }
@@ -26,24 +25,44 @@ struct SettingsScreen {
// MARK: - Actions
func tapCustomizeTab() {
customizeSegment.tapWhenReady()
let segment = customizeSegment
_ = segment.waitForExistence(timeout: 5)
segment.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
}
func tapSettingsTab() {
settingsSegment.tapWhenReady()
// Find the "Settings" segment in the segmented control (not the tab bar button).
// Try segmentedControls first, then fall back to finding by exclusion.
let segCtrl = app.segmentedControls.buttons["Settings"]
if segCtrl.waitForExistence(timeout: 3) {
segCtrl.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
return
}
// Fallback: find a "Settings" button that is NOT the tab bar button
let candidates = app.buttons.matching(NSPredicate(format: "label == 'Settings'")).allElementsBoundByIndex
let tabBarBtn = app.tabBars.buttons["Settings"]
for candidate in candidates where candidate.frame != tabBarBtn.frame {
candidate.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
return
}
}
func tapClearData() {
clearDataButton.tapWhenReady()
let button = clearDataButton
if button.exists && !button.isHittable {
app.swipeUp()
}
_ = button.waitForExistence(timeout: 5)
button.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
}
func tapAnalyticsToggle() {
// Scroll down to find the toggle if needed
let toggle = app.descendants(matching: .any).matching(identifier: "settings_analytics_toggle").firstMatch
if !toggle.isHittable {
let toggle = analyticsToggle
if toggle.exists && !toggle.isHittable {
app.swipeUp()
}
toggle.tapWhenReady()
_ = toggle.waitForExistence(timeout: 5)
toggle.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
}
// MARK: - Assertions

View File

@@ -22,31 +22,31 @@ struct TabBarScreen {
@discardableResult
func tapDay() -> DayScreen {
dayTab.tapWhenReady()
tapTab(dayTab)
return DayScreen(app: app)
}
@discardableResult
func tapMonth() -> TabBarScreen {
monthTab.tapWhenReady()
tapTab(monthTab)
return self
}
@discardableResult
func tapYear() -> TabBarScreen {
yearTab.tapWhenReady()
tapTab(yearTab)
return self
}
@discardableResult
func tapInsights() -> TabBarScreen {
insightsTab.tapWhenReady()
tapTab(insightsTab)
return self
}
@discardableResult
func tapSettings() -> SettingsScreen {
settingsTab.tapWhenReady()
tapTab(settingsTab)
return SettingsScreen(app: app)
}
@@ -59,4 +59,13 @@ struct TabBarScreen {
func assertTabBarVisible() {
XCTAssertTrue(dayTab.waitForExistence(timeout: 5), "Tab bar should be visible")
}
// MARK: - Private
/// Tap a tab bar button. Uses coordinate tap to avoid iOS 26 Liquid Glass
/// overlay elements reporting buttons as not hittable.
private func tapTab(_ tab: XCUIElement) {
_ = tab.waitForExistence(timeout: 5)
tab.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
}
}