diff --git a/-e b/-e new file mode 100644 index 000000000..e69de29bb diff --git a/app/src/androidTest/assets/pages/audioMediaPage.html b/app/src/androidTest/assets/pages/audioMediaPage.html new file mode 100644 index 000000000..1a8720a85 --- /dev/null +++ b/app/src/androidTest/assets/pages/audioMediaPage.html @@ -0,0 +1,26 @@ + + + Audio_Test_Page + + +

Page content: audio player

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/app/src/androidTest/assets/pages/videoMediaPage.html b/app/src/androidTest/assets/pages/videoMediaPage.html new file mode 100644 index 000000000..32baa8d78 --- /dev/null +++ b/app/src/androidTest/assets/pages/videoMediaPage.html @@ -0,0 +1,26 @@ + + + Video_Test_Page + + +

Page content: video player

+
+ +
+
+
+ + + \ No newline at end of file diff --git a/app/src/androidTest/assets/resources/audioSample.mp3 b/app/src/androidTest/assets/resources/audioSample.mp3 new file mode 100644 index 000000000..eb0420a48 Binary files /dev/null and b/app/src/androidTest/assets/resources/audioSample.mp3 differ diff --git a/app/src/androidTest/assets/resources/videoSample.webm b/app/src/androidTest/assets/resources/videoSample.webm new file mode 100644 index 000000000..f9afbdde3 Binary files /dev/null and b/app/src/androidTest/assets/resources/videoSample.webm differ diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt index 672a0e165..240caaca2 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/TestAssetHelper.kt @@ -18,7 +18,7 @@ object TestAssetHelper { val waitingTime: Long = TimeUnit.SECONDS.toMillis(15) val waitingTimeShort: Long = TimeUnit.SECONDS.toMillis(1) - data class TestAsset(val url: Uri, val content: String) + data class TestAsset(val url: Uri, val content: String, val title: String) /** * Hosts 3 simple websites, found at androidTest/assets/pages/generic[1|2|3].html @@ -33,7 +33,8 @@ object TestAssetHelper { return (1..4).map { TestAsset( server.url("pages/generic$it.html").toString().toUri()!!, - "Page content: $it" + "Page content: $it", + "" ) } } @@ -41,52 +42,70 @@ object TestAssetHelper { fun getGenericAsset(server: MockWebServer, pageNum: Int): TestAsset { val url = server.url("pages/generic$pageNum.html").toString().toUri()!! val content = "Page content: $pageNum" + val title = "Test_Page_$pageNum" - return TestAsset(url, content) + return TestAsset(url, content, title) } fun getLoremIpsumAsset(server: MockWebServer): TestAsset { val url = server.url("pages/lorem-ipsum.html").toString().toUri()!! val content = "Page content: lorem ipsum" - return TestAsset(url, content) + + return TestAsset(url, content, "") } fun getRefreshAsset(server: MockWebServer): TestAsset { val url = server.url("pages/refresh.html").toString().toUri()!! val content = "Page content: refresh" - return TestAsset(url, content) + return TestAsset(url, content, "") } fun getUUIDPage(server: MockWebServer): TestAsset { val url = server.url("pages/basic_nav_uuid.html").toString().toUri()!! val content = "Page content: basic_nav_uuid" - return TestAsset(url, content) + return TestAsset(url, content, "") } fun getDownloadAsset(server: MockWebServer): TestAsset { val url = server.url("pages/download.html").toString().toUri()!! val content = "Page content: Globe.svg" - return TestAsset(url, content) + return TestAsset(url, content, "") } fun getEnhancedTrackingProtectionAsset(server: MockWebServer): TestAsset { val url = server.url("pages/etp.html").toString().toUri()!! - return TestAsset(url, "") + return TestAsset(url, "", "") } fun getImageAsset(server: MockWebServer): TestAsset { val url = server.url("resources/rabbit.jpg").toString().toUri()!! - return TestAsset(url, "") + return TestAsset(url, "", "") } fun getSaveLoginAsset(server: MockWebServer): TestAsset { val url = server.url("pages/password.html").toString().toUri()!! - return TestAsset(url, "") + return TestAsset(url, "", "") + } + + fun getAudioPageAsset(server: MockWebServer): TestAsset { + val url = server.url("pages/audioMediaPage.html").toString().toUri()!! + val title = "Audio_Test_Page" + val content = "Page content: audio player" + + return TestAsset(url, content, title) + } + + fun getVideoPageAsset(server: MockWebServer): TestAsset { + val url = server.url("pages/videoMediaPage.html").toString().toUri()!! + val title = "Video_Test_Page" + val content = "Page content: video player" + + return TestAsset(url, content, title) } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt new file mode 100644 index 000000000..67e2ad16d --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/MediaNotificationTest.kt @@ -0,0 +1,131 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.ui + +import okhttp3.mockwebserver.MockWebServer +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.mozilla.fenix.helpers.AndroidAssetDispatcher +import org.mozilla.fenix.helpers.HomeActivityTestRule +import org.mozilla.fenix.helpers.TestAssetHelper +import org.mozilla.fenix.ui.robots.browserScreen +import org.mozilla.fenix.ui.robots.homeScreen +import org.mozilla.fenix.ui.robots.mDevice +import org.mozilla.fenix.ui.robots.navigationToolbar + +/** + * Tests for verifying basic functionality of media notifications: + * - video and audio playback system notifications appear and can pause/play the media content + * - a media notification icon is displayed on the homescreen for the tab playing media content + * Note: this test only verifies media notifications, not media itself + */ +class MediaNotificationTest { + /* ktlint-disable no-blank-line-before-rbrace */ // This imposes unreadable grouping. + + private lateinit var mockWebServer: MockWebServer + + @get:Rule + val activityTestRule = HomeActivityTestRule() + + @Before + fun setUp() { + mockWebServer = MockWebServer().apply { + setDispatcher(AndroidAssetDispatcher()) + start() + } + } + + @After + fun tearDown() { + mockWebServer.shutdown() + } + + @Test + fun videoPlaybackSystemNotificationTest() { + val videoTestPage = TestAssetHelper.getVideoPageAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(videoTestPage.url) { + clickMediaPlayerPlayButton() + waitForPlaybackToStart() + }.openNotificationShade { + verifySystemNotificationExists(videoTestPage.title) + clickMediaSystemNotificationControlButton("Pause") + verifyMediaSystemNotificationButtonState("Play") + } + + mDevice.pressBack() + + browserScreen { + verifyMediaIsPaused() + } + } + + @Test + fun audioPlaybackSystemNotificationTest() { + val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(audioTestPage.url) { + verifyPageContent(audioTestPage.content) + clickMediaPlayerPlayButton() + waitForPlaybackToStart() + }.openNotificationShade { + verifySystemNotificationExists(audioTestPage.title) + clickMediaSystemNotificationControlButton("Pause") + verifyMediaSystemNotificationButtonState("Play") + } + + mDevice.pressBack() + + browserScreen { + verifyMediaIsPaused() + } + } + + @Test + fun tabMediaControlButtonTest() { + val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer) + + navigationToolbar { + }.enterURLAndEnterToBrowser(audioTestPage.url) { + verifyPageContent(audioTestPage.content) + clickMediaPlayerPlayButton() + waitForPlaybackToStart() + }.openHomeScreen { + verifyTabMediaControlButtonState("Pause") + clickTabMediaControlButton() + verifyTabMediaControlButtonState("Play") + }.openTab(audioTestPage.title) { + verifyMediaIsPaused() + } + } + + @Test + fun mediaSystemNotificationInPrivateModeTest() { + val audioTestPage = TestAssetHelper.getAudioPageAsset(mockWebServer) + + homeScreen { }.togglePrivateBrowsingMode() + + navigationToolbar { + }.enterURLAndEnterToBrowser(audioTestPage.url) { + verifyPageContent(audioTestPage.content) + clickMediaPlayerPlayButton() + waitForPlaybackToStart() + }.openNotificationShade { + verifySystemNotificationExists("A site is playing media") + clickMediaSystemNotificationControlButton("Pause") + verifyMediaSystemNotificationButtonState("Play") + } + + mDevice.pressBack() + + browserScreen { + verifyMediaIsPaused() + } + } +} diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt index 09244e360..d48856747 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt @@ -19,6 +19,7 @@ import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.ext.waitNotNull import org.mozilla.fenix.ui.robots.homeScreen import org.mozilla.fenix.ui.robots.navigationToolbar +import org.mozilla.fenix.ui.robots.notificationShade /** * Tests for verifying basic functionality of tabbed browsing @@ -259,6 +260,9 @@ class TabbedBrowsingTest { navigationToolbar { }.enterURLAndEnterToBrowser(defaultWebPage.url) { mDevice.openNotification() + } + + notificationShade { verifyPrivateTabsNotification() }.clickClosePrivateTabsNotification { verifyPrivateSessionMessage() diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt index 33f78df17..7b2cda964 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/BrowserRobot.kt @@ -26,6 +26,7 @@ import androidx.test.uiautomator.By.text import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until +import androidx.test.uiautomator.Until.hasObject import org.hamcrest.CoreMatchers.allOf import org.hamcrest.CoreMatchers.containsString import org.junit.Assert.assertTrue @@ -34,6 +35,7 @@ import org.mozilla.fenix.ext.components import org.mozilla.fenix.helpers.Constants.LongClickDuration import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTimeShort import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull @@ -57,7 +59,7 @@ class BrowserRobot { ) TestAssetHelper.waitingTime onView(withId(R.id.mozac_browser_toolbar_url_view)) - .check(matches(withText(containsString(url.replace("http://", ""))))) + .check(matches(withText(containsString(url.replace("http://", ""))))) } fun verifyHelpUrl() { @@ -145,11 +147,6 @@ class BrowserRobot { ) } - fun verifyPrivateTabsNotification() { - mDevice.wait(Until.hasObject(text("Close private tabs")), waitingTime) - assertPrivateTabsNotification() - } - fun clickContextOpenLinkInNewTab() { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mDevice.waitNotNull( @@ -289,6 +286,36 @@ class BrowserRobot { mDevice.findObject(text(optionToSaveLogin)).click() } + fun clickMediaPlayerPlayButton() { + mDevice.waitNotNull( + hasObject( + By + .clazz("android.widget.Button") + .textContains("Play") + ), + waitingTime + ) + mediaPlayerPlayButton().click() + } + + fun waitForPlaybackToStart() { + mDevice.waitNotNull( + hasObject( + text("Media file is playing") + ), waitingTimeShort + ) + } + + fun verifyMediaIsPaused() { + mDevice.waitNotNull( + hasObject( + text("Media file is paused") + ), waitingTimeShort + ) + + mDevice.findObject(UiSelector().text("Media file is paused")).exists() + } + class Transition { private val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) private fun threeDotButton() = onView( @@ -329,12 +356,11 @@ class BrowserRobot { return HomeScreenRobot.Transition() } - fun clickClosePrivateTabsNotification(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { - mDevice.wait(Until.hasObject(text("Close private tabs")), waitingTime) - closePrivateTabsNotification().clickAndWaitForNewWindow(waitingTime) + fun openNotificationShade(interact: NotificationRobot.() -> Unit): NotificationRobot.Transition { + mDevice.openNotification() - HomeScreenRobot().interact() - return HomeScreenRobot.Transition() + NotificationRobot().interact() + return NotificationRobot.Transition() } } } @@ -355,10 +381,9 @@ fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view)) private fun tabsCounter() = onView(withId(R.id.mozac_browser_toolbar_browser_actions)) -private fun closePrivateTabsNotification() = - mDevice.findObject(UiSelector().text("Close private tabs")) - -private fun assertPrivateTabsNotification() { - mDevice.findObject(UiSelector().text("Firefox Preview (Private)")).exists() - mDevice.findObject(UiSelector().text("Close private tabs")).exists() -} +private fun mediaPlayerPlayButton() = + mDevice.findObject( + By + .clazz("android.widget.Button") + .textContains("Play") + ) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt index d23e68e0a..b87c4e3cb 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/HomeScreenRobot.kt @@ -6,8 +6,8 @@ package org.mozilla.fenix.ui.robots -import androidx.recyclerview.widget.RecyclerView import android.graphics.Bitmap +import androidx.recyclerview.widget.RecyclerView import androidx.test.espresso.Espresso.onView import androidx.test.espresso.action.ViewActions import androidx.test.espresso.action.ViewActions.click @@ -16,30 +16,32 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem import androidx.test.espresso.matcher.ViewMatchers -import androidx.test.espresso.matcher.ViewMatchers.withId -import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.Visibility import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withContentDescription import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.platform.app.InstrumentationRegistry import androidx.test.uiautomator.By +import androidx.test.uiautomator.By.text import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiScrollable import androidx.test.uiautomator.UiSelector import androidx.test.uiautomator.Until -import org.hamcrest.CoreMatchers.containsString +import androidx.test.uiautomator.Until.findObject import org.hamcrest.CoreMatchers.allOf +import org.hamcrest.CoreMatchers.containsString import org.hamcrest.CoreMatchers.not import org.mozilla.fenix.R +import org.mozilla.fenix.components.Search import org.mozilla.fenix.helpers.TestAssetHelper import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime import org.mozilla.fenix.helpers.click import org.mozilla.fenix.helpers.ext.waitNotNull -import org.mozilla.fenix.components.Search -import org.mozilla.fenix.helpers.withBitmapDrawable import org.mozilla.fenix.helpers.matchers.hasItem +import org.mozilla.fenix.helpers.withBitmapDrawable /** * Implementation of Robot Pattern for the home screen menu. @@ -168,7 +170,8 @@ class HomeScreenRobot { fun swipeToBottom() = onView(withId(R.id.homeLayout)).perform(ViewActions.swipeUp()) - fun swipeToTop() = onView(withId(R.id.sessionControlRecyclerView)).perform(ViewActions.swipeDown()) + fun swipeToTop() = + onView(withId(R.id.sessionControlRecyclerView)).perform(ViewActions.swipeDown()) fun swipeTabRight(title: String) = onView(allOf(withId(R.id.tab_title), withText(title))).perform(ViewActions.swipeRight()) @@ -185,10 +188,21 @@ class HomeScreenRobot { fun snackBarButtonClick(expectedText: String) { onView(allOf(withId(R.id.snackbar_btn), withText(expectedText))).check( - matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)) - ).perform(ViewActions.click()) + matches(withEffectiveVisibility(Visibility.VISIBLE)) + ).perform(click()) } + fun verifyTabMediaControlButtonState(action: String) { + mDevice.waitNotNull( + Until.findObject(By.res("org.mozilla.fenix.debug:id/play_pause_button")), + waitingTime + ) + + tabMediaControlButton().check(matches(withContentDescription(action))) + } + + fun clickTabMediaControlButton() = tabMediaControlButton().click() + class Transition { val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) @@ -242,16 +256,25 @@ class HomeScreenRobot { return NavigationToolbarRobot.Transition() } - fun openContextMenuOnTopSitesWithTitle(title: String, interact: HomeScreenRobot.() -> Unit): Transition { + fun openContextMenuOnTopSitesWithTitle( + title: String, + interact: HomeScreenRobot.() -> Unit + ): Transition { onView(withId(R.id.top_sites_list)).perform( - actionOnItem(hasDescendant(withText(title)), ViewActions.longClick()) + actionOnItem( + hasDescendant(withText(title)), + ViewActions.longClick() + ) ) HomeScreenRobot().interact() return Transition() } - fun openTopSiteTabWithTitle(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + fun openTopSiteTabWithTitle( + title: String, + interact: BrowserRobot.() -> Unit + ): BrowserRobot.Transition { onView(withId(R.id.top_sites_list)).perform( actionOnItem(hasDescendant(withText(title)), click()) ) @@ -280,7 +303,20 @@ class HomeScreenRobot { fun openCommonMythsLink(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { onView(withId(R.id.private_session_common_myths)) - .perform(click()) + .perform(click()) + + BrowserRobot().interact() + return BrowserRobot.Transition() + } + + fun openTab(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition { + mDevice.waitNotNull(findObject(text(title))) + onView( + allOf( + withId(R.id.tab_title), + withText(title) + ) + ).click() BrowserRobot().interact() return BrowserRobot.Transition() @@ -355,12 +391,12 @@ private fun assertCollectionsHeaderIsNotVisible() = .check(doesNotExist()) private fun assertNoCollectionsText() = - onView( - allOf( - withText("Collect the things that matter to you. To start, save open tabs to a new collection.") - ) + onView( + allOf( + withText("Collect the things that matter to you. To start, save open tabs to a new collection.") ) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) + ) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertNoCollectionsTextIsNotVisible() = onView( @@ -370,8 +406,9 @@ private fun assertNoCollectionsTextIsNotVisible() = ) .check(doesNotExist()) -private fun assertHomeComponent() = onView(ViewMatchers.withResourceName("sessionControlRecyclerView")) - .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) +private fun assertHomeComponent() = + onView(ViewMatchers.withResourceName("sessionControlRecyclerView")) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun threeDotButton() = onView(allOf(withId(R.id.menuButton))) @@ -485,10 +522,10 @@ private fun assertPrivacyNoticeButton() = // What's new elements private fun assertWhatsNewHeather() = onView(allOf(withText("See what’s new"))) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertWhatsNewLink() = onView(allOf(withText("Get answers here"))) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) private fun assertStartBrowsingButton() = onView(allOf(withText("Start browsing"))) @@ -496,18 +533,20 @@ private fun assertStartBrowsingButton() = // Take a position private fun assertTakePositionheader() = onView(allOf(withText("Take a position"))) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun assertTakePositionTopRadioButton() = onView(ViewMatchers.withResourceName("toolbar_top_radio_button")) +private fun assertTakePositionTopRadioButton() = + onView(ViewMatchers.withResourceName("toolbar_top_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) -private fun assertTakePositionBottomRadioButton() = onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button")) +private fun assertTakePositionBottomRadioButton() = + onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button")) .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) // Private mode elements private fun assertPrivateSessionHeader() = onView(allOf(withText("Private tabs"))) - .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) + .check(matches(withEffectiveVisibility(Visibility.VISIBLE))) const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " + "when you quit the app or close all private tabs. While this doesn’t make you anonymous to websites or " + @@ -521,9 +560,11 @@ private fun assertPrivateSessionMessage(visible: Boolean) = ) private fun assertShareTabsButton(visible: Boolean) = onView(allOf(withId(R.id.share_tabs_button))) - .check( - if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else matches(withEffectiveVisibility(Visibility.INVISIBLE)) + .check( + if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else matches( + withEffectiveVisibility(Visibility.INVISIBLE) ) + ) private fun assertCloseTabsButton(title: String) = onView(allOf(withId(R.id.close_tab_button), withContentDescription("Close tab $title"))) @@ -588,3 +629,5 @@ private fun assertTopSiteContextMenuItems() { waitingTime ) } + +private fun tabMediaControlButton() = onView(withId(R.id.play_pause_button)) diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt new file mode 100644 index 000000000..879bf029c --- /dev/null +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/robots/NotificationRobot.kt @@ -0,0 +1,83 @@ +package org.mozilla.fenix.ui.robots + +import android.content.res.Resources +import androidx.test.uiautomator.By.text +import androidx.test.uiautomator.UiScrollable +import androidx.test.uiautomator.UiSelector +import androidx.test.uiautomator.Until +import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime +import org.mozilla.fenix.helpers.ext.waitNotNull + +class NotificationRobot { + + fun verifySystemNotificationExists(notificationMessage: String) { + + fun notificationTray() = UiScrollable( + UiSelector().resourceId("com.android.systemui:id/notification_stack_scroller") + ) + + mDevice.waitNotNull( + Until.hasObject(text(notificationMessage)), + waitingTime + ) + + var notificationFound = false + while (!notificationFound) { + try { + val notification = notificationTray().getChildByText( + UiSelector().text(notificationMessage), notificationMessage, + true + ) + notification.exists() + notificationFound = true + } catch (e: Resources.NotFoundException) { + e.printStackTrace() + } + } + } + + fun verifyPrivateTabsNotification() { + mDevice.waitNotNull(Until.hasObject(text("Close private tabs")), waitingTime) + assertPrivateTabsNotification() + } + + fun clickMediaSystemNotificationControlButton(action: String) { + mediaSystemNotificationButton(action).waitForExists(waitingTime) + mediaSystemNotificationButton(action).click() + } + + fun verifyMediaSystemNotificationButtonState(action: String) { + mediaSystemNotificationButton(action).waitForExists(waitingTime) + } + + class Transition { + + fun clickClosePrivateTabsNotification(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition { + NotificationRobot().verifySystemNotificationExists("Close private tabs") + closePrivateTabsNotification().clickAndWaitForNewWindow() + + HomeScreenRobot().interact() + return HomeScreenRobot.Transition() + } + } +} + +fun notificationShade(interact: NotificationRobot.() -> Unit): NotificationRobot.Transition { + NotificationRobot().interact() + return NotificationRobot.Transition() +} + +private fun assertPrivateTabsNotification() { + mDevice.findObject(UiSelector().text("Firefox Preview (Private)")).exists() + mDevice.findObject(UiSelector().text("Close private tabs")).exists() +} + +private fun closePrivateTabsNotification() = + mDevice.findObject(UiSelector().text("Close private tabs")) + +private fun mediaSystemNotificationButton(action: String) = + mDevice.findObject( + UiSelector() + .resourceId("android:id/action0") + .descriptionContains(action) + )