// // SettingsScreen.swift // Tests iOS // // Screen object for the Settings tab (Customize + Settings sub-tabs). // import XCTest struct SettingsScreen { let app: XCUIApplication // MARK: - Elements var settingsHeader: XCUIElement { app.staticTexts["settings_header"] } var customizeSegment: XCUIElement { app.buttons["Customize"] } var upgradeBanner: XCUIElement { app.descendants(matching: .any).matching(identifier: "upgrade_banner").firstMatch } var subscribeButton: XCUIElement { app.descendants(matching: .any).matching(identifier: "subscribe_button").firstMatch } var whyUpgradeButton: XCUIElement { app.buttons["why_upgrade_button"] } var browseThemesButton: XCUIElement { app.buttons["browse_themes_button"] } var clearDataButton: XCUIElement { app.buttons["settings_clear_data"].firstMatch } var analyticsToggle: XCUIElement { app.descendants(matching: .any).matching(identifier: "settings_analytics_toggle").firstMatch } var showOnboardingButton: XCUIElement { app.buttons["settings_show_onboarding"].firstMatch } // MARK: - Actions func tapCustomizeTab() { let segment = customizeSegment _ = segment.waitForExistence(timeout: 5) segment.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() } func tapSettingsTab() { // 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() { 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() { let toggle = analyticsToggle if toggle.exists && !toggle.isHittable { app.swipeUp() } _ = toggle.waitForExistence(timeout: 5) toggle.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() } // MARK: - Assertions func assertVisible(file: StaticString = #file, line: UInt = #line) { XCTAssertTrue( settingsHeader.waitForExistence(timeout: 5), "Settings header should be visible", file: file, line: line ) } func assertUpgradeBannerVisible(file: StaticString = #file, line: UInt = #line) { XCTAssertTrue( upgradeBanner.waitForExistence(timeout: 5), "Upgrade banner should be visible", file: file, line: line ) } func assertUpgradeBannerHidden(file: StaticString = #file, line: UInt = #line) { XCTAssertTrue( upgradeBanner.waitForDisappearance(timeout: 5), "Upgrade banner should be hidden (subscribed)", file: file, line: line ) } }