mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-10-31 16:24:11 +00:00
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:
@@ -26,18 +26,20 @@ import SwiftUI
|
|||||||
/// When `true` the tab is given the `.search` role, which on iOS 26 detaches it
|
/// When `true` the tab is given the `.search` role, which on iOS 26 detaches it
|
||||||
/// into the trailing search button in the tab bar.
|
/// into the trailing search button in the tab bar.
|
||||||
let isSearch: Bool
|
let isSearch: Bool
|
||||||
|
let accessibilityIdentifier: String?
|
||||||
var badgeCount = 0
|
var badgeCount = 0
|
||||||
|
|
||||||
/// Provide the tab's split coordinator in here to have the tab bar automatically hidden
|
/// 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.
|
/// when pushing a child into the split view's details on iPhone/compact iPad.
|
||||||
weak var navigationSplitCoordinator: NavigationSplitCoordinator?
|
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.tag = tag
|
||||||
self.title = title
|
self.title = title
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.selectedIcon = selectedIcon
|
self.selectedIcon = selectedIcon
|
||||||
self.isSearch = isSearch
|
self.isSearch = isSearch
|
||||||
|
self.accessibilityIdentifier = accessibilityIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
func barVisibility(in horizontalSizeClass: UserInterfaceSizeClass?) -> Visibility {
|
func barVisibility(in horizontalSizeClass: UserInterfaceSizeClass?) -> Visibility {
|
||||||
@@ -406,6 +408,7 @@ private struct NavigationTabCoordinatorView<Tag: Hashable>: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.badge(module.details.badgeCount)
|
.badge(module.details.badgeCount)
|
||||||
|
.accessibilityIdentifier(module.details.accessibilityIdentifier ?? "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.backportTabBarMinimizeBehaviorOnScrollDown()
|
.backportTabBarMinimizeBehaviorOnScrollDown()
|
||||||
|
|||||||
@@ -90,13 +90,13 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
let chatsSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator(hideBrandChrome: flowParameters.userSession.userSettings.app.hideBrandChrome))
|
let chatsSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator(hideBrandChrome: flowParameters.userSession.userSettings.app.hideBrandChrome))
|
||||||
chatsTabFlowCoordinator = ChatsTabFlowCoordinator(navigationSplitCoordinator: chatsSplitCoordinator,
|
chatsTabFlowCoordinator = ChatsTabFlowCoordinator(navigationSplitCoordinator: chatsSplitCoordinator,
|
||||||
flowParameters: flowParameters)
|
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
|
chatsTabDetails.navigationSplitCoordinator = chatsSplitCoordinator
|
||||||
|
|
||||||
let spacesSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator(hideBrandChrome: flowParameters.userSession.userSettings.app.hideBrandChrome))
|
let spacesSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: PlaceholderScreenCoordinator(hideBrandChrome: flowParameters.userSession.userSettings.app.hideBrandChrome))
|
||||||
spacesTabFlowCoordinator = SpacesTabFlowCoordinator(navigationSplitCoordinator: spacesSplitCoordinator,
|
spacesTabFlowCoordinator = SpacesTabFlowCoordinator(navigationSplitCoordinator: spacesSplitCoordinator,
|
||||||
flowParameters: flowParameters)
|
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
|
spacesTabDetails.navigationSplitCoordinator = spacesSplitCoordinator
|
||||||
|
|
||||||
if flowParameters.userSession.userSettings.app.globalSearchEnabled {
|
if flowParameters.userSession.userSettings.app.globalSearchEnabled {
|
||||||
@@ -108,7 +108,7 @@ class UserSessionFlowCoordinator: FlowCoordinatorProtocol {
|
|||||||
|
|
||||||
searchScreenCoordinator = searchCoordinator
|
searchScreenCoordinator = searchCoordinator
|
||||||
searchTabNavigationStackCoordinator = searchStackCoordinator
|
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 {
|
} else {
|
||||||
searchScreenCoordinator = nil
|
searchScreenCoordinator = nil
|
||||||
searchTabNavigationStackCoordinator = nil
|
searchTabNavigationStackCoordinator = nil
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ enum A11yIdentifiers {
|
|||||||
static let encryptionResetScreen = EncryptionResetScreen()
|
static let encryptionResetScreen = EncryptionResetScreen()
|
||||||
static let encryptionResetPasswordScreen = EncryptionResetPasswordScreen()
|
static let encryptionResetPasswordScreen = EncryptionResetPasswordScreen()
|
||||||
static let homeScreen = HomeScreen()
|
static let homeScreen = HomeScreen()
|
||||||
|
static let homeTabs = HomeTabs()
|
||||||
static let loginScreen = LoginScreen()
|
static let loginScreen = LoginScreen()
|
||||||
static let authenticationStartScreen = AuthenticationStartScreen()
|
static let authenticationStartScreen = AuthenticationStartScreen()
|
||||||
static let reportContent = ReportContent()
|
static let reportContent = ReportContent()
|
||||||
@@ -48,6 +49,7 @@ enum A11yIdentifiers {
|
|||||||
static let spacesScreen = SpacesScreen()
|
static let spacesScreen = SpacesScreen()
|
||||||
static let spaceScreen = SpaceScreen()
|
static let spaceScreen = SpaceScreen()
|
||||||
static let spaceAddRoomsScreen = SpaceAddRoomsScreen()
|
static let spaceAddRoomsScreen = SpaceAddRoomsScreen()
|
||||||
|
static let searchScreen = SearchScreen()
|
||||||
static let spaceSettingsScreen = SpaceSettingsScreen()
|
static let spaceSettingsScreen = SpaceSettingsScreen()
|
||||||
static let linkNewDeviceScreen = LinkNewDeviceScreen()
|
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 {
|
struct InviteUsersScreen {
|
||||||
let proceed = "invite_users-proceed"
|
let proceed = "invite_users-proceed"
|
||||||
let userProfile = "invite_users-user_profile"
|
let userProfile = "invite_users-user_profile"
|
||||||
@@ -353,6 +361,13 @@ enum A11yIdentifiers {
|
|||||||
let cancel = "space_add_rooms_screen-cancel"
|
let cancel = "space_add_rooms_screen-cancel"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SearchScreen {
|
||||||
|
let roomNamePrefix = "search_screen-room_name"
|
||||||
|
func roomName(_ name: String) -> String {
|
||||||
|
"\(roomNamePrefix):\(name)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct SpaceSettingsScreen {
|
struct SpaceSettingsScreen {
|
||||||
let editBaseInfo = "space_settings_screen-edit_space_info"
|
let editBaseInfo = "space_settings_screen-edit_space_info"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ struct SearchScreen: View {
|
|||||||
private extension View {
|
private extension View {
|
||||||
/// Searchable makes the preview contents randomly appear lower
|
/// Searchable makes the preview contents randomly appear lower
|
||||||
@ViewBuilder func conditionalSearchable(searchQuery: Binding<String>) -> some View {
|
@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)
|
searchable(text: searchQuery, placement: .toolbarPrincipal)
|
||||||
} else {
|
} else {
|
||||||
self
|
self
|
||||||
@@ -334,6 +334,7 @@ private struct SearchScreenRoomCell: View {
|
|||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
}
|
}
|
||||||
.buttonStyle(SearchScreenRoomCellButtonStyle(isSelected: isSelected))
|
.buttonStyle(SearchScreenRoomCellButtonStyle(isSelected: isSelected))
|
||||||
|
.accessibilityIdentifier(A11yIdentifiers.searchScreen.roomName(room.title))
|
||||||
.listRowInsets(.init())
|
.listRowInsets(.init())
|
||||||
.listRowSeparator(.hidden)
|
.listRowSeparator(.hidden)
|
||||||
.rowDivider()
|
.rowDivider()
|
||||||
|
|||||||
@@ -31,12 +31,17 @@ class UserFlowTests: XCTestCase {
|
|||||||
/// Assumes app is on the home screen
|
/// Assumes app is on the home screen
|
||||||
private func checkRoomFlows() {
|
private func checkRoomFlows() {
|
||||||
// Search for the special test room
|
// 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))
|
XCTAssertTrue(searchField.waitForExistence(timeout: 30))
|
||||||
searchField.clearAndTypeText(Self.integrationTestsRoomName, app: app)
|
searchField.clearAndTypeText(Self.integrationTestsRoomName, app: app)
|
||||||
|
|
||||||
// And open it
|
// 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
|
// The backend is sometimes really slow and having a longer timeout
|
||||||
// beats having to rerun the whole suite again.
|
// beats having to rerun the whole suite again.
|
||||||
@@ -50,11 +55,6 @@ class UserFlowTests: XCTestCase {
|
|||||||
|
|
||||||
// Go back to the room list
|
// Go back to the room list
|
||||||
tapOnBackButton("Chats")
|
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() {
|
private func sendMessages() {
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ class UserSessionScreenTests: XCTestCase {
|
|||||||
try await app.assertScreenshot(step: Step.homeScreenWithTabBar)
|
try await app.assertScreenshot(step: Step.homeScreenWithTabBar)
|
||||||
|
|
||||||
// app.tabBars doesn't work on iPadOS 18 😐
|
// 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)
|
try await app.assertScreenshot(step: Step.spacesScreen)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user