// // AppThemeTests.swift // Tests iOS // // App theme tests: browse themes sheet, verify all 12 theme cards exist, // and apply a theme without crashing. // TC-070 // import XCTest final class AppThemeTests: BaseUITestCase { override var seedFixture: String? { "single_mood" } override var bypassSubscription: Bool { true } /// All 12 app theme names (must match the accessibility IDs: apptheme_card_{lowercased name}). private let allThemes = [ "Zen Garden", "Synthwave", "Celestial", "Editorial", "Mixtape", "Bloom", "Heartfelt", "Minimal", "Luxe", "Forecast", "Playful", "Journal" ] /// TC-070: Open Browse Themes sheet and verify all 12 theme cards exist. func testBrowseThemes_AllCardsExist() { let tabBar = TabBarScreen(app: app) let settingsScreen = tabBar.tapSettings() settingsScreen.assertVisible() // Tap Browse Themes button let browseButton = settingsScreen.browseThemesButton XCTAssertTrue( browseButton.waitForExistence(timeout: 5), "Browse Themes button should exist" ) browseButton.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() // Wait for the themes sheet to appear // Look for any theme card as an indicator that the sheet loaded let firstCard = app.descendants(matching: .any) .matching(identifier: "apptheme_card_zen garden") .firstMatch XCTAssertTrue( firstCard.waitForExistence(timeout: 5), "Themes sheet should appear with theme cards" ) // Verify all 12 theme cards are accessible (some may require scrolling) for theme in allThemes { let card = app.descendants(matching: .any) .matching(identifier: "apptheme_card_\(theme.lowercased())") .firstMatch if !card.exists { // Scroll down to find cards that are off-screen app.swipeUp() } XCTAssertTrue( card.waitForExistence(timeout: 3), "Theme card '\(theme)' should exist in the Browse Themes sheet" ) } captureScreenshot(name: "browse_themes_all_cards") } /// TC-070: Apply a representative set of themes and verify no crash. func testApplyThemes_NoCrash() { let tabBar = TabBarScreen(app: app) let settingsScreen = tabBar.tapSettings() settingsScreen.assertVisible() // Open Browse Themes sheet let browseBtn = settingsScreen.browseThemesButton _ = browseBtn.waitForExistence(timeout: 5) browseBtn.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() // Wait for sheet to load let firstCard = app.descendants(matching: .any) .matching(identifier: "apptheme_card_zen garden") .firstMatch _ = firstCard.waitForExistence(timeout: 5) // Tap a representative sample of themes: first, middle, last let sampled = ["Zen Garden", "Heartfelt", "Journal"] for theme in sampled { let card = app.descendants(matching: .any) .matching(identifier: "apptheme_card_\(theme.lowercased())") .firstMatch if !card.exists { app.swipeUp() } if card.waitForExistence(timeout: 3) { card.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() // A preview sheet or confirmation may appear — dismiss it // Look for an "Apply" or close button and tap if present let applyButton = app.buttons["Apply"] if applyButton.waitForExistence(timeout: 2) { applyButton.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() } } } captureScreenshot(name: "themes_applied") // Dismiss the themes sheet by swiping down or tapping Done let doneButton = app.buttons["Done"] if doneButton.waitForExistence(timeout: 2) { doneButton.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() } else { // Swipe down to dismiss the sheet app.swipeDown() } // Navigate to Day tab and verify no crash — entry row should still exist tabBar.tapDay() let entryRow = app.descendants(matching: .any) .matching(NSPredicate(format: "identifier BEGINSWITH %@", "entry_row_")) .firstMatch XCTAssertTrue( entryRow.waitForExistence(timeout: 5), "Entry row should still be visible after applying themes (no crash)" ) captureScreenshot(name: "day_view_after_theme_change") } }