Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CI] Add MessageList E2E tests #5530

Merged
merged 3 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
include:
- batch: 0
- batch: 1
fail-fast: false
env:
ANDROID_API_LEVEL: 34
steps:
Expand Down
13 changes: 9 additions & 4 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,16 @@ before_all do |lane|
end
end

lane :start_mock_server do
stop_mock_server if is_localhost
lane :start_mock_server do |options|
mock_server_repo = 'stream-chat-test-mock-server'
sh("rm -rf #{mock_server_repo}") if File.directory?(mock_server_repo)
sh("git clone [email protected]:#{github_repo.split('/').first}/#{mock_server_repo}.git")
stop_mock_server if is_localhost

if options[:local_server]
mock_server_repo = options[:local_server]
else
sh("rm -rf #{mock_server_repo}") if File.directory?(mock_server_repo)
sh("git clone [email protected]:#{github_repo.split('/').first}/#{mock_server_repo}.git")
end

Dir.chdir(mock_server_repo) do
FileUtils.mkdir_p('logs')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ open class MessageListPage {
class MessageList {

companion object {
val messageList = By.res("Stream_MessageList")
val messages = By.res("Stream_MessageCell")
val dateSeparator = By.res("Stream_MessageDateSeparator")
val unreadMessagesBadge = By.res("Stream_UnreadMessagesBadge")
Expand All @@ -90,6 +91,7 @@ open class MessageListPage {
val readStatusIsRead = By.res("Stream_MessageReadStatus_isRead")
val readStatusIsPending = By.res("Stream_MessageReadStatus_isPending")
val readStatusIsSent = By.res("Stream_MessageReadStatus_isSent")
val failedIcon = By.res("Stream_MessageFailedIcon")
val readCount = By.res("Stream_MessageReadCount")
val timestamp = By.res("Stream_Timestamp")
val reactions = By.res("Stream_MessageReaction")
Expand All @@ -98,6 +100,7 @@ open class MessageListPage {
val threadRepliesLabel = By.res("Stream_ThreadRepliesLabel")
val threadParticipantAvatar = By.res("Stream_ThreadParticipantAvatar")
val editedLabel = By.res("Stream_MessageEditedLabel")
val deletedMessage = By.res("Stream_MessageDeleted")
val messageHeaderLabel = By.res("Stream_MessageHeaderLabel") // e.g.: Pinned by you
val image = By.res("Stream_MediaContent")
val video = By.res("Stream_PlayButton")
Expand Down Expand Up @@ -145,6 +148,7 @@ open class MessageListPage {

companion object {
val reply = By.res("Stream_ContextMenu_Reply")
val resend = By.res("Stream_ContextMenu_Resend")
val threadReply = By.res("Stream_ContextMenu_Thread reply")
val markAsUnread = By.res("Stream_ContextMenu_Mark as Unread")
val copy = By.res("Stream_ContextMenu_Copy Message")
Expand All @@ -154,6 +158,7 @@ open class MessageListPage {
val unpin = By.res("Stream_ContextMenu_Unpin from this Chat")
val block = By.res("Stream_ContextMenu_Block user")
val delete = By.res("Stream_ContextMenu_Delete Message")
val ok = By.text("OK")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

package io.getstream.chat.android.compose.robots

import androidx.test.uiautomator.By
import androidx.test.uiautomator.Direction
import io.getstream.chat.android.compose.pages.ChannelListPage
import io.getstream.chat.android.compose.pages.LoginPage
import io.getstream.chat.android.compose.pages.MessageListPage
import io.getstream.chat.android.compose.pages.MessageListPage.Composer
import io.getstream.chat.android.compose.pages.MessageListPage.MessageList
import io.getstream.chat.android.compose.pages.MessageListPage.MessageList.Message
import io.getstream.chat.android.compose.pages.MessageListPage.MessageList.Message.ContextMenu
import io.getstream.chat.android.compose.pages.ThreadPage
import io.getstream.chat.android.compose.uiautomator.defaultTimeout
import io.getstream.chat.android.compose.uiautomator.device
Expand All @@ -31,11 +33,13 @@ import io.getstream.chat.android.compose.uiautomator.findObjects
import io.getstream.chat.android.compose.uiautomator.longPress
import io.getstream.chat.android.compose.uiautomator.swipeDown
import io.getstream.chat.android.compose.uiautomator.swipeUp
import io.getstream.chat.android.compose.uiautomator.tapOnScreenCenter
import io.getstream.chat.android.compose.uiautomator.typeText
import io.getstream.chat.android.compose.uiautomator.wait
import io.getstream.chat.android.compose.uiautomator.waitToAppear
import io.getstream.chat.android.compose.uiautomator.waitToDisappear
import io.getstream.chat.android.e2e.test.mockserver.ReactionType
import io.getstream.chat.android.e2e.test.robots.ParticipantRobot

class UserRobot {

Expand Down Expand Up @@ -87,17 +91,24 @@ class UserRobot {

fun deleteMessage(messageCellIndex: Int = 0, hard: Boolean = false): UserRobot {
openContextMenu(messageCellIndex)
Message.ContextMenu.delete.waitToAppear().click()
ContextMenu.delete.waitToAppear().click()
ContextMenu.ok.findObject().click()
return this
}

fun editMessage(newText: String, messageCellIndex: Int = 0): UserRobot {
openContextMenu(messageCellIndex)
Message.ContextMenu.edit.waitToAppear().click()
ContextMenu.edit.waitToAppear().click()
sendMessage(newText)
return this
}

fun resendMessage(messageCellIndex: Int = 0): UserRobot {
openContextMenu(messageCellIndex)
ContextMenu.resend.waitToAppear().click()
return this
}

fun clearComposer(): UserRobot {
Composer.inputField.waitToAppear().clear()
return this
Expand All @@ -121,15 +132,15 @@ class UserRobot {

fun quoteMessage(text: String, messageCellIndex: Int = 0): UserRobot {
openContextMenu(messageCellIndex)
Message.ContextMenu.reply.waitToAppear().click()
ContextMenu.reply.waitToAppear().click()
sendMessage(text)
return this
}

fun openThread(messageCellIndex: Int = 0, usingContextMenu: Boolean = true): UserRobot {
if (usingContextMenu) {
openContextMenu(messageCellIndex)
Message.ContextMenu.threadReply.waitToAppear().click()
ContextMenu.threadReply.waitToAppear().click()
} else {
Message.threadRepliesLabel.waitToAppear().click()
}
Expand All @@ -151,6 +162,17 @@ class UserRobot {
return this
}

fun sendMessageInThread(
text: String,
alsoSendInChannel: Boolean = false,
): UserRobot {
if (alsoSendInChannel) {
ThreadPage.ThreadList.alsoSendToChannelCheckbox.waitToAppear().click()
}
sendMessage(text)
return this
}

fun quoteMessageInThread(
text: String,
alsoSendInChannel: Boolean = false,
Expand All @@ -176,22 +198,22 @@ class UserRobot {
return this
}

fun scrollChannelListDown(times: Int = 1): UserRobot {
fun scrollChannelListDown(times: Int = 3): UserRobot {
device.swipeUp(times)
return this
}

fun scrollChannelListUp(times: Int = 1): UserRobot {
fun scrollChannelListUp(times: Int = 3): UserRobot {
device.swipeDown(times)
return this
}

fun scrollMessageListDown(times: Int = 1): UserRobot {
fun scrollMessageListDown(times: Int = 3): UserRobot {
scrollChannelListDown(times) // Reusing the channel list scroll
return this
}

fun scrollMessageListUp(times: Int = 1): UserRobot {
fun scrollMessageListUp(times: Int = 3): UserRobot {
scrollChannelListUp(times) // Reusing the channel list scroll
return this
}
Expand All @@ -206,6 +228,11 @@ class UserRobot {
return this
}

fun openAttachmentsMenu(): UserRobot {
Composer.attachmentsButton.waitToAppear().click()
return this
}

fun uploadGiphy(useComposerCommand: Boolean = false, send: Boolean = true): UserRobot {
val giphyMessageText = "G" // any message text will result in sending a giphy
if (useComposerCommand) {
Expand Down Expand Up @@ -263,14 +290,18 @@ class UserRobot {
fun mentionParticipant(useSuggestions: Boolean = true, send: Boolean = true): UserRobot {
if (useSuggestions) {
typeText("@")
Composer.participantMentionSuggestion.waitToAppear().click()
By.text(ParticipantRobot.name).waitToAppear().click()
} else {
typeText("@Han Solo")
typeText("@${ParticipantRobot.name}")
}

if (send) {
Composer.sendButton.waitToAppear().click()
}
return this
}

fun tapOnMessageList() {
device.tapOnScreenCenter()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,32 @@
package io.getstream.chat.android.compose.robots

import io.getstream.chat.android.compose.pages.ChannelListPage.ChannelList.Channel
import io.getstream.chat.android.compose.uiautomator.exists
import io.getstream.chat.android.compose.uiautomator.isDisplayed
import io.getstream.chat.android.compose.uiautomator.wait
import io.getstream.chat.android.compose.uiautomator.waitToAppear
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue

fun UserRobot.assertChannelAvatar(): UserRobot {
assertTrue(Channel.avatar.exists())
assertTrue(Channel.avatar.isDisplayed())
return this
}

fun UserRobot.assertMessageInChannelPreview(text: String, fromCurrentUser: Boolean): UserRobot {
val expectedPreview = if (fromCurrentUser) "You: $text" else text
assertEquals(expectedPreview, Channel.messagePreview.waitToAppear().text.trimEnd())
assertTrue(Channel.timestamp.exists())
assertTrue(Channel.timestamp.isDisplayed())
return this
}

fun UserRobot.assertMessageDeliveryStatus(shouldBeVisible: Boolean, shouldBeRead: Boolean = false): UserRobot {
if (shouldBeVisible) {
val readStatus = if (shouldBeRead) Channel.readStatusIsRead else Channel.readStatusIsSent
assertTrue(readStatus.wait().exists())
assertTrue(readStatus.wait().isDisplayed())
} else {
assertFalse(Channel.readStatusIsRead.exists())
assertFalse(Channel.readStatusIsSent.exists())
assertFalse(Channel.readStatusIsRead.isDisplayed())
assertFalse(Channel.readStatusIsSent.isDisplayed())
}
return this
}
Loading
Loading