Compare commits

..

1 Commits

Author SHA1 Message Date
b5817865e4 ci: Instrumentation tests coverage in ci.
Some checks failed
Check PR code / EspressoReports (pull_request) Failing after 53m12s
2025-03-18 10:37:15 +01:00
9 changed files with 50 additions and 7 deletions

View File

@ -209,6 +209,7 @@ dependencies {
androidTestUtil("androidx.test.services:test-services:1.6.0-alpha02")
testImplementation("org.robolectric:robolectric:4.14.1")
testImplementation("androidx.test:core-ktx:1.7.0-alpha01")
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
implementation("ch.acra:acra-http:$acraVersion")
implementation("ch.acra:acra-toast:$acraVersion")

View File

@ -2,6 +2,7 @@ package bou.amine.apps.readerforselfossv2.android
import android.content.Context
import androidx.annotation.ArrayRes
import androidx.test.espresso.Espresso
import androidx.test.espresso.Espresso.onData
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
@ -9,13 +10,19 @@ import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.action.ViewActions.typeTextIntoFocusedView
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.base.DefaultFailureHandler
import androidx.test.espresso.matcher.ViewMatchers.isChecked
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.Matchers.hasToString
import org.junit.Before
import java.util.Locale
fun performLogin(someUrl: String? = null) {
onView(withId(R.id.urlView)).perform(click()).perform(
@ -119,3 +126,38 @@ fun testAddSourceWithUrl(
.perform(click())
onView(withText(sourceName)).check(matches(isDisplayed()))
}
open class WithANRException {
// Running count of the number of Android Not Responding dialogues to prevent endless dismissal.
private var anrCount = 0
// `RootViewWithoutFocusException` class is private, need to match the message (instead of using type matching).
private val rootViewWithoutFocusExceptionMsg =
java.lang.String.format(
Locale.ROOT,
"Waited for the root of the view hierarchy to have " +
"window focus and not request layout for 10 seconds. If you specified a non " +
"default root matcher, it may be picking a root that never takes focus. " +
"Root:",
)
@Before
fun setUpHandler() {
Espresso.setFailureHandler { error, viewMatcher ->
if (error.message!!.contains(rootViewWithoutFocusExceptionMsg) && anrCount < 3) {
anrCount++
handleAnrDialogue()
} else { // chain all failures down to the default espresso handler
DefaultFailureHandler(getInstrumentation().targetContext).handle(error, viewMatcher)
}
}
}
private fun handleAnrDialogue() {
val device = UiDevice.getInstance(getInstrumentation())
// If running the device in English Locale
val waitButton = device.findObject(UiSelector().textContains("wait"))
if (waitButton.exists()) waitButton.click()
}
}

View File

@ -22,7 +22,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class HomeActivityTest {
class HomeActivityTest : WithANRException() {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)

View File

@ -21,7 +21,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class LoginActivityTest {
class LoginActivityTest : WithANRException() {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)

View File

@ -28,7 +28,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityGeneralTest {
class SettingsActivityGeneralTest : WithANRException() {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)

View File

@ -23,7 +23,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityOfflineTest {
class SettingsActivityOfflineTest : WithANRException() {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)

View File

@ -21,7 +21,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityReaderTest {
class SettingsActivityReaderTest : WithANRException() {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)

View File

@ -19,7 +19,7 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
@LargeTest
class SettingsActivityTest {
class SettingsActivityTest : WithANRException() {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
lateinit var context: Context

View File

@ -23,7 +23,7 @@ import java.util.UUID
@RunWith(AndroidJUnit4::class)
@LargeTest
class SourcesActivityTest {
class SourcesActivityTest : WithANRException() {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)