Files
Reflect/Tests iOS/Screens/DayScreen.swift
Trey t 224341fd98 Fix remaining 17 UI test failures: group defaults, identifiers, hittability, date format
- resetAppState: use correct suite name to clear group defaults (fixes stale subscription state)
- Reorder configureIfNeeded: set expireTrial before IAPManager init
- Add browse_themes_button identifier to CustomizeView Browse Themes button
- Add mood_button_* identifiers to Entry Detail mood grid in NoteEditorView
- Use coordinate-based tap throughout all test screens (iOS 26 Liquid Glass hittability)
- Fix HeaderMoodLogging date format: M/d/yyyy → yyyy/MM/dd to match entry_row identifiers
- AppLaunchTests: wait for isSelected state with NSPredicate instead of immediate check
- OnboardingTests: add waits between swipes and retry logic for skip button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 16:46:18 -06:00

90 lines
3.1 KiB
Swift

//
// DayScreen.swift
// Tests iOS
//
// Screen object for the Day (main) view mood logging and entry list.
//
import XCTest
struct DayScreen {
let app: XCUIApplication
// MARK: - Mood Buttons (via accessibilityIdentifier)
var greatButton: XCUIElement { app.buttons["mood_button_great"] }
var goodButton: XCUIElement { app.buttons["mood_button_good"] }
var averageButton: XCUIElement { app.buttons["mood_button_average"] }
var badButton: XCUIElement { app.buttons["mood_button_bad"] }
var horribleButton: XCUIElement { app.buttons["mood_button_horrible"] }
/// The mood header container
var moodHeader: XCUIElement { app.otherElements["mood_header"] }
// MARK: - Entry List
/// Find an entry row by its date string (format: "M/d/yyyy")
func entryRow(dateString: String) -> XCUIElement {
app.descendants(matching: .any).matching(identifier: "entry_row_\(dateString)").firstMatch
}
// MARK: - Actions
/// Tap a mood button by mood name. Waits for the celebration animation to complete.
func logMood(_ mood: MoodChoice, file: StaticString = #file, line: UInt = #line) {
let button = moodButton(for: mood)
guard button.waitForExistence(timeout: 5) else {
XCTFail("Mood button '\(mood.rawValue)' not found", file: file, line: line)
return
}
button.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap()
// Wait for the celebration animation to finish and entry to appear.
// The mood header disappears after logging today's mood.
// Give extra time for animation + data save.
_ = moodHeader.waitForDisappearance(timeout: 8)
}
// MARK: - Assertions
func assertMoodHeaderVisible(file: StaticString = #file, line: UInt = #line) {
XCTAssertTrue(
moodHeader.waitForExistence(timeout: 5),
"Mood voting header should be visible",
file: file, line: line
)
}
func assertMoodHeaderHidden(file: StaticString = #file, line: UInt = #line) {
// After logging, the header should either disappear or the buttons should not be hittable
let hidden = moodHeader.waitForDisappearance(timeout: 8)
XCTAssertTrue(hidden, "Mood header should be hidden after logging today's mood", file: file, line: line)
}
func assertEntryExists(dateString: String, file: StaticString = #file, line: UInt = #line) {
let row = entryRow(dateString: dateString)
XCTAssertTrue(
row.waitForExistence(timeout: 5),
"Entry row for \(dateString) should exist",
file: file, line: line
)
}
// MARK: - Private
private func moodButton(for mood: MoodChoice) -> XCUIElement {
switch mood {
case .great: return greatButton
case .good: return goodButton
case .average: return averageButton
case .bad: return badButton
case .horrible: return horribleButton
}
}
}
/// Represents the 5 selectable mood values for test code.
enum MoodChoice: String {
case great, good, average, bad, horrible
}