- Replace removePersistentDomain with key-by-key removal in resetAppState (removePersistentDomain is unreliable on app group UserDefaults suites) - Add explicit cache clearing in IAPManager.resetForTesting() to prevent stale cachedSubscriptionExpiration from restoring .subscribed state - Use descendants(matching: .any) for upgrade_banner and subscribe_button queries (VStack may not match otherElements in SwiftUI) - Add multiple swipe attempts for icon pack horizontal scroll - Use coordinate-based drag for onboarding paged TabView advancement - Add longer wait for Day view refresh after theme change - Add multiple scroll attempts to find clear data button in Settings Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
98 lines
3.5 KiB
Swift
98 lines
3.5 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.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
|
|
)
|
|
}
|
|
}
|