Skip to content

Commit

Permalink
[CI] Add MessageList E2E tests
Browse files Browse the repository at this point in the history
  • Loading branch information
testableapple committed Jan 8, 2025
1 parent fb5aaa4 commit 9ee519d
Show file tree
Hide file tree
Showing 19 changed files with 1,150 additions and 54 deletions.
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 git@github.com:#{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 git@github.com:#{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,26 +16,31 @@

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
import io.getstream.chat.android.compose.uiautomator.findObject
import io.getstream.chat.android.compose.uiautomator.findObjects
import io.getstream.chat.android.compose.uiautomator.isDisplayed
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 +92,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 +133,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 +163,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 +199,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 +229,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 +291,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

0 comments on commit 9ee519d

Please sign in to comment.