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>
This commit is contained in:
@@ -51,7 +51,8 @@ final class AppLaunchTests: BaseUITestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for a tab to become selected (iOS 26 Liquid Glass may delay state updates).
|
/// Wait for a tab to become selected (iOS 26 Liquid Glass may delay state updates).
|
||||||
private func assertTabSelected(_ tab: XCUIElement, name: String, timeout: TimeInterval = 3) {
|
private func assertTabSelected(_ tab: XCUIElement, name: String, timeout: TimeInterval = 8) {
|
||||||
|
// Re-query the element to get fresh state, since isSelected can be stale.
|
||||||
let predicate = NSPredicate(format: "isSelected == true")
|
let predicate = NSPredicate(format: "isSelected == true")
|
||||||
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: tab)
|
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: tab)
|
||||||
let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
|
let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ final class DeepLinkTests: BaseUITestCase {
|
|||||||
app.open(subscribeURL)
|
app.open(subscribeURL)
|
||||||
|
|
||||||
// Subscription view should appear as a sheet.
|
// Subscription view should appear as a sheet.
|
||||||
// Look for common subscription UI elements.
|
// Detect the SubscriptionStoreView container (works even when products are unavailable in test).
|
||||||
let subscribeText = app.staticTexts.matching(
|
let storeContainer = app.descendants(matching: .any)
|
||||||
NSPredicate(format: "label CONTAINS[c] 'subscribe' OR label CONTAINS[c] 'premium' OR label CONTAINS[c] 'upgrade' OR label CONTAINS[c] 'Reflect+'")
|
.matching(identifier: "Subscription Store View Container")
|
||||||
).firstMatch
|
.firstMatch
|
||||||
|
|
||||||
let found = subscribeText.waitForExistence(timeout: 8)
|
let found = storeContainer.waitForExistence(timeout: 8)
|
||||||
|
|
||||||
captureScreenshot(name: "deeplink_subscribe_result")
|
captureScreenshot(name: "deeplink_subscribe_result")
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ struct SettingsScreen {
|
|||||||
|
|
||||||
func assertVisible(file: StaticString = #file, line: UInt = #line) {
|
func assertVisible(file: StaticString = #file, line: UInt = #line) {
|
||||||
XCTAssertTrue(
|
XCTAssertTrue(
|
||||||
settingsHeader.waitForExistence(timeout: 5),
|
settingsHeader.waitForExistence(timeout: 8),
|
||||||
"Settings header should be visible",
|
"Settings header should be visible",
|
||||||
file: file, line: line
|
file: file, line: line
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -45,10 +45,14 @@ final class SettingsActionTests: BaseUITestCase {
|
|||||||
tabBar.tapDay()
|
tabBar.tapDay()
|
||||||
|
|
||||||
// App should remain usable after clearing data.
|
// App should remain usable after clearing data.
|
||||||
assertDayContentVisible(timeout: 10)
|
// After a full clear, Day view may show mood header, entry rows, or empty state.
|
||||||
|
let hasEntry = app.firstEntryRow.waitForExistence(timeout: 10)
|
||||||
|
let hasMoodHeader = app.element(UITestID.Day.moodHeader).waitForExistence(timeout: 2)
|
||||||
|
let hasEmptyState = app.element(UITestID.Day.emptyStateNoData).waitForExistence(timeout: 2)
|
||||||
|
XCTAssertTrue(hasEntry || hasMoodHeader || hasEmptyState,
|
||||||
|
"Day view should show entries, mood header, or empty state after clearing data")
|
||||||
|
|
||||||
// Clear action should not crash the app, even if the resulting day content
|
// Clear action should not crash the app.
|
||||||
// is rehydrated by app-specific defaults/placeholders.
|
|
||||||
XCTAssertTrue(app.tabBars.firstMatch.exists, "App should remain responsive after clearing data")
|
XCTAssertTrue(app.tabBars.firstMatch.exists, "App should remain responsive after clearing data")
|
||||||
|
|
||||||
captureScreenshot(name: "data_cleared")
|
captureScreenshot(name: "data_cleared")
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ final class StabilityTests: BaseUITestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for a tab to become selected (iOS 26 Liquid Glass may delay state updates).
|
/// Wait for a tab to become selected (iOS 26 Liquid Glass may delay state updates).
|
||||||
private func assertTabSelected(_ tab: XCUIElement, name: String, timeout: TimeInterval = 3) {
|
private func assertTabSelected(_ tab: XCUIElement, name: String, timeout: TimeInterval = 8) {
|
||||||
let predicate = NSPredicate(format: "isSelected == true")
|
let predicate = NSPredicate(format: "isSelected == true")
|
||||||
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: tab)
|
let expectation = XCTNSPredicateExpectation(predicate: predicate, object: tab)
|
||||||
let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
|
let result = XCTWaiter.wait(for: [expectation], timeout: timeout)
|
||||||
|
|||||||
Reference in New Issue
Block a user