Compare commits
	
		
			1 Commits
		
	
	
		
			br
			...
			6626784e8b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6626784e8b | 
@@ -48,7 +48,7 @@ jobs:
 | 
			
		||||
            adb logcat -G 16M
 | 
			
		||||
            ./gradlew JacocoDebugCodeCoverage || true
 | 
			
		||||
            ./gradlew androidApp:fetchScreenshots
 | 
			
		||||
            adb logcat 'InputReader:S' 'chatty:S' 'audio_hw_generic:S' '*:I' -d > ./androidApp/build/reports/androidTests/connected/screenshots/logs.txt
 | 
			
		||||
            adb logcat 'InputReader:S' 'chatty:S' 'audio_hw_generic:S' 'LogApiCalls:D' '*:I' -d > ./androidApp/build/reports/androidTests/connected/screenshots/logs.txt
 | 
			
		||||
      - uses: actions/upload-artifact@v3
 | 
			
		||||
        if: always()
 | 
			
		||||
        with:
 | 
			
		||||
 
 | 
			
		||||
@@ -93,5 +93,6 @@ class `1-LoginActivityTest` : WithANRException() {
 | 
			
		||||
        performLogin()
 | 
			
		||||
        onView(withText(R.string.gdpr_dialog_title)).check(matches(isDisplayed()))
 | 
			
		||||
        onView(withText("OK")).perform(click())
 | 
			
		||||
        checkHomeLoadingDone()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.IdlingRegistry
 | 
			
		||||
import androidx.test.espresso.action.ViewActions
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.assertion.ViewAssertions.matches
 | 
			
		||||
@@ -14,7 +15,9 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
 | 
			
		||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
			
		||||
import androidx.test.filters.LargeTest
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
 | 
			
		||||
import org.hamcrest.CoreMatchers.not
 | 
			
		||||
import org.junit.Before
 | 
			
		||||
import org.junit.FixMethodOrder
 | 
			
		||||
import org.junit.Rule
 | 
			
		||||
import org.junit.Test
 | 
			
		||||
@@ -29,6 +32,14 @@ class `2-HomeActivityTest` : WithANRException() {
 | 
			
		||||
    @get:Rule
 | 
			
		||||
    val activityRule = ActivityScenarioRule(HomeActivity::class.java)
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    fun registerIdlingResource() {
 | 
			
		||||
        IdlingRegistry
 | 
			
		||||
            .getInstance()
 | 
			
		||||
            .register(CountingIdlingResourceSingleton.countingIdlingResource)
 | 
			
		||||
        checkHomeLoadingDone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    fun testMenu() {
 | 
			
		||||
        onView(withId(R.id.action_search)).check(matches(isDisplayed())).check(
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.IdlingRegistry
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.assertion.ViewAssertions.matches
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 | 
			
		||||
@@ -10,6 +11,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
 | 
			
		||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
			
		||||
import androidx.test.filters.LargeTest
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
 | 
			
		||||
import org.hamcrest.CoreMatchers.allOf
 | 
			
		||||
import org.hamcrest.CoreMatchers.not
 | 
			
		||||
import org.junit.Before
 | 
			
		||||
@@ -31,6 +33,9 @@ class `3-SettingsActivityTest` : WithANRException() {
 | 
			
		||||
        activityRule.scenario.onActivity { activity ->
 | 
			
		||||
            context = activity.window.context
 | 
			
		||||
        }
 | 
			
		||||
        IdlingRegistry
 | 
			
		||||
            .getInstance()
 | 
			
		||||
            .register(CountingIdlingResourceSingleton.countingIdlingResource)
 | 
			
		||||
        openMenu()
 | 
			
		||||
        onView(withText(R.string.title_activity_settings)).perform(click())
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
import androidx.test.core.app.ApplicationProvider
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
 | 
			
		||||
import androidx.test.espresso.IdlingRegistry
 | 
			
		||||
import androidx.test.espresso.action.ViewActions
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.replaceText
 | 
			
		||||
@@ -19,6 +20,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
 | 
			
		||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
			
		||||
import androidx.test.filters.LargeTest
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
 | 
			
		||||
import org.hamcrest.CoreMatchers.allOf
 | 
			
		||||
import org.hamcrest.CoreMatchers.not
 | 
			
		||||
import org.junit.Before
 | 
			
		||||
@@ -38,6 +40,9 @@ class `4-SettingsActivityGeneralTest` : WithANRException() {
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    fun init() {
 | 
			
		||||
        IdlingRegistry
 | 
			
		||||
            .getInstance()
 | 
			
		||||
            .register(CountingIdlingResourceSingleton.countingIdlingResource)
 | 
			
		||||
        openActionBarOverflowOrOptionsMenu(
 | 
			
		||||
            ApplicationProvider.getApplicationContext(),
 | 
			
		||||
        )
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.IdlingRegistry
 | 
			
		||||
import androidx.test.espresso.action.ViewActions
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.assertion.ViewAssertions.matches
 | 
			
		||||
@@ -13,6 +14,7 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
			
		||||
import androidx.test.filters.LargeTest
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
 | 
			
		||||
import org.hamcrest.CoreMatchers.allOf
 | 
			
		||||
import org.hamcrest.CoreMatchers.not
 | 
			
		||||
import org.junit.After
 | 
			
		||||
@@ -35,6 +37,9 @@ class `5-SettingsActivityReaderTest` : WithANRException() {
 | 
			
		||||
        activityRule.scenario.onActivity { activity ->
 | 
			
		||||
            context = activity.window.context
 | 
			
		||||
        }
 | 
			
		||||
        IdlingRegistry
 | 
			
		||||
            .getInstance()
 | 
			
		||||
            .register(CountingIdlingResourceSingleton.countingIdlingResource)
 | 
			
		||||
        onView(withText(R.string.pref_header_viewer)).perform(click())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.IdlingRegistry
 | 
			
		||||
import androidx.test.espresso.action.ViewActions
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.assertion.ViewAssertions.matches
 | 
			
		||||
@@ -15,6 +16,7 @@ import androidx.test.ext.junit.rules.ActivityScenarioRule
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
			
		||||
import androidx.test.filters.LargeTest
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
 | 
			
		||||
import org.hamcrest.CoreMatchers.allOf
 | 
			
		||||
import org.hamcrest.CoreMatchers.not
 | 
			
		||||
import org.junit.After
 | 
			
		||||
@@ -37,6 +39,9 @@ class `6-SettingsActivityOfflineTest` : WithANRException() {
 | 
			
		||||
        activityRule.scenario.onActivity { activity ->
 | 
			
		||||
            context = activity.window.context
 | 
			
		||||
        }
 | 
			
		||||
        IdlingRegistry
 | 
			
		||||
            .getInstance()
 | 
			
		||||
            .register(CountingIdlingResourceSingleton.countingIdlingResource)
 | 
			
		||||
        onView(withText(R.string.pref_header_offline)).perform(click())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ package bou.amine.apps.readerforselfossv2.android
 | 
			
		||||
 | 
			
		||||
import androidx.test.espresso.AmbiguousViewMatcherException
 | 
			
		||||
import androidx.test.espresso.Espresso.onView
 | 
			
		||||
import androidx.test.espresso.IdlingRegistry
 | 
			
		||||
import androidx.test.espresso.action.ViewActions
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.click
 | 
			
		||||
import androidx.test.espresso.action.ViewActions.swipeDown
 | 
			
		||||
@@ -14,6 +15,7 @@ import androidx.test.espresso.matcher.ViewMatchers.withText
 | 
			
		||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
 | 
			
		||||
import androidx.test.ext.junit.runners.AndroidJUnit4
 | 
			
		||||
import androidx.test.filters.LargeTest
 | 
			
		||||
import bou.amine.apps.readerforselfossv2.android.testing.CountingIdlingResourceSingleton
 | 
			
		||||
import org.junit.After
 | 
			
		||||
import org.junit.Before
 | 
			
		||||
import org.junit.Rule
 | 
			
		||||
@@ -32,6 +34,9 @@ class `7-SourcesActivityTest` : WithANRException() {
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    fun init() {
 | 
			
		||||
        IdlingRegistry
 | 
			
		||||
            .getInstance()
 | 
			
		||||
            .register(CountingIdlingResourceSingleton.countingIdlingResource)
 | 
			
		||||
        sourceName = UUID.randomUUID().toString().substring(0, 15)
 | 
			
		||||
 | 
			
		||||
        goToSources()
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ 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.RootMatchers.isDialog
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.isChecked
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.isNotChecked
 | 
			
		||||
@@ -24,6 +25,7 @@ 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.CoreMatchers.not
 | 
			
		||||
import org.hamcrest.Matchers.hasToString
 | 
			
		||||
import org.junit.BeforeClass
 | 
			
		||||
import java.io.BufferedOutputStream
 | 
			
		||||
@@ -139,6 +141,10 @@ fun testAddSourceWithUrl(
 | 
			
		||||
    onView(withText(sourceName)).check(matches(isDisplayed()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun checkHomeLoadingDone() {
 | 
			
		||||
    onView(withId(R.id.swipeRefreshLayout)).inRoot(not(isDialog())).perform(waitUntilNotLoading(300000))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Suppress("detekt:UtilityClassWithPublicConstructor")
 | 
			
		||||
open class WithANRException {
 | 
			
		||||
    companion object {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,14 @@ import android.widget.RelativeLayout
 | 
			
		||||
import androidx.annotation.DrawableRes
 | 
			
		||||
import androidx.annotation.StringRes
 | 
			
		||||
import androidx.core.graphics.drawable.toBitmap
 | 
			
		||||
import androidx.core.view.isVisible
 | 
			
		||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
 | 
			
		||||
import androidx.test.core.app.ApplicationProvider
 | 
			
		||||
import androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu
 | 
			
		||||
import androidx.test.espresso.PerformException
 | 
			
		||||
import androidx.test.espresso.Root
 | 
			
		||||
import androidx.test.espresso.UiController
 | 
			
		||||
import androidx.test.espresso.ViewAction
 | 
			
		||||
import androidx.test.espresso.matcher.RootMatchers.isPlatformPopup
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.hasSibling
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withChild
 | 
			
		||||
@@ -19,11 +24,15 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withParent
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withResourceName
 | 
			
		||||
import androidx.test.espresso.matcher.ViewMatchers.withText
 | 
			
		||||
import androidx.test.espresso.util.HumanReadables
 | 
			
		||||
import androidx.test.espresso.util.TreeIterables
 | 
			
		||||
import org.hamcrest.CoreMatchers.allOf
 | 
			
		||||
import org.hamcrest.CoreMatchers.any
 | 
			
		||||
import org.hamcrest.Description
 | 
			
		||||
import org.hamcrest.Matcher
 | 
			
		||||
import org.hamcrest.Matchers
 | 
			
		||||
import org.hamcrest.TypeSafeMatcher
 | 
			
		||||
import java.util.concurrent.TimeoutException
 | 
			
		||||
 | 
			
		||||
fun withError(
 | 
			
		||||
    @StringRes id: Int,
 | 
			
		||||
@@ -44,6 +53,47 @@ fun withError(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun waitUntilNotLoading(millis: Long): ViewAction {
 | 
			
		||||
    return object : ViewAction {
 | 
			
		||||
        override fun getConstraints(): Matcher<View> = any(View::class.java)
 | 
			
		||||
 | 
			
		||||
        override fun getDescription(): String = "wait for a specific view is not loading during $millis millis."
 | 
			
		||||
 | 
			
		||||
        override fun perform(
 | 
			
		||||
            uiController: UiController,
 | 
			
		||||
            view: View?,
 | 
			
		||||
        ) {
 | 
			
		||||
            uiController.loopMainThreadUntilIdle()
 | 
			
		||||
            val startTime = System.currentTimeMillis()
 | 
			
		||||
            val endTime = startTime + millis
 | 
			
		||||
 | 
			
		||||
            do {
 | 
			
		||||
                // either the empty view is displayed
 | 
			
		||||
                for (child in TreeIterables.breadthFirstViewTraversal(view)) {
 | 
			
		||||
                    // found view with required ID
 | 
			
		||||
                    if (withId(R.id.emptyText).matches(child) && child.isVisible) {
 | 
			
		||||
                        return
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // or the refresh layout is refreshing
 | 
			
		||||
                if (view is SwipeRefreshLayout && !view.isRefreshing) {
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                uiController.loopMainThreadForAtLeast(100)
 | 
			
		||||
            } while (System.currentTimeMillis() < endTime)
 | 
			
		||||
 | 
			
		||||
            // timeout happens
 | 
			
		||||
            throw PerformException
 | 
			
		||||
                .Builder()
 | 
			
		||||
                .withActionDescription(this.description)
 | 
			
		||||
                .withViewDescription(HumanReadables.describe(view))
 | 
			
		||||
                .withCause(TimeoutException())
 | 
			
		||||
                .build()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fun isPopupWindow(): Matcher<Root> = isPlatformPopup()
 | 
			
		||||
 | 
			
		||||
fun withDrawable(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user