HomeScreenRobot.kt 30.1 KB
Newer Older
Kevin Brosnan's avatar
Kevin Brosnan committed
1
2
3
4
5
6
7
8
/* 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/. */

@file:Suppress("TooManyFunctions")

package org.mozilla.fenix.ui.robots

9
import android.graphics.Bitmap
10
import android.widget.EditText
11
import androidx.recyclerview.widget.RecyclerView
Kevin Brosnan's avatar
Kevin Brosnan committed
12
import androidx.test.espresso.Espresso.onView
13
import androidx.test.espresso.NoMatchingViewException
14
import androidx.test.espresso.action.ViewActions
15
import androidx.test.espresso.action.ViewActions.click
16
17
18
import androidx.test.espresso.action.ViewActions.longClick
import androidx.test.espresso.action.ViewActions.swipeLeft
import androidx.test.espresso.action.ViewActions.swipeRight
19
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
Kevin Brosnan's avatar
Kevin Brosnan committed
20
import androidx.test.espresso.assertion.ViewAssertions.matches
21
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItem
Kevin Brosnan's avatar
Kevin Brosnan committed
22
import androidx.test.espresso.matcher.ViewMatchers
23
import androidx.test.espresso.matcher.ViewMatchers.Visibility
24
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
25
import androidx.test.espresso.matcher.ViewMatchers.hasSibling
26
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
27
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
28
import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility
mcarare's avatar
mcarare committed
29
import androidx.test.espresso.matcher.ViewMatchers.withHint
30
31
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
32
import androidx.test.platform.app.InstrumentationRegistry
33
import androidx.test.uiautomator.By
34
import androidx.test.uiautomator.By.text
35
import androidx.test.uiautomator.UiDevice
36
37
import androidx.test.uiautomator.UiScrollable
import androidx.test.uiautomator.UiSelector
38
import androidx.test.uiautomator.Until
39
import androidx.test.uiautomator.Until.findObject
40
import mozilla.components.support.ktx.android.content.appName
41
import org.hamcrest.CoreMatchers.allOf
42
import org.hamcrest.CoreMatchers.containsString
43
import org.hamcrest.CoreMatchers.instanceOf
44
import org.hamcrest.CoreMatchers.not
45
import org.hamcrest.Matchers
mcarare's avatar
mcarare committed
46
import org.junit.Assert
47
import org.mozilla.fenix.R
48
import org.mozilla.fenix.components.Search
49
import org.mozilla.fenix.helpers.TestAssetHelper
50
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
51
import org.mozilla.fenix.helpers.TestHelper.scrollToElementByText
52
import org.mozilla.fenix.helpers.click
53
import org.mozilla.fenix.helpers.ext.waitNotNull
54
import org.mozilla.fenix.helpers.matchers.hasItem
55
import org.mozilla.fenix.helpers.withBitmapDrawable
Kevin Brosnan's avatar
Kevin Brosnan committed
56

57
58
59
/**
 * Implementation of Robot Pattern for the home screen menu.
 */
