1
0
Fork 0

Updated the method to verify system notifications and added new tests for media notifications (#9330)

master
Oana Horvath 2020-03-31 21:11:41 +03:00 committed by GitHub
parent cee34893ed
commit 5f68d6cb29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 413 additions and 56 deletions

0
-e 100644
View File

View File

@ -0,0 +1,26 @@
<html>
<head>
<title>Audio_Test_Page</title>
</head>
<body>
<p id="testContent">Page content: audio player</p>
<div class="audioPlayer">
<audio id="audioSample" controls loop>
<source src="../resources/audioSample.mp3">
</audio>
</div>
<div class="playbackState">
</div>
<script>
const audio = document.querySelector('audio');
audio.addEventListener('playing', (event) => {
document.querySelector('.playbackState').innerText="Media file is playing"
});
audio.addEventListener('pause', (event) => {
document.querySelector('.playbackState').innerText="Media file is paused"
});
</script>
</body>
</html>

View File

@ -0,0 +1,26 @@
<html>
<head>
<title>Video_Test_Page</title>
</head>
<body>
<p id="testContent">Page content: video player</p>
<div id="video-container">
<video id="videoSample" width="320" height="240" controls loop>
<source src="../resources/videoSample.webm">
</video>
</div>
<div class="playbackState">
</div>
<script>
const video = document.querySelector('video');
video.addEventListener('playing', (event) => {
document.querySelector('.playbackState').innerText="Media file is playing";
});
video.addEventListener('pause', (event) => {
document.querySelector('.playbackState').innerHTML="Media file is paused";
});
</script>
</body>
</html>

View File

@ -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)
}
}

View File

@ -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()
}
}
}

View File

@ -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()

View File

@ -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")
)

View File

@ -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<RecyclerView.ViewHolder>(hasDescendant(withText(title)), ViewActions.longClick())
actionOnItem<RecyclerView.ViewHolder>(
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<RecyclerView.ViewHolder>(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 whats 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 doesnt 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))

View File

@ -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)
)