Files
Reflect/Tests iOS/Screens/SettingsScreen.swift
Trey t 16c5c34942 Fix 4 flaky UI tests for iOS 26 compatibility
- 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>
2026-02-26 18:59:22 -06:00

100 lines
3.3 KiB
Swift

//
// 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.element(UITestID.Settings.header) }
var customizeSegment: XCUIElement { app.element(UITestID.Settings.customizeTab) }
var settingsSegment: XCUIElement { app.element(UITestID.Settings.settingsTab) }
var upgradeBanner: XCUIElement {
app.element(UITestID.Settings.upgradeBanner)
}
var subscribeButton: XCUIElement {
app.element(UITestID.Settings.subscribeButton)
}
var whyUpgradeButton: XCUIElement { app.element(UITestID.Settings.whyUpgradeButton) }
var browseThemesButton: XCUIElement { app.element(UITestID.Settings.browseThemesButton) }
var clearDataButton: XCUIElement { app.element(UITestID.Settings.clearDataButton) }
var analyticsToggle: XCUIElement { app.element(UITestID.Settings.analyticsToggle) }
var showOnboardingButton: XCUIElement { app.buttons["settings_show_onboarding"] }
// MARK: - Actions
func tapCustomizeTab() {
tapSegment(identifier: UITestID.Settings.customizeTab, fallbackLabel: "Customize")
}
func tapSettingsTab() {
tapSegment(identifier: UITestID.Settings.settingsTab, fallbackLabel: "Settings")
}
func tapClearData() {
let button = clearDataButton
_ = app.swipeUntilExists(button, direction: .up, maxSwipes: 6)
button.tapWhenReady(timeout: 5)
}
func tapAnalyticsToggle() {
let toggle = analyticsToggle
_ = app.swipeUntilExists(toggle, direction: .up, maxSwipes: 6)
toggle.tapWhenReady(timeout: 5)
}
// MARK: - Assertions
func assertVisible(file: StaticString = #file, line: UInt = #line) {
XCTAssertTrue(
settingsHeader.waitForExistence(timeout: 8),
"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
)
}
// MARK: - Private
private func tapSegment(identifier: String, fallbackLabel: String) {
let byID = app.element(identifier)
if byID.waitForExistence(timeout: 2) {
byID.tapWhenReady()
return
}
let segmentedButton = app.segmentedControls.buttons[fallbackLabel]
if segmentedButton.waitForExistence(timeout: 2) {
segmentedButton.tapWhenReady()
return
}
let candidates = app.buttons.matching(NSPredicate(format: "label == %@", fallbackLabel)).allElementsBoundByIndex
let tabBarButton = app.tabBars.buttons[fallbackLabel]
if let nonTabButton = candidates.first(where: { $0.frame != tabBarButton.frame }) {
nonTabButton.tapWhenReady()
}
}
}