Kevin Brosnan's avatar
Kevin Brosnan committed
60
class HomeScreenRobot {
61
62
63
64
65
66
    val privateSessionMessage =
        "${appContext.appName} clears your search and browsing history from private tabs when you close them" +
                " or quit the app. While this doesn’t make you anonymous to websites or your internet" +
                " service provider, it makes it easier to keep what you do online private from anyone" +
                " else who uses this device."

67
    fun verifyNavigationToolbar() = assertNavigationToolbar()
mcarare's avatar
mcarare committed
68
    fun verifyFocusedNavigationToolbar() = assertFocusedNavigationToolbar()
69
70
71
    fun verifyHomeScreen() = assertHomeScreen()
    fun verifyHomePrivateBrowsingButton() = assertHomePrivateBrowsingButton()
    fun verifyHomeMenu() = assertHomeMenu()
72
    fun verifyTabButton() = assertTabButton()
73
74
75
    fun verifyCollectionsHeader() = assertCollectionsHeader()
    fun verifyNoCollectionsHeader() = assertNoCollectionsHeader()
    fun verifyNoCollectionsText() = assertNoCollectionsText()
76
77
78
    fun verifyHomeWordmark() = assertHomeWordmark()
    fun verifyHomeToolbar() = assertHomeToolbar()
    fun verifyHomeComponent() = assertHomeComponent()
79
    fun verifyDefaultSearchEngine(searchEngine: String) = verifySearchEngineIcon(searchEngine)
80
    fun verifyNoTabsOpened() = assertNoTabsOpened()
mcarare's avatar
mcarare committed
81
    fun verifyKeyboardVisible() = assertKeyboardVisibility(isExpectedToBeVisible = true)
82

83
84
    // First Run elements
    fun verifyWelcomeHeader() = assertWelcomeHeader()
85

86
    fun verifyStartSyncHeader() = assertStartSyncHeader()
87
88
89
90
91
92
93
94
95
96
    fun verifyAccountsSignInButton() = assertAccountsSignInButton()
    fun verifyGetToKnowHeader() = assertGetToKnowHeader()
    fun verifyChooseThemeHeader() = assertChooseThemeHeader()
    fun verifyChooseThemeText() = assertChooseThemeText()
    fun verifyLightThemeToggle() = assertLightThemeToggle()
    fun verifyLightThemeDescription() = assertLightThemeDescription()
    fun verifyDarkThemeToggle() = assertDarkThemeToggle()
    fun verifyDarkThemeDescription() = assertDarkThemeDescription()
    fun verifyAutomaticThemeToggle() = assertAutomaticThemeToggle()
    fun verifyAutomaticThemeDescription() = assertAutomaticThemeDescription()
97
    fun verifyAutomaticPrivacyHeader() = assertAutomaticPrivacyHeader()
98
    fun verifyTrackingProtectionToggle() = assertTrackingProtectionToggle()
99
    fun verifyAutomaticPrivacyText() = assertAutomaticPrivacyText()
100

101
    // Browse privately
102
103
    fun verifyBrowsePrivatelyHeader() = assertBrowsePrivatelyHeader()
    fun verifyBrowsePrivatelyText() = assertBrowsePrivatelyText()
104
105
106
107
108
109
110
111
112

    // Take a position
    fun verifyTakePositionHeader() = assertTakePositionheader()
    fun verifyTakePositionElements() {
        assertTakePositionBottomRadioButton()
        assertTakePositionTopRadioButton()
    }

    // Your privacy
113
114
115
116
117
    fun verifyYourPrivacyHeader() = assertYourPrivacyHeader()
    fun verifyYourPrivacyText() = assertYourPrivacyText()
    fun verifyPrivacyNoticeButton() = assertPrivacyNoticeButton()
    fun verifyStartBrowsingButton() = assertStartBrowsingButton()

118
    fun verifyPrivateSessionMessage() = assertPrivateSessionMessage()
119

120
121
122
123
124
    fun verifyExistingTopSitesList() = assertExistingTopSitesList()
    fun verifyNotExistingTopSitesList(title: String) = assertNotExistingTopSitesList(title)
    fun verifyExistingTopSitesTabs(title: String) = assertExistingTopSitesTabs(title)
    fun verifyTopSiteContextMenuItems() = assertTopSiteContextMenuItems()

125
126
127
    // Collections element
    fun clickCollectionThreeDotButton() {
        collectionThreeDotButton().click()
128
129
130
131
132
        mDevice.waitNotNull(findObject(text("Delete collection")), waitingTime)
    }

    fun selectOpenTabs() {
        onView(allOf(withText("Open tabs"))).click()
133
    }
134

135
    fun selectRenameCollection() {
136
137
138
139
140
141
142
        onView(allOf(withText("Rename collection"))).click()
        mDevice.waitNotNull(findObject(text("Rename collection")))
    }

