diff --git a/app/build.gradle b/app/build.gradle index 9f9ccfd723..b0203e60a8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -391,6 +391,7 @@ dependencies { androidTestImplementation "androidx.test.espresso:espresso-web:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-accessibility:$espressoVersion" androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion" + implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion" // Mocking support androidTestImplementation 'com.github.tmurakami:dexopener:2.0.5' // required to allow mocking on API 27 and older diff --git a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java index 0246abed0d..80ae9acffa 100644 --- a/app/src/androidTest/java/com/owncloud/android/AbstractIT.java +++ b/app/src/androidTest/java/com/owncloud/android/AbstractIT.java @@ -301,6 +301,10 @@ public abstract class AbstractIT { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); } + protected void onIdleSync(Runnable recipient) { + InstrumentationRegistry.getInstrumentation().waitForIdle(recipient); + } + protected void openDrawer(IntentsTestRule activityRule) { Activity sut = activityRule.launchActivity(null); diff --git a/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinActivityIT.kt b/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinActivityIT.kt index 42e69169b4..44f50d48e4 100644 --- a/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinActivityIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/ui/trashbin/TrashbinActivityIT.kt @@ -10,11 +10,17 @@ package com.owncloud.android.ui.trashbin import android.accounts.Account import android.accounts.AccountManager import android.content.Intent -import androidx.test.espresso.intent.rule.IntentsTestRule +import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.IdlingRegistry +import androidx.test.ext.junit.rules.ActivityScenarioRule +import com.nextcloud.utils.EspressoIdlingResource import com.owncloud.android.AbstractIT import com.owncloud.android.MainApp import com.owncloud.android.lib.common.accounts.AccountUtils import com.owncloud.android.utils.ScreenshotTest +import org.junit.After +import org.junit.Before import org.junit.Rule import org.junit.Test @@ -25,91 +31,91 @@ class TrashbinActivityIT : AbstractIT() { FILES } + private var scenario: ActivityScenario? = null + val intent = Intent(ApplicationProvider.getApplicationContext(), TrashbinActivity::class.java) + @get:Rule - var activityRule = IntentsTestRule(TrashbinActivity::class.java, true, false) + val activityRule = ActivityScenarioRule(intent) + + @Before + fun registerIdlingResource() { + IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource) + } + + @After + fun unregisterIdlingResource() { + IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource) + scenario?.close() + } @Test @ScreenshotTest fun error() { - val sut: TrashbinActivity = activityRule.launchActivity(null) - - val trashbinRepository = TrashbinLocalRepository(TestCase.ERROR) - - sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) - - sut.runOnUiThread { sut.loadFolder() } - - shortSleep() - - screenshot(sut) + scenario = activityRule.scenario + scenario?.onActivity { sut -> + val trashbinRepository = TrashbinLocalRepository(TestCase.ERROR) + sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) + onIdleSync { + sut.runOnUiThread { sut.loadFolder() } + screenshot(sut) + } + } } @Test @ScreenshotTest fun files() { - val sut: TrashbinActivity = activityRule.launchActivity(null) - - val trashbinRepository = TrashbinLocalRepository(TestCase.FILES) - - sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) - - sut.runOnUiThread { sut.loadFolder() } - - waitForIdleSync() - shortSleep() - shortSleep() - - screenshot(sut) + scenario = activityRule.scenario + scenario?.onActivity { sut -> + val trashbinRepository = TrashbinLocalRepository(TestCase.FILES) + sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) + onIdleSync { + sut.runOnUiThread { sut.loadFolder() } + screenshot(sut) + } + } } @Test @ScreenshotTest fun empty() { - val sut: TrashbinActivity = activityRule.launchActivity(null) - - val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) - - sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) - - sut.runOnUiThread { sut.loadFolder() } - - shortSleep() - shortSleep() - waitForIdleSync() - - screenshot(sut.binding.emptyList.emptyListView) + scenario = activityRule.scenario + scenario?.onActivity { sut -> + val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) + sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) + onIdleSync { + sut.runOnUiThread { sut.loadFolder() } + screenshot(sut) + } + } } @Test @ScreenshotTest fun loading() { - val sut: TrashbinActivity = activityRule.launchActivity(null) - - val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) - - sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) - - sut.runOnUiThread { sut.showInitialLoading() } - - shortSleep() - - screenshot(sut.binding.listFragmentLayout) + scenario = activityRule.scenario + scenario?.onActivity { sut -> + val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) + sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) + onIdleSync { + sut.runOnUiThread { sut.showInitialLoading() } + screenshot(sut) + } + } } @Test @ScreenshotTest fun normalUser() { - val sut: TrashbinActivity = activityRule.launchActivity(null) - - val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) - - sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) - - sut.runOnUiThread { sut.showUser() } - - shortSleep() - - screenshot(sut) + scenario = activityRule.scenario + scenario?.onActivity { sut -> + val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) + sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) + onIdleSync { + sut.runOnUiThread { sut.showUser() } + screenshot(sut) + } + } } @Test @@ -122,18 +128,18 @@ class TrashbinActivityIT : AbstractIT() { platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_OC_BASE_URL, "https://nextcloud.localhost") platformAccountManager.setUserData(temp, AccountUtils.Constants.KEY_USER_ID, "differentUser") - val intent = Intent() + val intent = Intent(targetContext, TrashbinActivity::class.java) intent.putExtra(Intent.EXTRA_USER, "differentUser@https://nextcloud.localhost") - val sut: TrashbinActivity = activityRule.launchActivity(intent) - val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) - - sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) - - sut.runOnUiThread { sut.showUser() } - - shortSleep() - - screenshot(sut) + val sutScenario = ActivityScenario.launch(intent) + sutScenario.onActivity { sut -> + sut.intent = intent + val trashbinRepository = TrashbinLocalRepository(TestCase.EMPTY) + sut.trashbinPresenter = TrashbinPresenter(trashbinRepository, sut) + onIdleSync { + sut.runOnUiThread { sut.showUser() } + screenshot(sut) + } + } } } diff --git a/app/src/main/java/com/nextcloud/utils/EspressoIdlingResource.kt b/app/src/main/java/com/nextcloud/utils/EspressoIdlingResource.kt new file mode 100644 index 0000000000..6cd8eda403 --- /dev/null +++ b/app/src/main/java/com/nextcloud/utils/EspressoIdlingResource.kt @@ -0,0 +1,27 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2024 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.nextcloud.utils + +import androidx.test.espresso.idling.CountingIdlingResource + +object EspressoIdlingResource { + + private const val RESOURCE = "GLOBAL" + + @JvmField val countingIdlingResource = CountingIdlingResource(RESOURCE) + + fun increment() { + countingIdlingResource.increment() + } + + fun decrement() { + if (!countingIdlingResource.isIdleNow) { + countingIdlingResource.decrement() + } + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt index fefa493ef3..d65d366343 100644 --- a/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt +++ b/app/src/main/java/com/owncloud/android/ui/trashbin/TrashbinActivity.kt @@ -25,6 +25,7 @@ import com.nextcloud.client.account.CurrentAccountProvider import com.nextcloud.client.di.Injectable import com.nextcloud.client.network.ClientFactory import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.utils.EspressoIdlingResource import com.owncloud.android.R import com.owncloud.android.databinding.TrashbinActivityBinding import com.owncloud.android.lib.resources.trashbin.model.TrashbinFile @@ -177,6 +178,7 @@ class TrashbinActivity : } fun loadFolder() { + EspressoIdlingResource.increment() trashbinListAdapter?.let { if (it.itemCount > EMPTY_LIST_COUNT) { binding.swipeContainingList.isRefreshing = true @@ -186,6 +188,7 @@ class TrashbinActivity : trashbinPresenter?.loadFolder() } + EspressoIdlingResource.decrement() } override fun onOptionsItemSelected(item: MenuItem): Boolean { @@ -285,19 +288,23 @@ class TrashbinActivity : @VisibleForTesting fun showInitialLoading() { + EspressoIdlingResource.increment() binding.emptyList.emptyListView.visibility = View.GONE binding.list.visibility = View.GONE binding.loadingContent.visibility = View.VISIBLE + EspressoIdlingResource.decrement() } @VisibleForTesting fun showUser() { + EspressoIdlingResource.increment() binding.loadingContent.visibility = View.GONE binding.list.visibility = View.VISIBLE binding.swipeContainingList.isRefreshing = false binding.emptyList.emptyListViewText.text = user.get().accountName binding.emptyList.emptyListViewText.visibility = View.VISIBLE binding.emptyList.emptyListView.visibility = View.VISIBLE + EspressoIdlingResource.decrement() } override fun showError(message: Int) { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 8807687f32..cb7ccf43fa 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6384,6 +6384,14 @@ + + + + + + + + @@ -7567,6 +7575,11 @@ + + + + +