Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

[Android] Take a screenshot when instrumentation tests fail #871

Merged
merged 1 commit into from
Nov 17, 2023
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
7 changes: 3 additions & 4 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,8 @@ jobs:
disable-animations: true
enable-hw-keyboard: true
script: |
./gradlew unitTestsWithCoverage ${{ env.CI_GRADLE_ARG_PROPERTIES }}
./gradlew generateUnitTestCoverageReport ${{ env.CI_GRADLE_ARG_PROPERTIES }}
./gradlew instrumentationTestsWithCoverage ${{ env.CI_GRADLE_ARG_PROPERTIES }}
./gradlew generateInstrumentationTestCoverageReport ${{ env.CI_GRADLE_ARG_PROPERTIES }}
chmod +x scripts/ci_test.sh
scripts/ci_test.sh

- name : Upload test results
if : ${{ always() }}
Expand All @@ -105,6 +103,7 @@ jobs:
path : |
./**/build/reports/tests/**
./**/build/reports/androidTests/connected/**
./**/build/reports/screenshots/**

- name: Upload unit test coverage to Codecov
uses: codecov/codecov-action@v3
Expand Down
1 change: 1 addition & 0 deletions platforms/android/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,5 @@ test-turbine = { module="app.cash.turbine:turbine", version="1.0.0" }
test-androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" }
test-androidx-espresso = { module="androidx.test.espresso:espresso-core", version.ref="espresso" }
test-androidx-espresso-accessibility = { module="androidx.test.espresso:espresso-accessibility", version.ref="espresso" }
test-androidx-uiautomator = "androidx.test.uiautomator:uiautomator:2.2.0"
test-mockk-android = { module="io.mockk:mockk-android", version.ref="mockk" }
1 change: 1 addition & 0 deletions platforms/android/library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ dependencies {
androidTestImplementation libs.test.androidx.espresso
androidTestImplementation libs.test.androidx.espresso.accessibility
androidTestImplementation libs.test.mockk.android
androidTestImplementation libs.test.androidx.uiautomator
}

android.libraryVariants.all { variant ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import android.view.View
import android.widget.EditText
import android.widget.TextView
import androidx.core.text.getSpans
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.Espresso.setFailureHandler
import androidx.test.espresso.accessibility.AccessibilityChecks
import androidx.test.espresso.action.ViewActions.pressKey
import androidx.test.espresso.action.ViewActions.replaceText
Expand Down Expand Up @@ -58,6 +60,13 @@ class EditorEditTextInputTests {
AccessibilityChecks.enable()
}

@Before
fun setUp() {
setFailureHandler(
ScreenshotFailureHandler(ApplicationProvider.getApplicationContext())
)
}

@After
fun cleanUp() {
// Finish composing just in case, to prevent clashes between test cases
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package io.element.android.wysiwyg.test.utils

import android.content.ContentValues
import android.content.Context
import android.graphics.Bitmap
import android.os.Environment
import android.provider.MediaStore
import android.view.View
import androidx.test.espresso.FailureHandler
import androidx.test.espresso.base.DefaultFailureHandler
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import org.hamcrest.Matcher
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Calendar

class ScreenshotFailureHandler(appContext: Context) : FailureHandler {
private val defaultHandler: FailureHandler = DefaultFailureHandler(appContext)

override fun handle(error: Throwable, viewMatcher: Matcher<View>) {
getInstrumentation()
.uiAutomation
.takeScreenshot()
.save()

defaultHandler.handle(error, viewMatcher)
}
}

private fun Bitmap.save() {
val timestamp = timestamp()
val contentResolver = getInstrumentation().targetContext.applicationContext.contentResolver
try {
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "$timestamp.jpeg")
put(MediaStore.Images.Media.RELATIVE_PATH, "${Environment.DIRECTORY_PICTURES}/UiTest")
}

val uri = contentResolver
.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
?: return

contentResolver.openOutputStream(uri)?.use { outputStream ->
compress(Bitmap.CompressFormat.PNG, 20, outputStream)
}

contentResolver.update(uri, contentValues, null, null)
} catch (e: IOException) {
e.printStackTrace()
}
}

private fun timestamp(): String =
SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().time)
23 changes: 23 additions & 0 deletions platforms/android/scripts/ci_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

./gradlew unitTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES
./gradlew generateUnitTestCoverageReport $CI_GRADLE_ARG_PROPERTIES

# Don't exit immediately from UI test failure to collect screenshots
set +e

./gradlew instrumentationTestsWithCoverage $CI_GRADLE_ARG_PROPERTIES

UI_TEST_EXIT_CODE=$?
if [ $UI_TEST_EXIT_CODE -ne 0 ]; then
echo "UI tests failed."
echo "Pulling screenshots from device..."
adb shell ls /sdcard/Pictures/UiTest/
mkdir build/reports/screenshots
adb pull /sdcard/Pictures/UiTest/ build/reports/screenshots/
exit $UI_TEST_EXIT_CODE
fi
set -e

./gradlew generateInstrumentationTestCoverageReport $CI_GRADLE_ARG_PROPERTIES

Loading