diff --git a/app/src/androidTest/assets/pages/download.html b/app/src/androidTest/assets/pages/download.html index f6dd187d50..440a3b0c07 100644 --- a/app/src/androidTest/assets/pages/download.html +++ b/app/src/androidTest/assets/pages/download.html @@ -1,5 +1,10 @@ - Page content: Globe.svg + Page content: Globe.svg + diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt index 2ae01aa50e..62ba4f069a 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestHelper.kt @@ -9,6 +9,7 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Build +import android.os.Environment import androidx.preference.PreferenceManager import androidx.test.espresso.Espresso.onView import androidx.test.espresso.ViewAction @@ -25,11 +26,13 @@ import androidx.test.uiautomator.By import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until +import kotlinx.coroutines.runBlocking import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.allOf import org.mozilla.fenix.R import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.ui.robots.mDevice +import java.io.File object TestHelper { fun scrollToElementByText(text: String): UiScrollable { @@ -117,4 +120,19 @@ object TestHelper { 0 ) } + + //Remove test file from the device Downloads folder + @Suppress("Deprecation") + fun deleteDownloadFromStorage(fileName: String){ + runBlocking { + val downloadedFile = File( + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), + fileName + ) + + if (downloadedFile.exists()) { + downloadedFile.delete() + } + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index e4d676eef6..17c5f6e187 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -8,6 +8,7 @@ import android.view.View import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.IdlingRegistry import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.GrantPermissionRule import androidx.test.uiautomator.UiDevice import okhttp3.mockwebserver.MockWebServer import org.junit.After @@ -21,12 +22,15 @@ import org.mozilla.fenix.helpers.HomeActivityTestRule import org.mozilla.fenix.helpers.RecyclerViewIdlingResource import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestHelper +import org.mozilla.fenix.helpers.TestHelper.deleteDownloadFromStorage import org.mozilla.fenix.helpers.ViewVisibilityIdlingResource import org.mozilla.fenix.ui.robots.browserScreen import org.mozilla.fenix.ui.robots.clickUrlbar +import org.mozilla.fenix.ui.robots.downloadRobot import org.mozilla.fenix.ui.robots.enhancedTrackingProtection import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar +import java.io.File /** * Test Suite that contains tests defined as part of the Smoke and Sanity check defined in Test rail. @@ -39,6 +43,7 @@ class SmokeTest { private var awesomeBar: ViewVisibilityIdlingResource? = null private var searchSuggestionsIdlingResource: RecyclerViewIdlingResource? = null private var addonsListIdlingResource: RecyclerViewIdlingResource? = null + private val downloadFileName = "Globe.svg" // This finds the dialog fragment child of the homeFragment, otherwise the awesomeBar would return null private fun getAwesomebarView(): View? { @@ -51,6 +56,11 @@ class SmokeTest { @get:Rule val activityTestRule = HomeActivityTestRule() + @get:Rule + var mGrantPermissions = GrantPermissionRule.grant( + android.Manifest.permission.WRITE_EXTERNAL_STORAGE, + android.Manifest.permission.READ_EXTERNAL_STORAGE + ) @Before fun setUp() { @@ -75,6 +85,8 @@ class SmokeTest { if (addonsListIdlingResource != null) { IdlingRegistry.getInstance().unregister(addonsListIdlingResource!!) } + + deleteDownloadFromStorage(downloadFileName) } // copied over from HomeScreenTest @@ -568,4 +580,38 @@ class SmokeTest { verifyUrl("webcompat.com/issues/new") } } + + @Test + /* Verifies downloads in the Downloads Menu: + - downloads appear in the list + - deleting a download from device storage, removes it from the Downloads Menu too + */ + fun manageDownloadsInDownloadsMenuTest() { + val downloadWebPage = TestAssetHelper.getDownloadAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(downloadWebPage.url) { + mDevice.waitForIdle() + } + + downloadRobot { + verifyDownloadPrompt() + }.clickDownload { + mDevice.waitForIdle() + verifyDownloadNotificationPopup() + } + + browserScreen { + }.openThreeDotMenu { + }.openDownloadsManager { + waitForDownloadsListToExist() + verifyDownloadedFileName(downloadFileName) + verifyDownloadedFileIcon() + deleteDownloadFromStorage(downloadFileName) + }.exitDownloadsManagerToBrowser { + }.openThreeDotMenu { + }.openDownloadsManager { + verifyEmptyDownloadsList() + } + } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt index 48ccc4c2e1..8733d44010 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/DownloadRobot.kt @@ -7,7 +7,9 @@ package org.mozilla.fenix.ui.robots import android.content.Intent +import android.os.Environment import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.ViewInteraction import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers @@ -15,17 +17,24 @@ import androidx.test.espresso.matcher.RootMatchers.isDialog import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until +import kotlinx.coroutines.runBlocking import org.hamcrest.CoreMatchers +import org.hamcrest.core.StringContains.containsString +import org.junit.Assert.assertTrue import org.mozilla.fenix.R import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestHelper import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.helpers.Constants.PackageName.GOOGLE_APPS_PHOTOS +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import java.io.File /** * Implementation of Robot Pattern for download UI handling. @@ -39,6 +48,23 @@ class DownloadRobot { fun verifyPhotosAppOpens() = assertPhotosOpens() + fun verifyDownloadedFileName(fileName: String) { + mDevice.findObject(UiSelector().text(fileName)).waitForExists(waitingTime) + downloadedFile(fileName).check(matches(isDisplayed())) + } + + fun verifyDownloadedFileIcon() = assertDownloadedFileIcon() + + fun verifyEmptyDownloadsList() { + mDevice.findObject(UiSelector().resourceId("org.mozilla.fenix.debug:id/download_empty_view")) + .waitForExists(waitingTime) + onView(withText("No downloaded files")).check(matches(isDisplayed())) + } + + fun waitForDownloadsListToExist() = + assertTrue(mDevice.findObject(UiSelector().resourceId("org.mozilla.fenix.debug:id/download_list")) + .waitForExists(waitingTime)) + class Transition { fun clickDownload(interact: DownloadRobot.() -> Unit): Transition { @@ -84,6 +110,13 @@ class DownloadRobot { DownloadRobot().interact() return Transition() } + + fun exitDownloadsManagerToBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + onView(withContentDescription("Navigate up")).click() + + BrowserRobot().interact() + return BrowserRobot.Transition() + } } } @@ -125,3 +158,7 @@ private fun assertPhotosOpens() { ) } } + +private fun downloadedFile(fileName: String) = onView(withText(fileName)) + +private fun assertDownloadedFileIcon() = onView(withId(R.id.favicon)).check(matches(isDisplayed())) \ No newline at end of file diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt index 250aa25462..a32a5754e8 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NavigationToolbarRobot.kt @@ -21,6 +21,7 @@ import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withResourceName import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By @@ -99,8 +100,9 @@ class NavigationToolbarRobot { runWithIdleRes(sessionLoadedIdlingResource) { onView( anyOf( - ViewMatchers.withResourceName("browserLayout"), - ViewMatchers.withResourceName("onboarding_message") // Req ETP dialog + withResourceName("browserLayout"), + withResourceName("onboarding_message"), // Req ETP dialog + withResourceName("download_button") ) ) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt index 982fa613c3..aa0e06a211 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/ThreeDotMenuMainRobot.kt @@ -151,6 +151,14 @@ class ThreeDotMenuMainRobot { return SettingsRobot.Transition() } + fun openDownloadsManager(interact: DownloadRobot.() -> Unit): DownloadRobot.Transition { + onView(withId(R.id.mozac_browser_menu_recyclerView)).perform(swipeDown()) + downloadsButton().click() + + DownloadRobot().interact() + return DownloadRobot.Transition() + } + fun openSyncedTabs(interact: SyncedTabsRobot.() -> Unit): SyncedTabsRobot.Transition { onView(withId(R.id.mozac_browser_menu_recyclerView)).perform(ViewActions.swipeDown()) mDevice.waitNotNull(Until.findObject(By.text("Synced tabs")), waitingTime)