diff --git a/ElementX/Sources/Mocks/UserSessionMock.swift b/ElementX/Sources/Mocks/UserSessionMock.swift index f2877dcb1..3300540cd 100644 --- a/ElementX/Sources/Mocks/UserSessionMock.swift +++ b/ElementX/Sources/Mocks/UserSessionMock.swift @@ -22,5 +22,7 @@ extension UserSessionMock { voiceMessageMediaManager = VoiceMessageMediaManagerMock() sessionSecurityStatePublisher = CurrentValueSubject(.init(verificationState: .verified, recoveryState: .enabled)).asCurrentValuePublisher() + + liveLocationManager = LiveLocationManagerMock(.init()) } } diff --git a/IntegrationTests/Sources/UserFlowTests.swift b/IntegrationTests/Sources/UserFlowTests.swift index 8f22a7cfe..f1187345e 100644 --- a/IntegrationTests/Sources/UserFlowTests.swift +++ b/IntegrationTests/Sources/UserFlowTests.swift @@ -23,10 +23,6 @@ class UserFlowTests: XCTestCase { func testUserFlow() { checkRoomFlows() - checkSettings() - - checkRoomCreation() - app.logout() } @@ -51,17 +47,9 @@ class UserFlowTests: XCTestCase { firstRoom.tap(.center) sendMessages() - - checkPhotoSharing() - - checkDocumentSharing() - - checkLocationSharing() - + checkTimelineItemActionMenu() - checkRoomDetails() - // Go back to the room list tapOnBackButton("Chats") @@ -99,75 +87,6 @@ class UserFlowTests: XCTestCase { // Close the formatting options app.buttons[A11yIdentifiers.roomScreen.composerToolbar.closeFormattingOptions].tap(.center) } - - private func checkPhotoSharing() { - tapOnButton(A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions) - tapOnButton(A11yIdentifiers.roomScreen.attachmentPickerPhotoLibrary) - - sleep(10) // Wait for the picker to load - - // Tap on the second image. First one is always broken on simulators. - let secondImage = app.scrollViews.images.element(boundBy: 1) - XCTAssertTrue(secondImage.waitForExistence(timeout: 20.0)) // Photo library takes a bit to load - secondImage.tap(.center) - - // Wait for the image to be processed and the new screen to appear - sleep(10) - - // Cancel the upload flow - tapOnButton("Cancel", waitForDisappearance: true) - } - - private func checkDocumentSharing() { - tapOnButton(A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions) - tapOnButton(A11yIdentifiers.roomScreen.attachmentPickerDocuments) - - sleep(10) // Wait for the picker to load - - tapOnButton("Cancel", waitForDisappearance: true) - } - - private func checkLocationSharing() { - tapOnButton(A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions) - tapOnButton(A11yIdentifiers.roomScreen.attachmentPickerLocation) - - sleep(10) // Wait for the picker to load - - // The order of the alerts is a bit of a mistery so try twice - - allowLocationPermissionOnce() - - // Handle map loading errors (missing credentials) - let alertOkButton = app.alerts.firstMatch.buttons["OK"].firstMatch - if alertOkButton.waitForExistence(timeout: 10.0) { - alertOkButton.tap(.center) - } - - allowLocationPermissionOnce() - - tapOnButton("Close", waitForDisappearance: true) - } - - private func allowLocationPermissionOnce() { - let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") - let notificationAlertAllowButton = springboard.buttons["Allow Once"].firstMatch - if notificationAlertAllowButton.waitForExistence(timeout: 10.0) { - notificationAlertAllowButton.tap(.center) - } - } - - private func checkRoomCreation() { - tapOnButton(A11yIdentifiers.homeScreen.startChat) - - tapOnButton(A11yIdentifiers.startChatScreen.createRoom) - - // Don't create the room, it will make the test account very noisy. - // The UI tests already test this flow with mocked data. - - tapOnBackButton("Start chat") - - tapOnButton("Cancel", waitForDisappearance: true) - } private func checkTimelineItemActionMenu() { // Long press on the last message @@ -184,77 +103,6 @@ class UserFlowTests: XCTestCase { } } - private func checkRoomDetails() { - // Open the room details - let roomHeader = app.buttons[A11yIdentifiers.roomScreen.name] - XCTAssertTrue(roomHeader.waitForExistence(timeout: 10.0)) - roomHeader.tap(.center) - - // Swipe until the People button is hittable - let peopleButton = app.buttons[A11yIdentifiers.roomDetailsScreen.people] - if !peopleButton.isHittable { - var attempts = 0 - while !peopleButton.isHittable, attempts < 5 { - app.swipeUp() - attempts += 1 - } - } - - // Open the room members list. - tapOnButton(A11yIdentifiers.roomDetailsScreen.people) - - // Open the first member's details. Loading members for big rooms can take a while. - let firstRoomMember = app.scrollViews.buttons.firstMatch - XCTAssertTrue(firstRoomMember.waitForExistence(timeout: 1000.0)) - firstRoomMember.tap(.center) - - // Open the profile from the bottom sheet - let viewProfileButton = app.buttons[A11yIdentifiers.manageRoomMemberSheet.viewProfile] - XCTAssertTrue(viewProfileButton.waitForExistence(timeout: 10.0)) - tapOnButton(A11yIdentifiers.manageRoomMemberSheet.viewProfile, waitForDisappearance: true) - - // Go back to the room member details - tapOnBackButton("People") - - // Go back to the room details - tapOnBackButton("Room info") - - // Go back to the room - tapOnBackButton("Chat") - } - - private func checkSettings() { - // On first login when multiple sheets get presented the profile button is not hittable - // Moving the scroll fixed it for some obscure reason - app.swipeDown() - - let profileButton = app.buttons[A11yIdentifiers.homeScreen.userAvatar] - - // `Failed to scroll to visible (by AX action) Button` https://stackoverflow.com/a/33534187/730924 - profileButton.tap(.center) - - // Open analytics - tapOnButton(A11yIdentifiers.settingsScreen.analytics) - - // Go back to settings - tapOnBackButton("Settings") - - // Open report a bug - tapOnButton(A11yIdentifiers.settingsScreen.reportBug) - - // Go back to settings - tapOnBackButton("Settings") - - // Open about - tapOnButton(A11yIdentifiers.settingsScreen.about) - - // Go back to settings - tapOnBackButton("Settings") - - // Close the settings - tapOnButton(A11yIdentifiers.settingsScreen.done) - } - private func tapOnButton(_ identifier: String, waitForDisappearance: Bool = false) { let button = app.buttons[identifier] XCTAssertTrue(button.waitForExistence(timeout: 10.0)) diff --git a/UITests/Sources/UserSessionScreenTests.swift b/UITests/Sources/UserSessionScreenTests.swift index d87442617..71aaa9c5d 100644 --- a/UITests/Sources/UserSessionScreenTests.swift +++ b/UITests/Sources/UserSessionScreenTests.swift @@ -76,6 +76,93 @@ class UserSessionScreenTests: XCTestCase { XCTAssert(joinButton.waitForExistence(timeout: 10)) } + func testRoomDetails() { + let app = Application.launch(.userSessionScreen) + + app.buttons[A11yIdentifiers.homeScreen.roomName(firstRoomName)].tap() + XCTAssert(app.buttons[firstRoomName].waitForExistence(timeout: 5.0)) + + // Open the room details + let roomHeader = app.buttons[A11yIdentifiers.roomScreen.name] + XCTAssertTrue(roomHeader.waitForExistence(timeout: 10.0)) + roomHeader.tap(.center) + + // Swipe until the People button is hittable + let peopleButton = app.buttons[A11yIdentifiers.roomDetailsScreen.people] + if !peopleButton.isHittable { + var attempts = 0 + while !peopleButton.isHittable, attempts < 5 { + app.swipeUp() + attempts += 1 + } + } + + // Open the room members list. + app.buttons[A11yIdentifiers.roomDetailsScreen.people].tap() + + // Open the first member's details. Loading members for big rooms can take a while. + let firstRoomMember = app.scrollViews.buttons.firstMatch + XCTAssertTrue(firstRoomMember.waitForExistence(timeout: 1000.0)) + firstRoomMember.tap(.center) + + // Open the profile from the bottom sheet + let viewProfileButton = app.buttons[A11yIdentifiers.manageRoomMemberSheet.viewProfile] + XCTAssertTrue(viewProfileButton.waitForExistence(timeout: 10.0)) + app.buttons[A11yIdentifiers.manageRoomMemberSheet.viewProfile].tap() + + // Go back to the room member details + tapOnBackButton("People", app) + + // Go back to the room details + tapOnBackButton("Room info", app) + + // Go back to the room + tapOnBackButton("Chat", app) + } + + func testPhotoSharing() { + let app = Application.launch(.userSessionScreen) + + app.buttons[A11yIdentifiers.homeScreen.roomName(firstRoomName)].tap() + XCTAssert(app.buttons[firstRoomName].waitForExistence(timeout: 5.0)) + + app.buttons[A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions].tap() + app.buttons[A11yIdentifiers.roomScreen.attachmentPickerPhotoLibrary].tap() + + // Tap on the second image. First one is always broken on simulators. + let secondImage = app.scrollViews.images.element(boundBy: 1) + XCTAssertTrue(secondImage.waitForExistence(timeout: 20.0)) // Photo library takes a bit to load + secondImage.tap(.center) + } + + func testDocumentSharing() { + let app = Application.launch(.userSessionScreen) + + app.buttons[A11yIdentifiers.homeScreen.roomName(firstRoomName)].tap() + XCTAssert(app.buttons[firstRoomName].waitForExistence(timeout: 5.0)) + + app.buttons[A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions].tap() + app.buttons[A11yIdentifiers.roomScreen.attachmentPickerDocuments].tap() + } + + func testLocationSharing() { + let app = Application.launch(.userSessionScreen) + + app.buttons[A11yIdentifiers.homeScreen.roomName(firstRoomName)].tap() + XCTAssert(app.buttons[firstRoomName].waitForExistence(timeout: 5.0)) + + app.buttons[A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions].tap() + app.buttons[A11yIdentifiers.roomScreen.attachmentPickerLocation].tap() + + allowLocationPermissionOnce() + + // Handle map loading errors (missing credentials) + let alertOkButton = app.alerts.firstMatch.buttons["OK"].firstMatch + if alertOkButton.waitForExistence(timeout: 10.0) { + alertOkButton.tap(.center) + } + } + func testSpaceExploration() async throws { let app = Application.launch(.userSessionSpacesFlow) @@ -188,4 +275,62 @@ class UserSessionScreenTests: XCTestCase { try await Task.sleep(for: .seconds(1)) try await app.assertScreenshot(step: Step.spaceScreen) } + + func testSettings() { + let app = Application.launch(.userSessionScreen) + + let profileButton = app.buttons[A11yIdentifiers.homeScreen.userAvatar] + + // `Failed to scroll to visible (by AX action) Button` https://stackoverflow.com/a/33534187/730924 + profileButton.tap(.center) + + // Open analytics + app.buttons[A11yIdentifiers.settingsScreen.analytics].tap() + + // Go back to settings + tapOnBackButton("Settings", app) + + // Open report a bug + app.buttons[A11yIdentifiers.settingsScreen.reportBug].tap() + + // Go back to settings + tapOnBackButton("Settings", app) + + // Open about + app.buttons[A11yIdentifiers.settingsScreen.about].tap() + + // Go back to settings + tapOnBackButton("Settings", app) + + // Close the settings + app.buttons[A11yIdentifiers.settingsScreen.done].tap() + } + + func testRoomCreation() { + let app = Application.launch(.userSessionScreen) + + app.buttons[A11yIdentifiers.homeScreen.startChat].tap() + + app.buttons[A11yIdentifiers.startChatScreen.createRoom].tap() + + tapOnBackButton("Start chat", app) + } + + private func allowLocationPermissionOnce() { + let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") + let notificationAlertAllowButton = springboard.buttons["Allow Once"].firstMatch + if notificationAlertAllowButton.waitForExistence(timeout: 10.0) { + notificationAlertAllowButton.tap(.center) + } + } + + /// Taps on a back button that the system configured with a label but no identifier. + /// + /// When there are multiple buttons with the same label in the hierarchy, all the buttons we created + /// should have an identifier set, and so this method will ignore those picking the one with only a label. + private func tapOnBackButton(_ label: String = "Back", _ app: XCUIApplication) { + let button = app.buttons.matching(NSPredicate(format: "label == %@ && identifier == 'BackButton'", label)).firstMatch + XCTAssertTrue(button.waitForExistence(timeout: 10.0)) + button.tap(.center) + } }