    fun selectAddTabToCollection() {
        onView(allOf(withText("Add tab"))).click()
        mDevice.waitNotNull(findObject(text("Select Tabs")))
143
    }
144

145
    fun selectDeleteCollection() {
146
147
        onView(allOf(withText("Delete collection"))).click()
        mDevice.waitNotNull(findObject(By.res("android:id/message")), waitingTime)
148
    }
149

150
    fun confirmDeleteCollection() {
151
152
        onView(allOf(withText("DELETE"))).click()
        mDevice.waitNotNull(findObject(By.res("org.mozilla.fenix.debug:id/collections_header")), waitingTime)
153
    }
154

155
    fun typeCollectionName(name: String) {
156
        mDevice.wait(findObject(By.res("org.mozilla.fenix.debug:id/name_collection_edittext")), waitingTime)
157
158
        collectionNameTextField().perform(ViewActions.replaceText(name))
        collectionNameTextField().perform(ViewActions.pressImeActionButton())
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
        mDevice.waitNotNull(Until.gone(text("Name collection")))
    }

    fun saveTabsSelectedForCollection() = onView(withId(R.id.save_button)).click()

    fun verifyCollectionIsDisplayed(title: String) {
        mDevice.wait(findObject(text(title)), waitingTime)
        collectionTitle(title).check(matches(isDisplayed()))
    }

    fun verifyCollectionIcon() =
        onView(withId(R.id.collection_icon)).check(matches(isDisplayed()))

    fun expandCollection(title: String) {
        try {
            mDevice.waitNotNull(findObject(text(title)), waitingTime)
            collectionTitle(title).click()
        } catch (e: NoMatchingViewException) {
            scrollToElementByText(title)
        }
    }

    fun collapseCollection(title: String) {
        try {
            mDevice.waitNotNull(findObject(text(title)), waitingTime)
            onView(allOf(withId(R.id.chevron), hasSibling(withText(title)))).click()
        } catch (e: NoMatchingViewException) {
            scrollToElementByText(title)
        }
    }

    fun clickSaveCollectionButton() = saveCollectionButton().click()

    fun verifyItemInCollectionExists(title: String, visible: Boolean = true) {
        try {
            collectionItem(title)
                .check(
                    if (visible) matches(isDisplayed()) else doesNotExist()
                )
        } catch (e: NoMatchingViewException) {
            scrollToElementByText(title)
        }
    }

    fun verifyCollectionItemLogo() =
        onView(withId(R.id.list_item_favicon)).check(matches(isDisplayed()))

    fun verifyCollectionItemUrl() =
        onView(withId(R.id.list_item_url)).check(matches(isDisplayed()))

    fun verifyShareCollectionButtonIsVisible(visible: Boolean) {
        shareCollectionButton()
            .check(
                if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE))
                else matches(withEffectiveVisibility(Visibility.GONE))
            )
215
    }
216

