Skip to content
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
6 changes: 6 additions & 0 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ lane :run_e2e_test do |options|

start_mock_server(local_server: options[:local_server], branch: options[:mock_server_branch])
install_test_services
update_emulator_settings
upload_attachments

stream_apk_folder_path = options[:apk_folder_path] || '..'
Expand Down Expand Up @@ -165,6 +166,11 @@ private_lane :install_test_services do
install(tool: :allurectl, chmod: true) if is_ci
end

private_lane :update_emulator_settings do
sh('adb shell settings put system show_touches 1')
sh('adb shell settings put system pointer_location 1')
end

desc 'Run fastlane linting'
lane :rubocop do
next unless is_check_required(sources: sources_matrix[:ruby], force_check: @force_check)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ class QuotedReplyTests : StreamTestCase() {
}

@AllureId("5893")
@Ignore("https://linear.app/stream/issue/AND-960")
@Test
fun test_quotedReplyNotInList_whenParticipantAddsQuotedReply_Message_InThread() {
step("GIVEN user opens the channel") {
Expand All @@ -405,16 +406,16 @@ class QuotedReplyTests : StreamTestCase() {
}
step("THEN user observes the quote reply in thread") {
userRobot
.openThread()
.assertQuotedMessage(text = quoteReply, quote = sampleText, isDisplayed = true)
.openThread(usingContextMenu = false)
.assertQuotedMessage(text = quoteReply, quote = "1", isDisplayed = true)
.assertScrollToBottomButton(isDisplayed = false)
}
step("WHEN user taps on a quoted message") {
userRobot.tapOnQuotedMessage()
}
step("THEN user is scrolled up to the quote") {
userRobot
.assertQuotedMessage(text = quoteReply, quote = sampleText, isDisplayed = false)
.assertQuotedMessage(text = quoteReply, quote = "1", isDisplayed = false)
.assertScrollToBottomButton(isDisplayed = true)
}
}
Expand Down Expand Up @@ -557,6 +558,8 @@ class QuotedReplyTests : StreamTestCase() {
@AllureId("5898")
@Test
fun test_quotedReplyInThreadAndAlsoInChannel() {
val quotedText = messagesCount.toString()

step("GIVEN user opens the channel") {
backendRobot.generateChannels(
channelsCount = 1,
Expand All @@ -567,17 +570,17 @@ class QuotedReplyTests : StreamTestCase() {
userRobot.login().openChannel()
}
step("WHEN participant adds a quoted reply in thread and also in channel") {
participantRobot.quoteMessageInThread(quoteReply, alsoSendInChannel = true, last = false)
participantRobot.quoteMessageInThread(quoteReply, alsoSendInChannel = true)
}
step("THEN user observes the quoted reply in channel") {
userRobot
.assertQuotedMessage(text = quoteReply, quote = sampleText)
.assertQuotedMessage(text = quoteReply, quote = quotedText)
.assertScrollToBottomButton(isDisplayed = false)
}
step("AND user observes the quoted reply also in thread") {
userRobot
.openThread()
.assertQuotedMessage(text = quoteReply, quote = sampleText)
.openThread(usingContextMenu = false)
.assertQuotedMessage(text = quoteReply, quote = quotedText)
.assertScrollToBottomButton(isDisplayed = false)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import androidx.lifecycle.lifecycleScope
import io.getstream.chat.android.client.ChatClient
import io.getstream.chat.android.client.token.TokenProvider
import io.getstream.chat.android.compose.sample.data.PredefinedUserCredentials
import io.getstream.chat.android.compose.sample.data.PredefinedUserCredentials.API_KEY
import io.getstream.chat.android.compose.ui.theme.ChatTheme
import io.getstream.chat.android.models.ConnectionState
import io.getstream.chat.android.models.User
Expand Down Expand Up @@ -184,7 +183,7 @@ class JwtTestActivity : AppCompatActivity() {

private suspend fun fetchJwtToken(baseUrl: String, userId: String): String {
return withContext(Dispatchers.IO) {
val endpoint = "$baseUrl/jwt/get?api_key=$API_KEY&user_id=$userId"
val endpoint = "$baseUrl/jwt/get?platform=android"
val request = Request.Builder().url(endpoint).build()

OkHttpClient().newCall(request).execute().use { response ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
package io.getstream.chat.android.e2e.test.rules

import android.database.sqlite.SQLiteDatabase
import android.os.Environment
import androidx.test.platform.app.InstrumentationRegistry
import io.getstream.chat.android.compose.uiautomator.allureLogcat
import io.getstream.chat.android.compose.uiautomator.allureScreenrecord
import io.getstream.chat.android.compose.uiautomator.allureScreenshot
import io.getstream.chat.android.compose.uiautomator.allureWindowHierarchy
import io.getstream.chat.android.compose.uiautomator.device
Expand All @@ -44,31 +46,84 @@ public class RetryRule(private val count: Int) : TestRule {
return object : Statement() {
@Throws(Throwable::class)
override fun evaluate() {
val testName = description.displayName
val retryAnnotation: Retry? = description.getAnnotation(Retry::class.java)
val retryCount = retryAnnotation?.count ?: count
val databaseOperations = DatabaseOperations()
var caughtThrowable: Throwable? = null
lateinit var videoFilePath: String
lateinit var recordingThread: Thread

for (i in 0 until retryCount) {
try {
System.err.println("${description.displayName}: run #${i + 1} started.")
System.err.println("$testName: run #${i + 1} started.")
device.executeShellCommand("logcat -c")
videoFilePath = "${Environment.getExternalStorageDirectory().absolutePath}/$testName.mp4"
recordingThread = startVideoRecording(videoFilePath)
base.evaluate()
stopVideoRecording(videoFilePath, recordingThread)
return
} catch (t: Throwable) {
System.err.println("${description.displayName}: run #${i + 1} failed.")
databaseOperations.clearDatabases()
System.err.println("$testName: run #${i + 1} failed.")
caughtThrowable = t
databaseOperations.clearDatabases()
stopVideoRecording(videoFilePath, recordingThread)
device.allureLogcat(name = "logcat_${i + 1}")
device.allureScreenshot(name = "screenshot_${i + 1}")
device.allureWindowHierarchy(name = "hierarchy_${i + 1}")
device.allureScreenrecord(
name = "record_${i + 1}",
file = File(videoFilePath),
)
} finally {
device.executeShellCommand("rm $videoFilePath")
}
}

throw caughtThrowable ?: IllegalStateException()
}
}
}

private fun startVideoRecording(remoteVideoPath: String): Thread {
return Thread {
device.executeShellCommand(
"screenrecord --bit-rate 8000000 --time-limit 180 $remoteVideoPath",
)
}.also { it.start() }
}

private fun stopVideoRecording(remoteVideoPath: String, thread: Thread) {
device.executeShellCommand("pkill -INT screenrecord")
thread.join(5000)
waitUntil { !isScreenrecordRunning() }
waitUntil { isFileStable(remoteVideoPath) }
}

private fun isScreenrecordRunning(): Boolean {
val ps = device.executeShellCommand("ps | grep screenrecord || true")
return ps.contains("screenrecord")
}

private fun isFileStable(path: String): Boolean {
val output = device.executeShellCommand("ls -l $path")
val size = output.trim().split(Regex("\\s+")).getOrNull(4)?.toLongOrNull() ?: 0L
Thread.sleep(200)
val output2 = device.executeShellCommand("ls -l $path")
val size2 = output2.trim().split(Regex("\\s+")).getOrNull(4)?.toLongOrNull() ?: 0L
return size > 0 && size == size2
}

@Suppress("TooGenericExceptionThrown")
private fun waitUntil(timeoutMs: Long = 5000, condition: () -> Boolean) {
val start = System.currentTimeMillis()
while (!condition()) {
if (System.currentTimeMillis() - start > timeoutMs) {
throw RuntimeException("Timeout waiting for video recording to finish")
}
Thread.sleep(200)
}
}
}

public open class DatabaseOperations {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import androidx.test.uiautomator.UiObject2
import io.qameta.allure.kotlin.Allure
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File

public fun UiDevice.stopApp() {
executeShellCommand("pm clear $packageName")
Expand Down Expand Up @@ -155,6 +156,15 @@ public fun UiDevice.allureScreenshot(name: String) {
}
}

public fun UiDevice.allureScreenrecord(name: String, file: File) {
Allure.attachment(
name = "$name.mp4",
type = "video/mp4",
fileExtension = ".mp4",
content = file.inputStream(),
)
}

public fun UiDevice.allureLogcat(name: String) {
Allure.attachment(
name = "$name.txt",
Expand Down
Loading