mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Add message sending end editing steps to the user session flow UI test
This commit is contained in:
@@ -183,6 +183,12 @@ enum A11yIdentifiers {
|
|||||||
let openComposeOptions = "composer_toolbar-open_compose_options"
|
let openComposeOptions = "composer_toolbar-open_compose_options"
|
||||||
let closeFormattingOptions = "composer_toolbar-close-formatting-options"
|
let closeFormattingOptions = "composer_toolbar-close-formatting-options"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let timelineItemActionMenuAction = TimelineItemActionMenuAction()
|
||||||
|
|
||||||
|
struct TimelineItemActionMenuAction {
|
||||||
|
let edit = "timeline_item_action_menu-edit"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RoomDetailsScreen {
|
struct RoomDetailsScreen {
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ enum TimelineItemMenuAction: Identifiable, Hashable {
|
|||||||
Label(L10n.actionCopyCaption, icon: \.copy)
|
Label(L10n.actionCopyCaption, icon: \.copy)
|
||||||
case .edit:
|
case .edit:
|
||||||
Label(L10n.actionEdit, icon: \.edit)
|
Label(L10n.actionEdit, icon: \.edit)
|
||||||
|
.accessibilityIdentifier(A11yIdentifiers.roomScreen.timelineItemActionMenuAction.edit)
|
||||||
case .addCaption:
|
case .addCaption:
|
||||||
Label(L10n.actionAddCaption, icon: \.edit)
|
Label(L10n.actionAddCaption, icon: \.edit)
|
||||||
case .editCaption:
|
case .editCaption:
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import Foundation
|
|||||||
import MatrixRustSDK
|
import MatrixRustSDK
|
||||||
|
|
||||||
class MockTimelineController: TimelineControllerProtocol {
|
class MockTimelineController: TimelineControllerProtocol {
|
||||||
|
private let lastInsertedMessageID: TimelineItemIdentifier = .event(uniqueID: .init("last_message"),
|
||||||
|
eventOrTransactionID: .eventID("last_message"))
|
||||||
|
|
||||||
/// An array of timeline item arrays that will be inserted in order for each back pagination request.
|
/// An array of timeline item arrays that will be inserted in order for each back pagination request.
|
||||||
var backPaginationResponses: [[RoomTimelineItemProtocol]] = []
|
var backPaginationResponses: [[RoomTimelineItemProtocol]] = []
|
||||||
/// An array of timeline items that will be appended in order when ``simulateIncomingItems()`` is called.
|
/// An array of timeline items that will be appended in order when ``simulateIncomingItems()`` is called.
|
||||||
@@ -35,7 +38,12 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var timelineItems: [RoomTimelineItemProtocol] = RoomTimelineItemFixtures.default
|
var timelineItems: [RoomTimelineItemProtocol] = RoomTimelineItemFixtures.default {
|
||||||
|
didSet {
|
||||||
|
callbacks.send(.updatedTimelineItems(timelineItems: timelineItems, isSwitchingTimelines: false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var timelineItemsTimestamp: [TimelineItemIdentifier: Date] = [:]
|
var timelineItemsTimestamp: [TimelineItemIdentifier: Date] = [:]
|
||||||
|
|
||||||
private var client: UITestsSignalling.Client?
|
private var client: UITestsSignalling.Client?
|
||||||
@@ -122,7 +130,18 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
func edit(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
intentionalMentions: IntentionalMentions) async { }
|
intentionalMentions: IntentionalMentions) async {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
|
timelineItems[timelineItems.endIndex - 1] = TextRoomTimelineItem(id: lastInsertedMessageID,
|
||||||
|
timestamp: .distantFuture,
|
||||||
|
isOutgoing: true,
|
||||||
|
isEditable: true,
|
||||||
|
canBeRepliedTo: true,
|
||||||
|
sender: .test,
|
||||||
|
content: .init(body: message),
|
||||||
|
properties: .init(isEdited: true))
|
||||||
|
}
|
||||||
|
|
||||||
func editCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
func editCaption(_ eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID,
|
||||||
message: String,
|
message: String,
|
||||||
@@ -164,12 +183,24 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
func sendMessage(_ message: String,
|
func sendMessage(_ message: String,
|
||||||
html: String?,
|
html: String?,
|
||||||
inReplyToEventID: String?,
|
inReplyToEventID: String?,
|
||||||
intentionalMentions: IntentionalMentions) async { }
|
intentionalMentions: IntentionalMentions) async {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
|
timelineItems.append(TextRoomTimelineItem(id: lastInsertedMessageID,
|
||||||
|
timestamp: .distantFuture,
|
||||||
|
isOutgoing: true,
|
||||||
|
isEditable: true,
|
||||||
|
canBeRepliedTo: true,
|
||||||
|
sender: .test,
|
||||||
|
content: .init(body: message)))
|
||||||
|
}
|
||||||
|
|
||||||
func sendAudio(url: URL,
|
func sendAudio(url: URL,
|
||||||
audioInfo: MatrixRustSDK.AudioInfo,
|
audioInfo: MatrixRustSDK.AudioInfo,
|
||||||
caption: String?,
|
caption: String?,
|
||||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
if let timelineProxy {
|
if let timelineProxy {
|
||||||
return await timelineProxy.sendAudio(url: url,
|
return await timelineProxy.sendAudio(url: url,
|
||||||
audioInfo: audioInfo,
|
audioInfo: audioInfo,
|
||||||
@@ -184,6 +215,8 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
fileInfo: MatrixRustSDK.FileInfo,
|
fileInfo: MatrixRustSDK.FileInfo,
|
||||||
caption: String?,
|
caption: String?,
|
||||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
if let timelineProxy {
|
if let timelineProxy {
|
||||||
return await timelineProxy.sendFile(url: url,
|
return await timelineProxy.sendFile(url: url,
|
||||||
fileInfo: fileInfo,
|
fileInfo: fileInfo,
|
||||||
@@ -199,6 +232,8 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
imageInfo: MatrixRustSDK.ImageInfo,
|
imageInfo: MatrixRustSDK.ImageInfo,
|
||||||
caption: String?,
|
caption: String?,
|
||||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
if let timelineProxy {
|
if let timelineProxy {
|
||||||
return await timelineProxy.sendImage(url: url,
|
return await timelineProxy.sendImage(url: url,
|
||||||
thumbnailURL: thumbnailURL,
|
thumbnailURL: thumbnailURL,
|
||||||
@@ -215,6 +250,8 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
description: String?,
|
description: String?,
|
||||||
zoomLevel: UInt8?,
|
zoomLevel: UInt8?,
|
||||||
assetType: MatrixRustSDK.AssetType?) async -> Result<Void, TimelineControllerError> {
|
assetType: MatrixRustSDK.AssetType?) async -> Result<Void, TimelineControllerError> {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
if let timelineProxy {
|
if let timelineProxy {
|
||||||
return await timelineProxy.sendLocation(body: body,
|
return await timelineProxy.sendLocation(body: body,
|
||||||
geoURI: geoURI,
|
geoURI: geoURI,
|
||||||
@@ -231,6 +268,8 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
videoInfo: MatrixRustSDK.VideoInfo,
|
videoInfo: MatrixRustSDK.VideoInfo,
|
||||||
caption: String?,
|
caption: String?,
|
||||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
if let timelineProxy {
|
if let timelineProxy {
|
||||||
return await timelineProxy.sendVideo(url: url,
|
return await timelineProxy.sendVideo(url: url,
|
||||||
thumbnailURL: thumbnailURL,
|
thumbnailURL: thumbnailURL,
|
||||||
@@ -246,6 +285,8 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
audioInfo: MatrixRustSDK.AudioInfo,
|
audioInfo: MatrixRustSDK.AudioInfo,
|
||||||
waveform: [Float],
|
waveform: [Float],
|
||||||
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineControllerError> {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
if let timelineProxy {
|
if let timelineProxy {
|
||||||
return await timelineProxy.sendVoiceMessage(url: url,
|
return await timelineProxy.sendVoiceMessage(url: url,
|
||||||
audioInfo: audioInfo,
|
audioInfo: audioInfo,
|
||||||
@@ -259,6 +300,8 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
// MARK: - Polls
|
// MARK: - Polls
|
||||||
|
|
||||||
func createPoll(question: String, answers: [String], pollKind: Poll.Kind) async -> Result<Void, TimelineControllerError> {
|
func createPoll(question: String, answers: [String], pollKind: Poll.Kind) async -> Result<Void, TimelineControllerError> {
|
||||||
|
callbacks.send(.messageSentOrEdited)
|
||||||
|
|
||||||
if let timelineProxy {
|
if let timelineProxy {
|
||||||
_ = await timelineProxy.createPoll(question: question, answers: answers, pollKind: pollKind)
|
_ = await timelineProxy.createPoll(question: question, answers: answers, pollKind: pollKind)
|
||||||
}
|
}
|
||||||
@@ -326,7 +369,6 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
|
|
||||||
let incomingItem = incomingItems.removeFirst()
|
let incomingItem = incomingItems.removeFirst()
|
||||||
timelineItems.append(incomingItem)
|
timelineItems.append(incomingItem)
|
||||||
callbacks.send(.updatedTimelineItems(timelineItems: timelineItems, isSwitchingTimelines: false))
|
|
||||||
|
|
||||||
try client?.send(.success)
|
try client?.send(.success)
|
||||||
}
|
}
|
||||||
@@ -342,7 +384,6 @@ class MockTimelineController: TimelineControllerProtocol {
|
|||||||
|
|
||||||
let newItems = backPaginationResponses.removeFirst()
|
let newItems = backPaginationResponses.removeFirst()
|
||||||
timelineItems.insert(contentsOf: newItems, at: 0)
|
timelineItems.insert(contentsOf: newItems, at: 0)
|
||||||
callbacks.send(.updatedTimelineItems(timelineItems: timelineItems, isSwitchingTimelines: false))
|
|
||||||
|
|
||||||
try client?.send(.success)
|
try client?.send(.success)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class UserSessionScreenTests: XCTestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testUserSessionFlows() async throws {
|
func testUserSessionFlows() async throws {
|
||||||
let app = Application.launch(.userSessionScreen)
|
let app = Application.launch(.userSessionScreen, disableTimelineAccessibility: false)
|
||||||
|
|
||||||
app.swipeDown() // Make sure the header shows a large title
|
app.swipeDown() // Make sure the header shows a large title
|
||||||
|
|
||||||
@@ -44,7 +44,35 @@ class UserSessionScreenTests: XCTestCase {
|
|||||||
XCTAssert(app.buttons[firstRoomName].waitForExistence(timeout: 5.0))
|
XCTAssert(app.buttons[firstRoomName].waitForExistence(timeout: 5.0))
|
||||||
try await Task.sleep(for: .seconds(1))
|
try await Task.sleep(for: .seconds(1))
|
||||||
try await app.assertScreenshot(step: Step.roomScreen)
|
try await app.assertScreenshot(step: Step.roomScreen)
|
||||||
|
|
||||||
|
var composer = app.textViews[A11yIdentifiers.roomScreen.messageComposer]
|
||||||
|
composer.tap(.center)
|
||||||
|
composer.typeText("sugar honey ice")
|
||||||
|
|
||||||
|
app.buttons[A11yIdentifiers.roomScreen.sendButton].tap()
|
||||||
|
|
||||||
|
let latestMessage = app.textViews.matching(NSPredicate(format: "value CONTAINS 'sugar honey ice'")).firstMatch
|
||||||
|
XCTAssert(latestMessage.waitForExistence(timeout: 5.0))
|
||||||
|
|
||||||
|
// Tapping on the mesage text view or the cell doesn't work.
|
||||||
|
// Use the sender static text instead.
|
||||||
|
let latestEventSender = app.staticTexts["@test.matrix.org"]
|
||||||
|
XCTAssert(latestEventSender.waitForExistence(timeout: 5.0))
|
||||||
|
latestEventSender.press(forDuration: 5.0)
|
||||||
|
|
||||||
|
let editButton = app.buttons[A11yIdentifiers.roomScreen.timelineItemActionMenuAction.edit]
|
||||||
|
XCTAssert(editButton.waitForExistence(timeout: 5.0))
|
||||||
|
editButton.tap()
|
||||||
|
|
||||||
|
composer = app.textViews[A11yIdentifiers.roomScreen.messageComposer]
|
||||||
|
composer.tap(.center)
|
||||||
|
composer.typeText(" & tea")
|
||||||
|
|
||||||
|
app.buttons[A11yIdentifiers.roomScreen.sendButton].tap()
|
||||||
|
|
||||||
|
let latestEditedMessage = app.textViews.matching(NSPredicate(format: "value CONTAINS 'sugar honey ice & tea'")).firstMatch
|
||||||
|
XCTAssert(latestEditedMessage.waitForExistence(timeout: 5.0))
|
||||||
|
|
||||||
app.buttons[A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions].tap(.center)
|
app.buttons[A11yIdentifiers.roomScreen.composerToolbar.openComposeOptions].tap(.center)
|
||||||
try await app.assertScreenshot(step: Step.composerAttachments)
|
try await app.assertScreenshot(step: Step.composerAttachments)
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:69e336fcc27867de462eeb74a83cb50a62cf278920199a56792632e4329cc250
|
oid sha256:bf0f3e45df8d7b61fc004ec7d9378950a0bc26c3d96249c2260a254bd8b92abc
|
||||||
size 619016
|
size 644781
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:15c02e01fd99fab8b93a4c9b8922da79aee505d6141cf01fb7b9bfb9243867ef
|
oid sha256:843e4dbadd9547a96fa24f21b28825f838a6ea352fd9d8f3abed910e5fc5c634
|
||||||
size 463451
|
size 417228
|
||||||
|
|||||||
Reference in New Issue
Block a user