217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    fun verifyCollectionMenuIsVisible(visible: Boolean) {
        collectionThreeDotButton()
            .check(
                if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE))
                else matches(withEffectiveVisibility(Visibility.GONE))
            )
    }

    fun verifyCollectionItemRemoveButtonIsVisible(title: String, visible: Boolean) {
        removeTabFromCollectionButton(title)
            .check(
                if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE))
                else doesNotExist()
            )
    }

    fun verifySelectTabsView(vararg tabTitles: String) {
        onView(allOf(withId(R.id.back_button), withText("Select Tabs")))
            .check(matches(isDisplayed()))

        for (title in tabTitles)
            onView(withId(R.id.tab_list)).check(matches(hasItem(withText(title))))
    }

    fun verifyTabsSelectedCounterText(tabsSelected: Int) {
        when (tabsSelected) {
            0 -> onView(withId(R.id.bottom_bar_text)).check(matches(withText("Select tabs to save")))
            1 -> onView(withId(R.id.bottom_bar_text)).check(matches(withText("1 tab selected")))
            else -> onView(withId(R.id.bottom_bar_text)).check(matches(withText("$tabsSelected tabs selected")))
        }
    }

    fun selectAllTabsForCollection() {
        onView(withId(R.id.select_all_button))
            .check(matches(withText("Select All")))
            .click()
    }

    fun deselectAllTabsForCollection() {
        onView(withId(R.id.select_all_button))
            .check(matches(withText("Deselect All")))
            .click()
    }

    fun selectTabForCollection(title: String) {
        tab(title).click()
    }

    fun clickAddNewCollection() =
        onView(allOf(withText("Add new collection"))).click()

    fun verifyNameCollectionView() {
        onView(allOf(withId(R.id.back_button), withText("Name collection")))
            .check(matches(isDisplayed()))
    }

    fun verifyDefaultCollectionName(name: String) =
        onView(withId(R.id.name_collection_edittext)).check(matches(withText(name)))

    fun verifySelectCollectionView() {
        onView(allOf(withId(R.id.back_button), withText("Select collection")))
            .check(matches(isDisplayed()))
    }

    fun verifyShareTabsOverlay() = assertShareTabsOverlay()

    fun clickShareCollectionButton() = onView(withId(R.id.collection_share_button)).click()

    fun removeTabFromCollection(title: String) = removeTabFromCollectionButton(title).click()

    fun swipeCollectionItemRight(title: String) {
        try {
            collectionItem(title).perform(swipeRight())
        } catch (e: NoMatchingViewException) {
            scrollToElementByText(title)
        }
    }

    fun swipeCollectionItemLeft(title: String) {
        try {
            collectionItem(title).perform(swipeLeft())
        } catch (e: NoMatchingViewException) {
            scrollToElementByText(title)
        }
    }

    fun longTapSelectTab(title: String) {
        tab(title).perform(longClick())
    }

    fun goBackCollectionFlow() = collectionFlowBackButton().click()

309
    fun scrollToElementByText(text: String): UiScrollable {
310
        val appView = UiScrollable(UiSelector().scrollable(true))
311
        appView.scrollTextIntoView(text)
312
313
        return appView
    }
314

Oana Horvath's avatar
Oana Horvath committed
315
316
317
318
    fun closeTab() {
        closeTabButton().click()
    }

319
320
    fun togglePrivateBrowsingModeOnOff() {
        onView(ViewMatchers.withResourceName("privateBrowsingButton"))
321
            .perform(click())
322
323
    }

324
    fun swipeToBottom() = onView(withId(R.id.homeLayout)).perform(ViewActions.swipeUp())
325

326
327
    fun swipeToTop() =
        onView(withId(R.id.sessionControlRecyclerView)).perform(ViewActions.swipeDown())
328
329

    fun swipeTabRight(title: String) =
330
        tab(title).perform(ViewActions.swipeRight())
331
332

    fun swipeTabLeft(title: String) =
333
        tab(title).perform(ViewActions.swipeLeft())
334
335
336

    fun verifySnackBarText(expectedText: String) {
        val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
337
        mDevice.waitNotNull(findObject(By.text(expectedText)), TestAssetHelper.waitingTime)
338
    }
339

340
    fun snackBarButtonClick(expectedText: String) {
341
        onView(allOf(withId(R.id.snackbar_btn), withText(expectedText))).check(
342
343
            matches(withEffectiveVisibility(Visibility.VISIBLE))
        ).perform(click())
344
    }
345

346
347
    fun verifyTabMediaControlButtonState(action: String) {
        mDevice.waitNotNull(
348
349
350
351
352
            findObject(
                By
                    .res("org.mozilla.fenix.debug:id/play_pause_button")
                    .desc(action)
            ),
353
354
355
356
357
358
359
360
            waitingTime
        )

        tabMediaControlButton().check(matches(withContentDescription(action)))
    }

    fun clickTabMediaControlButton() = tabMediaControlButton().click()

