Fix integration tests following the search tab introduction

Tabbar tabs now can take accessibility identifiers and the integration test uses the newly expected flow.
This commit is contained in:
Stefan Ceriu
2026-10-14 09:44:53 +03:00
parent 7752ae3f6a
commit 27e59a81e4
6 changed files with 32 additions and 13 deletions
@@ -26,18 +26,20 @@ import SwiftUI
/// When `true` the tab is given the `.search` role, which on iOS 26 detaches it
/// into the trailing search button in the tab bar.
let isSearch: Bool
let accessibilityIdentifier: String?
var badgeCount = 0
/// Provide the tab's split coordinator in here to have the tab bar automatically hidden
/// when pushing a child into the split view's details on iPhone/compact iPad.
weak var navigationSplitCoordinator: NavigationSplitCoordinator?
init(tag: Tag, title: String, icon: KeyPath<CompoundIcons, Image>, selectedIcon: KeyPath<CompoundIcons, Image>, isSearch: Bool = false) {
init(tag: Tag, title: String, icon: KeyPath<CompoundIcons, Image>, selectedIcon: KeyPath<CompoundIcons, Image>, isSearch: Bool = false, accessibilityIdentifier: String? = nil) {
self.tag = tag
self.title = title
self.icon = icon
self.selectedIcon = selectedIcon
self.isSearch = isSearch
self.accessibilityIdentifier = accessibilityIdentifier
}
func barVisibility(in horizontalSizeClass: UserInterfaceSizeClass?) -> Visibility {
@@ -406,6 +408,7 @@ private struct NavigationTabCoordinatorView<Tag: Hashable>: View {
}
}
.badge(module.details.badgeCount)
.accessibilityIdentifier(module.details.accessibilityIdentifier ?? "")
}
}
.backportTabBarMinimizeBehaviorOnScrollDown()
@@ -90,13 +90,13 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
let chatsSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator(hideBrandChrome: flowParameters.userSession.userSettings.app.hideBrandChrome))
chatsTabFlowCoordinator = ChatsTabFlowCoordinator(navigationSplitCoordinator: chatsSplitCoordinator,
flowParameters: flowParameters)
chatsTabDetails = .init(tag: HomeTab.chats, title: L10n.screenHomeTabChats, icon: \.chat, selectedIcon: \.chatSolid)
chatsTabDetails = .init(tag: HomeTab.chats, title: L10n.screenHomeTabChats, icon: \.chat, selectedIcon: \.chatSolid, accessibilityIdentifier: A11yIdentifiers.homeTabs.chats)
chatsTabDetails.navigationSplitCoordinator = chatsSplitCoordinator
let spacesSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator(hideBrandChrome: flowParameters.userSession.userSettings.app.hideBrandChrome))
spacesTabFlowCoordinator = SpacesTabFlowCoordinator(navigationSplitCoordinator: spacesSplitCoordinator,
flowParameters: flowParameters)
spacesTabDetails = .init(tag: HomeTab.spaces, title: L10n.screenHomeTabSpaces, icon: \.space, selectedIcon: \.spaceSolid)
spacesTabDetails = .init(tag: HomeTab.spaces, title: L10n.screenHomeTabSpaces, icon: \.space, selectedIcon: \.spaceSolid, accessibilityIdentifier: A11yIdentifiers.homeTabs.spaces)
spacesTabDetails.navigationSplitCoordinator = spacesSplitCoordinator
if flowParameters.userSession.userSettings.app.globalSearchEnabled {
@@ -108,7 +108,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
searchScreenCoordinator = searchCoordinator
searchTabNavigationStackCoordinator = searchStackCoordinator
searchTabDetails = .init(tag: HomeTab.search, title: UntranslatedL10n.screenHomeTabSearch, icon: \.search, selectedIcon: \.search, isSearch: true)
searchTabDetails = .init(tag: HomeTab.search, title: UntranslatedL10n.screenHomeTabSearch, icon: \.search, selectedIcon: \.search, isSearch: true, accessibilityIdentifier: A11yIdentifiers.homeTabs.search)
} else {
searchScreenCoordinator = nil
searchTabNavigationStackCoordinator = nil
@@ -20,6 +20,7 @@ enum A11yIdentifiers {
static let encryptionResetScreen = EncryptionResetScreen()
static let encryptionResetPasswordScreen = EncryptionResetPasswordScreen()
static let homeScreen = HomeScreen()
static let homeTabs = HomeTabs()
static let loginScreen = LoginScreen()
static let authenticationStartScreen = AuthenticationStartScreen()
static let reportContent = ReportContent()
@@ -48,6 +49,7 @@ enum A11yIdentifiers {
static let spacesScreen = SpacesScreen()
static let spaceScreen = SpaceScreen()
static let spaceAddRoomsScreen = SpaceAddRoomsScreen()
static let searchScreen = SearchScreen()
static let spaceSettingsScreen = SpaceSettingsScreen()
static let linkNewDeviceScreen = LinkNewDeviceScreen()
@@ -120,6 +122,12 @@ enum A11yIdentifiers {
}
}
struct HomeTabs {
let chats = "home_tabs-chats"
let spaces = "home_tabs-spaces"
let search = "home_tabs-search"
}
struct InviteUsersScreen {
let proceed = "invite_users-proceed"
let userProfile = "invite_users-user_profile"
@@ -353,6 +361,13 @@ enum A11yIdentifiers {
let cancel = "space_add_rooms_screen-cancel"
}
struct SearchScreen {
let roomNamePrefix = "search_screen-room_name"
func roomName(_ name: String) -> String {
"\(roomNamePrefix):\(name)"
}
}
struct SpaceSettingsScreen {
let editBaseInfo = "space_settings_screen-edit_space_info"
}
@@ -283,7 +283,7 @@ struct SearchScreen: View {
private extension View {
/// Searchable makes the preview contents randomly appear lower
@ViewBuilder func conditionalSearchable(searchQuery: Binding<String>) -> some View {
if !ProcessInfo.isXcodePreview, !ProcessInfo.isRunningTests {
if !ProcessInfo.isXcodePreview, !ProcessInfo.isRunningTests || ProcessInfo.isRunningIntegrationTests {
searchable(text: searchQuery, placement: .toolbarPrincipal)
} else {
self
@@ -334,6 +334,7 @@ private struct SearchScreenRoomCell: View {
.padding(.vertical, 12)
}
.buttonStyle(SearchScreenRoomCellButtonStyle(isSelected: isSelected))
.accessibilityIdentifier(A11yIdentifiers.searchScreen.roomName(room.title))
.listRowInsets(.init())
.listRowSeparator(.hidden)
.rowDivider()
+7 -7
View File
@@ -31,12 +31,17 @@ class UserFlowTests: XCTestCase {
/// Assumes app is on the home screen
private func checkRoomFlows() {
// Search for the special test room
let searchField = app.searchFields.firstMatch
let searchTab = app.buttons[A11yIdentifiers.homeTabs.search].firstMatch
XCTAssertTrue(searchTab.waitForExistence(timeout: 30))
searchTab.tap(.center)
// The search tab hosts its field in the tab bar, which exposes it as a text field.
let searchField = app.textFields.firstMatch
XCTAssertTrue(searchField.waitForExistence(timeout: 30))
searchField.clearAndTypeText(Self.integrationTestsRoomName, app: app)
// And open it
let firstRoom = app.buttons.matching(NSPredicate(format: "identifier CONTAINS %@", Self.integrationTestsRoomName)).firstMatch
let firstRoom = app.buttons[A11yIdentifiers.searchScreen.roomName(Self.integrationTestsRoomName)].firstMatch
// The backend is sometimes really slow and having a longer timeout
// beats having to rerun the whole suite again.
@@ -50,11 +55,6 @@ class UserFlowTests: XCTestCase {
// Go back to the room list
tapOnBackButton("Chats")
// Cancel initial the room search
let searchCancelButton = app.buttons["Close"].firstMatch
XCTAssertTrue(searchCancelButton.waitForExistence(timeout: 10.0))
searchCancelButton.tap(.center)
}
private func sendMessages() {
+1 -1
View File
@@ -197,7 +197,7 @@ class UserSessionScreenTests: XCTestCase {
try await app.assertScreenshot(step: Step.homeScreenWithTabBar)
// app.tabBars doesn't work on iPadOS 18 😐
app.buttons["Spaces"].firstMatch.tap(.center)
app.buttons[A11yIdentifiers.homeTabs.spaces].firstMatch.tap(.center)
try await app.assertScreenshot(step: Step.spacesScreen)