361
    class Transition {
362
363
        val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

364
365
366
367
368
369
370
371
372
373
374
375
376
377
        fun openTabDrawer(interact: TabDrawerRobot.() -> Unit): TabDrawerRobot.Transition {
            mDevice.waitForIdle()

            tabsCounter().click()

            mDevice.waitNotNull(
                Until.findObject(By.res("org.mozilla.fenix.debug:id/tab_layout")),
                waitingTime
            )

            TabDrawerRobot().interact()
            return TabDrawerRobot.Transition()
        }

378
        fun openThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
379
380
            threeDotButton().perform(click())

381
382
            ThreeDotMenuMainRobot().interact()
            return ThreeDotMenuMainRobot.Transition()
383
        }
384

385
386
387
388
389
390
391
        fun openSearch(interact: SearchRobot.() -> Unit): SearchRobot.Transition {
            navigationToolbar().perform(click())

            SearchRobot().interact()
            return SearchRobot.Transition()
        }

392
393
        fun dismissOnboarding() {
            openThreeDotMenu { }.openSettings { }.goBack { }
394
        }
395

396
        fun togglePrivateBrowsingMode() {
397
398
399
            onView(ViewMatchers.withResourceName("privateBrowsingButton"))
                .perform(click())
        }
400

mcarare's avatar
mcarare committed
401
402
403
404
        fun pressBack() {
            onView(ViewMatchers.isRoot()).perform(ViewActions.pressBack())
        }

405
        fun openTabsListThreeDotMenu(interact: ThreeDotMenuMainRobot.() -> Unit): ThreeDotMenuMainRobot.Transition {
406
//            tabsListThreeDotButton().perform(click())
407

408
409
            ThreeDotMenuMainRobot().interact()
            return ThreeDotMenuMainRobot.Transition()
410
        }
411
412
413
414
415
416
417
418
419

        fun closeAllPrivateTabs(interact: HomeScreenRobot.() -> Unit): Transition {
            onView(withId(R.id.close_tabs_button))
                .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
                .perform(click())

            HomeScreenRobot().interact()
            return Transition()
        }
420
421
422
423
424
425
426

        fun openNavigationToolbar(interact: NavigationToolbarRobot.() -> Unit): NavigationToolbarRobot.Transition {

            assertNavigationToolbar().perform(click())
            NavigationToolbarRobot().interact()
            return NavigationToolbarRobot.Transition()
        }
427

428
429
430
431
        fun openContextMenuOnTopSitesWithTitle(
            title: String,
            interact: HomeScreenRobot.() -> Unit
        ): Transition {
432
            onView(withId(R.id.top_sites_list)).perform(
433
434
435
436
                actionOnItem<RecyclerView.ViewHolder>(
                    hasDescendant(withText(title)),
                    ViewActions.longClick()
                )
437
438
439
440
441
442
            )

            HomeScreenRobot().interact()
            return Transition()
        }

443
444
445
446
        fun openTopSiteTabWithTitle(
            title: String,
            interact: BrowserRobot.() -> Unit
        ): BrowserRobot.Transition {
447
448
449
450
451
452
453
454
            onView(withId(R.id.top_sites_list)).perform(
                actionOnItem<RecyclerView.ViewHolder>(hasDescendant(withText(title)), click())
            )

            BrowserRobot().interact()
            return BrowserRobot.Transition()
        }

455
456
457
458
459
460
461
462
463
464
465
466
        fun renameTopSite(title: String, interact: HomeScreenRobot.() -> Unit): Transition {
            onView(withText("Rename"))
                .check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
                .perform(click())
            onView(Matchers.allOf(withId(R.id.top_site_title), instanceOf(EditText::class.java)))
                .perform(ViewActions.replaceText(title))
            onView(withId(android.R.id.button1)).perform((click()))

            HomeScreenRobot().interact()
            return Transition()
        }

467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
        fun removeTopSite(interact: HomeScreenRobot.() -> Unit): Transition {
            onView(withText("Remove"))
                .check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
                .perform(click())

            HomeScreenRobot().interact()
            return Transition()
        }

        fun openTopSiteInPrivateTab(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
            onView(withText("Open in private tab"))
                .check((matches(withEffectiveVisibility(Visibility.VISIBLE))))
                .perform(click())

            BrowserRobot().interact()
            return BrowserRobot.Transition()
        }
484
485
486

        fun openCommonMythsLink(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
            onView(withId(R.id.private_session_common_myths))
487
488
489
490
491
492
493
494
                .perform(click())

            BrowserRobot().interact()
            return BrowserRobot.Transition()
        }

        fun openTab(title: String, interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
            mDevice.waitNotNull(findObject(text(title)))
495
            tab(title).click()
496
497
498
499

            BrowserRobot().interact()
            return BrowserRobot.Transition()
        }
500
    }
Kevin Brosnan's avatar
Kevin Brosnan committed
501
502
}

503
fun homeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
Kevin Brosnan's avatar
Kevin Brosnan committed
504
    HomeScreenRobot().interact()
505
    return HomeScreenRobot.Transition()
Kevin Brosnan's avatar
Kevin Brosnan committed
506
507
}

508
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
509
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
510

mcarare's avatar
mcarare committed
511
512
513
514
515
516
517
518
private fun assertKeyboardVisibility(isExpectedToBeVisible: Boolean) =
    Assert.assertEquals(
        isExpectedToBeVisible,
        UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
            .executeShellCommand("dumpsys input_method | grep mInputShown")
            .contains("mInputShown=true")
    )

519
private fun navigationToolbar() =
520
    onView(allOf(withText("Search or enter address")))
521

Oana Horvath's avatar
Oana Horvath committed
522
523
private fun closeTabButton() = onView(withId(R.id.close_tab_button))

524
private fun assertNavigationToolbar() =
525
    onView(allOf(withText("Search or enter address")))
mcarare's avatar
mcarare committed
526
527
528
529
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

private fun assertFocusedNavigationToolbar() =
    onView(allOf(withHint("Search or enter address")))
530
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
531

532
private fun assertHomeScreen() = onView(ViewMatchers.withResourceName("homeLayout"))
Kevin Brosnan's avatar
Kevin Brosnan committed
533
    .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
534

535
private fun assertHomeMenu() = onView(ViewMatchers.withResourceName("menuButton"))
Kevin Brosnan's avatar
Kevin Brosnan committed
536
    .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
537
538
539
540
541

private fun assertHomePrivateBrowsingButton() =
    onView(ViewMatchers.withResourceName("privateBrowsingButton"))
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

542
private fun assertHomeWordmark() = onView(ViewMatchers.withResourceName("wordmark"))
Kevin Brosnan's avatar
Kevin Brosnan committed
543
    .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
544

545
private fun assertHomeToolbar() = onView(ViewMatchers.withResourceName("toolbar"))
546
    .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
547

548
549
private fun assertTabButton() =
    onView(allOf(withId(R.id.tab_button), isDisplayed()))
550
551
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

552
private fun assertCollectionsHeader() =
553
    onView(allOf(withText("Collections")))
554
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
555
556

private fun assertNoCollectionsHeader() =
557
    onView(allOf(withText("Collect the things that matter to you")))
558
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
559

560
private fun assertNoCollectionsText() =
561
562
    onView(
        allOf(
563
            withText("Group together similar searches, sites, and tabs for quick access later.")
mcarare's avatar
mcarare committed
564
        )
565
566
    )
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
mcarare's avatar
mcarare committed
567

568
569
570
private fun assertHomeComponent() =
    onView(ViewMatchers.withResourceName("sessionControlRecyclerView"))
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
571

572
573
private fun assertNoTabsOpened() = onView(withId(R.id.counter_text)).check(matches(withText("0")))

574
private fun threeDotButton() = onView(allOf(withId(R.id.menuButton)))
575

576
577
578
579
580
581
582
583
584
585
586
587
588
private fun verifySearchEngineIcon(searchEngineIcon: Bitmap, searchEngineName: String) {
    onView(withId(R.id.search_engine_icon))
        .check(matches(withBitmapDrawable(searchEngineIcon, searchEngineName)))
}

private fun getSearchEngine(searchEngineName: String) =
    Search(appContext).searchEngineManager.getDefaultSearchEngine(appContext, searchEngineName)

private fun verifySearchEngineIcon(searchEngineName: String) {
    val ddgSearchEngine = getSearchEngine(searchEngineName)
    verifySearchEngineIcon(ddgSearchEngine.icon, ddgSearchEngine.name)
}

589
// First Run elements
590
private fun assertWelcomeHeader() =
591
    onView(allOf(withText("Welcome to ${appContext.appName}!")))
592
593
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

594
private fun assertStartSyncHeader() =
595
    onView(allOf(withText("Start syncing bookmarks, passwords, and more with your Firefox account.")))
596
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
597
598

private fun assertAccountsSignInButton() =
599
    onView(ViewMatchers.withResourceName("fxa_sign_in_button"))
600
601
602
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

private fun assertGetToKnowHeader() =
603
    onView(allOf(withText("Get to know ${appContext.appName}")))
604
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
605

606
607
608
private fun assertChooseThemeHeader() {
    scrollToElementByText("Choose your theme")
    onView(withText("Choose your theme"))
609
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
610
611
612
}
private fun assertChooseThemeText() {
    scrollToElementByText("Choose your theme")
613
    onView(allOf(withText("Save some battery and your eyesight by enabling dark mode.")))
614
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
615
}
616

617
618
private fun assertLightThemeToggle() {
    scrollToElementByText("Choose your theme")
619
620
    onView(ViewMatchers.withResourceName("theme_light_radio_button"))
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
621
}
622

623
624
private fun assertLightThemeDescription() {
    scrollToElementByText("Choose your theme")
625
    onView(allOf(withText("Light theme")))
626
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
627
}
628

629
630
private fun assertDarkThemeToggle() {
    scrollToElementByText("Choose your theme")
631
632
    onView(ViewMatchers.withResourceName("theme_dark_radio_button"))
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
633
}
634

635
636
private fun assertDarkThemeDescription() {
    scrollToElementByText("Choose your theme")
637
    onView(allOf(withText("Dark theme")))
638
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
639
640
641
}
private fun assertAutomaticThemeToggle() {
    scrollToElementByText("Choose your theme")
642
    onView(withId(R.id.theme_automatic_radio_button))
643
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
644
}
645

646
647
private fun assertAutomaticThemeDescription() {
    scrollToElementByText("Choose your theme")
648
    onView(allOf(withText("Automatic")))
649
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
650
}
651

652
653
private fun assertAutomaticPrivacyHeader() {
    scrollToElementByText("Automatic privacy")
654
    onView(allOf(withText("Automatic privacy")))
655
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
656
}
657

658
659
660
661
662
private fun assertTrackingProtectionToggle() {
    scrollToElementByText("Automatic privacy")
    onView(withId(R.id.tracking_protection_toggle))
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
663

664
private fun assertAutomaticPrivacyText() {
665
    scrollToElementByText("Automatic privacy")
666
    onView(
667
        allOf(
668
            withText(
669
                "Privacy and security settings block trackers, malware, and companies that follow you."
670
671
672
            )
        )
    )
673
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
674
}
675

676
677
private fun assertBrowsePrivatelyHeader() {
    scrollToElementByText("Browse privately")
678
    onView(allOf(withText("Browse privately")))
679
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
680
}
681

682
683
private fun assertBrowsePrivatelyText() {
    scrollToElementByText("Browse privately")
684
    onView(allOf(withText(containsString("Update your private browsing settings."))))
685
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
686
687
688
}
private fun assertYourPrivacyHeader() {
    scrollToElementByText("Your privacy")
689
    onView(allOf(withText("Your privacy")))
690
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
691
}
692

693
694
private fun assertYourPrivacyText() {
    scrollToElementByText("Your privacy")
695
    onView(
696
        allOf(
697
            withText(
698
                "We’ve designed ${appContext.appName} to give you control over what you share online and what you share with us."
699
700
701
            )
        )
    )
702
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
703
}
704

705
706
private fun assertPrivacyNoticeButton() {
    scrollToElementByText("Your privacy")
707
    onView(allOf(withText("Read our privacy notice")))
708
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
709
}
710

711
712
private fun assertStartBrowsingButton() {
    scrollToElementByText("Start browsing")
713
    onView(allOf(withText("Start browsing")))
714
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
715
}
716

717
// Take a position
718
719
720
721
722
private fun assertTakePositionheader() {
    scrollToElementByText("Take a position")
    onView(allOf(withText("Take a position")))
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
}
723

724
725
private fun assertTakePositionTopRadioButton() {
    scrollToElementByText("Take a position")
726
    onView(ViewMatchers.withResourceName("toolbar_top_radio_button"))
727
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
728
}
729

730
731
private fun assertTakePositionBottomRadioButton() {
    scrollToElementByText("Take a position")
732
    onView(ViewMatchers.withResourceName("toolbar_bottom_radio_button"))
733
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
734
}
735

736
private fun assertPrivateSessionMessage() =
737
    onView(withId(R.id.private_session_description))
738
739
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

740
741
private fun collectionThreeDotButton() =
    onView(allOf(withId(R.id.collection_overflow_button)))
742

743
744
745
private fun collectionNameTextField() =
    onView(allOf(ViewMatchers.withResourceName("name_collection_edittext")))

746
747
748
private fun collectionTitle(title: String) =
    onView(allOf(withId(R.id.collection_title), withText(title)))

749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
private fun assertExistingTopSitesList() =
    onView(allOf(withId(R.id.top_sites_list)))
        .check((matches(withEffectiveVisibility(Visibility.VISIBLE))))

private fun assertExistingTopSitesTabs(title: String) =
    onView(allOf(withId(R.id.top_sites_list)))
        .check(matches(hasItem(hasDescendant(withText(title)))))
        .check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

private fun assertNotExistingTopSitesList(title: String) =
    onView(allOf(withId(R.id.top_sites_list)))
        .check(matches(not(hasItem(hasDescendant(withText(title))))))

private fun assertTopSiteContextMenuItems() {
    val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

    mDevice.waitNotNull(
766
        findObject(By.text("Open in private tab")),
767
768
769
        waitingTime
    )
    mDevice.waitNotNull(
770
        findObject(By.text("Remove")),
771
772
773
        waitingTime
    )
}
774

775
776
777
778
779
780
781
private fun assertShareTabsOverlay() {
    onView(withId(R.id.shared_site_list)).check(matches(isDisplayed()))
    onView(withId(R.id.share_tab_title)).check(matches(isDisplayed()))
    onView(withId(R.id.share_tab_favicon)).check(matches(isDisplayed()))
    onView(withId(R.id.share_tab_url)).check(matches(isDisplayed()))
}

782
private fun tabMediaControlButton() = onView(withId(R.id.play_pause_button))
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799

private fun collectionItem(title: String) =
    onView(allOf(withId(R.id.list_element_title), withText(title)))

private fun saveCollectionButton() = onView(withId(R.id.save_tab_group_button))

private fun shareCollectionButton() = onView(withId(R.id.collection_share_button))

private fun removeTabFromCollectionButton(title: String) =
    onView(
        allOf(
            withId(R.id.list_item_action_button),
            hasSibling(withText(title))
        )
    )

private fun collectionFlowBackButton() = onView(withId(R.id.back_button))
800
private fun tabsCounter() = onView(withId(R.id.tab_button))
801
802
803
804
805
806
807
808

private fun tab(title: String) =
    onView(
        allOf(
            withId(R.id.tab_title),
            withText(title)
        )
    )