1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 package org.mozilla.fenix.components.toolbar
7 import android.content.Intent
8 import android.view.ViewGroup
9 import androidx.navigation.NavController
10 import io.mockk.MockKAnnotations
12 import io.mockk.coEvery
14 import io.mockk.impl.annotations.MockK
15 import io.mockk.impl.annotations.RelaxedMockK
18 import io.mockk.mockkObject
19 import io.mockk.mockkStatic
21 import io.mockk.unmockkObject
22 import io.mockk.unmockkStatic
23 import io.mockk.verify
24 import kotlinx.coroutines.CoroutineScope
25 import kotlinx.coroutines.ExperimentalCoroutinesApi
26 import kotlinx.coroutines.test.runTest
27 import mozilla.appservices.places.BookmarkRoot
28 import mozilla.components.browser.state.action.CustomTabListAction
29 import mozilla.components.browser.state.state.BrowserState
30 import mozilla.components.browser.state.state.ReaderState
31 import mozilla.components.browser.state.state.TabSessionState
32 import mozilla.components.browser.state.state.createCustomTab
33 import mozilla.components.browser.state.state.createTab
34 import mozilla.components.browser.state.store.BrowserStore
35 import mozilla.components.concept.engine.EngineSession
36 import mozilla.components.concept.engine.prompt.ShareData
37 import mozilla.components.feature.search.SearchUseCases
38 import mozilla.components.feature.session.SessionFeature
39 import mozilla.components.feature.session.SessionUseCases
40 import mozilla.components.feature.tab.collections.TabCollection
41 import mozilla.components.feature.tabs.CustomTabsUseCases
42 import mozilla.components.feature.top.sites.DefaultTopSitesStorage
43 import mozilla.components.feature.top.sites.PinnedSiteStorage
44 import mozilla.components.feature.top.sites.TopSite
45 import mozilla.components.feature.top.sites.TopSitesUseCases
46 import mozilla.components.service.glean.testing.GleanTestRule
47 import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
48 import mozilla.components.support.test.ext.joinBlocking
49 import mozilla.components.support.test.robolectric.testContext
50 import mozilla.components.support.test.rule.MainCoroutineRule
51 import mozilla.components.support.test.rule.runTestOnMain
52 import org.junit.After
53 import org.junit.Assert.assertEquals
54 import org.junit.Assert.assertNotNull
55 import org.junit.Assert.assertNull
56 import org.junit.Assert.assertTrue
57 import org.junit.Before
60 import org.junit.runner.RunWith
61 import org.mozilla.fenix.GleanMetrics.Collections
62 import org.mozilla.fenix.GleanMetrics.Events
63 import org.mozilla.fenix.GleanMetrics.ReaderMode
64 import org.mozilla.fenix.HomeActivity
65 import org.mozilla.fenix.NavGraphDirections
66 import org.mozilla.fenix.R
67 import org.mozilla.fenix.browser.BrowserAnimator
68 import org.mozilla.fenix.browser.BrowserFragmentDirections
69 import org.mozilla.fenix.browser.readermode.ReaderModeController
70 import org.mozilla.fenix.collections.SaveCollectionStep
71 import org.mozilla.fenix.components.FenixSnackbar
72 import org.mozilla.fenix.components.TabCollectionStorage
73 import org.mozilla.fenix.components.accounts.AccountState
74 import org.mozilla.fenix.ext.components
75 import org.mozilla.fenix.ext.directionsEq
76 import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
77 import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
78 import org.mozilla.fenix.utils.Settings
80 @OptIn(ExperimentalCoroutinesApi::class)
81 @RunWith(FenixRobolectricTestRunner::class)
82 class DefaultBrowserToolbarMenuControllerTest {
85 val coroutinesTestRule = MainCoroutineRule()
88 val gleanTestRule = GleanTestRule(testContext)
90 @MockK private lateinit var snackbarParent: ViewGroup
92 @RelaxedMockK private lateinit var activity: HomeActivity
94 @RelaxedMockK private lateinit var navController: NavController
96 @RelaxedMockK private lateinit var openInFenixIntent: Intent
98 @RelaxedMockK private lateinit var settings: Settings
100 @RelaxedMockK private lateinit var searchUseCases: SearchUseCases
102 @RelaxedMockK private lateinit var sessionUseCases: SessionUseCases
104 @RelaxedMockK private lateinit var customTabUseCases: CustomTabsUseCases
106 @RelaxedMockK private lateinit var browserAnimator: BrowserAnimator
108 @RelaxedMockK private lateinit var snackbar: FenixSnackbar
110 @RelaxedMockK private lateinit var tabCollectionStorage: TabCollectionStorage
112 @RelaxedMockK private lateinit var topSitesUseCase: TopSitesUseCases
114 @RelaxedMockK private lateinit var readerModeController: ReaderModeController
116 @MockK private lateinit var sessionFeatureWrapper: ViewBoundFeatureWrapper<SessionFeature>
118 @RelaxedMockK private lateinit var sessionFeature: SessionFeature
120 @RelaxedMockK private lateinit var topSitesStorage: DefaultTopSitesStorage
122 @RelaxedMockK private lateinit var pinnedSiteStorage: PinnedSiteStorage
124 private lateinit var browserStore: BrowserStore
125 private lateinit var selectedTab: TabSessionState
129 MockKAnnotations.init(this)
132 "org.mozilla.fenix.settings.deletebrowsingdata.DeleteAndQuitKt",
134 every { deleteAndQuit(any(), any(), any()) } just Runs
136 mockkObject(FenixSnackbar.Companion)
137 every { FenixSnackbar.make(any(), any(), any(), any()) } returns snackbar
139 every { activity.components.useCases.sessionUseCases } returns sessionUseCases
140 every { activity.components.useCases.customTabsUseCases } returns customTabUseCases
141 every { activity.components.useCases.searchUseCases } returns searchUseCases
142 every { activity.components.useCases.topSitesUseCase } returns topSitesUseCase
143 every { sessionFeatureWrapper.get() } returns sessionFeature
144 every { navController.currentDestination } returns mockk {
145 every { id } returns R.id.browserFragment
147 every { settings.topSitesMaxLimit } returns 16
149 val onComplete = slot<(Boolean) -> Unit>()
150 every { browserAnimator.captureEngineViewAndDrawStatically(any(), capture(onComplete)) } answers { onComplete.captured.invoke(true) }
152 selectedTab = createTab("https://www.mozilla.org", id = "1")
153 browserStore = BrowserStore(
154 initialState = BrowserState(
155 tabs = listOf(selectedTab),
156 selectedTabId = selectedTab.id,
163 unmockkStatic("org.mozilla.fenix.settings.deletebrowsingdata.DeleteAndQuitKt")
164 unmockkObject(FenixSnackbar.Companion)
168 fun handleToolbarBookmarkPressWithReaderModeInactive() = runTest {
169 val item = ToolbarMenu.Item.Bookmark
171 val expectedTitle = "Mozilla"
172 val expectedUrl = "https://mozilla.org"
173 val regularTab = createTab(
175 readerState = ReaderState(active = false, activeUrl = "https://1234.org"),
176 title = expectedTitle,
179 BrowserStore(BrowserState(tabs = listOf(regularTab), selectedTabId = regularTab.id))
181 var bookmarkTappedInvoked = false
182 val controller = createController(
185 bookmarkTapped = { url, title ->
186 assertEquals(expectedTitle, title)
187 assertEquals(expectedUrl, url)
188 bookmarkTappedInvoked = true
191 assertNull(Events.browserMenuAction.testGetValue())
193 controller.handleToolbarItemInteraction(item)
195 assertNotNull(Events.browserMenuAction.testGetValue())
196 val snapshot = Events.browserMenuAction.testGetValue()!!
197 assertEquals(1, snapshot.size)
198 assertEquals("bookmark", snapshot.single().extra?.getValue("item"))
200 assertTrue(bookmarkTappedInvoked)
204 fun `IF reader mode is active WHEN bookmark menu item is pressed THEN menu item is handled`() = runTest {
205 val item = ToolbarMenu.Item.Bookmark
206 val expectedTitle = "Mozilla"
207 val readerUrl = "moz-extension://1234"
208 val readerTab = createTab(
210 readerState = ReaderState(active = true, activeUrl = "https://mozilla.org"),
211 title = expectedTitle,
214 BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
216 var bookmarkTappedInvoked = false
217 val controller = createController(
219 store = browserStore,
220 bookmarkTapped = { url, title ->
221 assertEquals(expectedTitle, title)
222 assertEquals(readerTab.readerState.activeUrl, url)
223 bookmarkTappedInvoked = true
226 assertNull(Events.browserMenuAction.testGetValue())
228 controller.handleToolbarItemInteraction(item)
230 assertNotNull(Events.browserMenuAction.testGetValue())
231 val snapshot = Events.browserMenuAction.testGetValue()!!
232 assertEquals(1, snapshot.size)
233 assertEquals("bookmark", snapshot.single().extra?.getValue("item"))
235 assertTrue(bookmarkTappedInvoked)
239 fun `WHEN open in Fenix menu item is pressed THEN menu item is handled correctly`() = runTest {
240 val customTab = createCustomTab("https://mozilla.org")
241 browserStore.dispatch(CustomTabListAction.AddCustomTabAction(customTab)).joinBlocking()
242 val controller = createController(
244 store = browserStore,
245 customTabSessionId = customTab.id,
248 val item = ToolbarMenu.Item.OpenInFenix
250 every { activity.startActivity(any()) } just Runs
251 controller.handleToolbarItemInteraction(item)
253 verify { sessionFeature.release() }
254 verify { customTabUseCases.migrate(customTab.id, true) }
255 verify { activity.startActivity(openInFenixIntent) }
256 verify { activity.finishAndRemoveTask() }
260 fun `WHEN reader mode menu item is pressed THEN handle appearance change`() = runTest {
261 val item = ToolbarMenu.Item.CustomizeReaderView
262 assertNull(ReaderMode.appearance.testGetValue())
264 val controller = createController(scope = this, store = browserStore)
266 controller.handleToolbarItemInteraction(item)
268 verify { readerModeController.showControls() }
269 assertNotNull(ReaderMode.appearance.testGetValue())
270 assertNull(ReaderMode.appearance.testGetValue()!!.single().extra)
274 fun `WHEN quit menu item is pressed THEN menu item is handled correctly`() = runTest {
275 val item = ToolbarMenu.Item.Quit
278 val controller = createController(scope = this, store = browserStore)
280 controller.handleToolbarItemInteraction(item)
282 verify { deleteAndQuit(activity, testScope, null) }
286 fun `WHEN backwards nav menu item is pressed THEN the session navigates back with active session`() = runTest {
287 val item = ToolbarMenu.Item.Back(false)
289 val controller = createController(scope = this, store = browserStore)
290 assertNull(Events.browserMenuAction.testGetValue())
292 controller.handleToolbarItemInteraction(item)
294 assertNotNull(Events.browserMenuAction.testGetValue())
295 val snapshot = Events.browserMenuAction.testGetValue()!!
296 assertEquals(1, snapshot.size)
297 assertEquals("back", snapshot.single().extra?.getValue("item"))
299 verify { sessionUseCases.goBack(browserStore.state.selectedTabId!!) }
303 fun `WHEN backwards nav menu item is long pressed THEN the session navigates back with no active session`() = runTest {
304 val item = ToolbarMenu.Item.Back(true)
306 val controller = createController(scope = this, store = browserStore)
307 assertNull(Events.browserMenuAction.testGetValue())
309 controller.handleToolbarItemInteraction(item)
311 assertNotNull(Events.browserMenuAction.testGetValue())
312 val snapshot = Events.browserMenuAction.testGetValue()!!
313 assertEquals(1, snapshot.size)
314 assertEquals("back", snapshot.single().extra?.getValue("item"))
315 val directions = BrowserFragmentDirections.actionGlobalTabHistoryDialogFragment(null)
317 verify { navController.navigate(directions) }
321 fun `WHEN forward nav menu item is pressed THEN the session navigates forward to active session`() = runTest {
322 val item = ToolbarMenu.Item.Forward(false)
324 val controller = createController(scope = this, store = browserStore)
325 assertNull(Events.browserMenuAction.testGetValue())
327 controller.handleToolbarItemInteraction(item)
329 assertNotNull(Events.browserMenuAction.testGetValue())
330 val snapshot = Events.browserMenuAction.testGetValue()!!
331 assertEquals(1, snapshot.size)
332 assertEquals("forward", snapshot.single().extra?.getValue("item"))
334 verify { sessionUseCases.goForward(selectedTab.id) }
338 fun `WHEN forward nav menu item is long pressed THEN the browser navigates forward with no active session`() = runTest {
339 val item = ToolbarMenu.Item.Forward(true)
341 val controller = createController(scope = this, store = browserStore)
342 assertNull(Events.browserMenuAction.testGetValue())
344 controller.handleToolbarItemInteraction(item)
346 assertNotNull(Events.browserMenuAction.testGetValue())
347 val snapshot = Events.browserMenuAction.testGetValue()!!
348 assertEquals(1, snapshot.size)
349 assertEquals("forward", snapshot.single().extra?.getValue("item"))
351 val directions = BrowserFragmentDirections.actionGlobalTabHistoryDialogFragment(null)
353 verify { navController.navigate(directions) }
357 fun `WHEN reload nav menu item is pressed THEN the session reloads from cache`() = runTest {
358 val item = ToolbarMenu.Item.Reload(false)
360 val controller = createController(scope = this, store = browserStore)
361 assertNull(Events.browserMenuAction.testGetValue())
363 controller.handleToolbarItemInteraction(item)
365 assertNotNull(Events.browserMenuAction.testGetValue())
366 val snapshot = Events.browserMenuAction.testGetValue()!!
367 assertEquals(1, snapshot.size)
368 assertEquals("reload", snapshot.single().extra?.getValue("item"))
370 verify { sessionUseCases.reload(selectedTab.id) }
374 fun `WHEN reload nav menu item is long pressed THEN the session reloads with no cache`() = runTest {
375 val item = ToolbarMenu.Item.Reload(true)
377 val controller = createController(scope = this, store = browserStore)
378 assertNull(Events.browserMenuAction.testGetValue())
380 controller.handleToolbarItemInteraction(item)
382 assertNotNull(Events.browserMenuAction.testGetValue())
383 val snapshot = Events.browserMenuAction.testGetValue()!!
384 assertEquals(1, snapshot.size)
385 assertEquals("reload", snapshot.single().extra?.getValue("item"))
388 sessionUseCases.reload(
390 EngineSession.LoadUrlFlags.select(EngineSession.LoadUrlFlags.BYPASS_CACHE),
396 fun `WHEN stop nav menu item is pressed THEN the session stops loading`() = runTest {
397 val item = ToolbarMenu.Item.Stop
399 val controller = createController(scope = this, store = browserStore)
400 assertNull(Events.browserMenuAction.testGetValue())
402 controller.handleToolbarItemInteraction(item)
404 assertNotNull(Events.browserMenuAction.testGetValue())
405 val snapshot = Events.browserMenuAction.testGetValue()!!
406 assertEquals(1, snapshot.size)
407 assertEquals("stop", snapshot.single().extra?.getValue("item"))
409 verify { sessionUseCases.stopLoading(selectedTab.id) }
413 fun `WHEN settings menu item is pressed THEN menu item is handled`() = runTest {
414 val item = ToolbarMenu.Item.Settings
416 val controller = createController(scope = this, store = browserStore)
417 assertNull(Events.browserMenuAction.testGetValue())
419 controller.handleToolbarItemInteraction(item)
421 assertNotNull(Events.browserMenuAction.testGetValue())
422 val snapshot = Events.browserMenuAction.testGetValue()!!
423 assertEquals(1, snapshot.size)
424 assertEquals("settings", snapshot.single().extra?.getValue("item"))
425 val directions = BrowserFragmentDirections.actionBrowserFragmentToSettingsFragment()
427 verify { navController.navigate(directions, null) }
431 fun `WHEN bookmark menu item is pressed THEN navigate to bookmarks page`() = runTest {
432 val item = ToolbarMenu.Item.Bookmarks
434 val controller = createController(scope = this, store = browserStore)
435 assertNull(Events.browserMenuAction.testGetValue())
437 controller.handleToolbarItemInteraction(item)
439 assertNotNull(Events.browserMenuAction.testGetValue())
440 val snapshot = Events.browserMenuAction.testGetValue()!!
441 assertEquals(1, snapshot.size)
442 assertEquals("bookmarks", snapshot.single().extra?.getValue("item"))
443 val directions = BrowserFragmentDirections.actionGlobalBookmarkFragment(BookmarkRoot.Mobile.id)
445 verify { navController.navigate(directions, null) }
449 fun `WHEN history menu item is pressed THEN navigate to history page`() = runTest {
450 val item = ToolbarMenu.Item.History
452 val controller = createController(scope = this, store = browserStore)
453 assertNull(Events.browserMenuAction.testGetValue())
455 controller.handleToolbarItemInteraction(item)
457 assertNotNull(Events.browserMenuAction.testGetValue())
458 val snapshot = Events.browserMenuAction.testGetValue()!!
459 assertEquals(1, snapshot.size)
460 assertEquals("history", snapshot.single().extra?.getValue("item"))
461 val directions = BrowserFragmentDirections.actionGlobalHistoryFragment()
463 verify { navController.navigate(directions, null) }
467 fun `WHEN request desktop menu item is toggled On THEN desktop site is requested for the session`() = runTest {
468 val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
469 mockk(relaxed = true)
470 val item = ToolbarMenu.Item.RequestDesktop(true)
472 every { sessionUseCases.requestDesktopSite } returns requestDesktopSiteUseCase
474 val controller = createController(scope = this, store = browserStore)
475 assertNull(Events.browserMenuAction.testGetValue())
477 controller.handleToolbarItemInteraction(item)
479 assertNotNull(Events.browserMenuAction.testGetValue())
480 val snapshot = Events.browserMenuAction.testGetValue()!!
481 assertEquals(1, snapshot.size)
482 assertEquals("desktop_view_on", snapshot.single().extra?.getValue("item"))
485 requestDesktopSiteUseCase.invoke(
493 fun `WHEN request desktop menu item is toggled Off THEN mobile site is requested for the session`() = runTest {
494 val requestDesktopSiteUseCase: SessionUseCases.RequestDesktopSiteUseCase =
495 mockk(relaxed = true)
496 val item = ToolbarMenu.Item.RequestDesktop(false)
498 every { sessionUseCases.requestDesktopSite } returns requestDesktopSiteUseCase
500 val controller = createController(scope = this, store = browserStore)
501 assertNull(Events.browserMenuAction.testGetValue())
503 controller.handleToolbarItemInteraction(item)
505 assertNotNull(Events.browserMenuAction.testGetValue())
506 val snapshot = Events.browserMenuAction.testGetValue()!!
507 assertEquals(1, snapshot.size)
508 assertEquals("desktop_view_off", snapshot.single().extra?.getValue("item"))
511 requestDesktopSiteUseCase.invoke(
519 fun `WHEN add to shortcuts menu item is pressed THEN add site AND show snackbar`() = runTestOnMain {
520 val item = ToolbarMenu.Item.AddToTopSites
521 val addPinnedSiteUseCase: TopSitesUseCases.AddPinnedSiteUseCase = mockk(relaxed = true)
523 every { topSitesUseCase.addPinnedSites } returns addPinnedSiteUseCase
525 snackbarParent.context.getString(R.string.snackbar_added_to_shortcuts)
526 } returns "Added to shortcuts!"
528 val controller = createController(scope = this, store = browserStore)
529 assertNull(Events.browserMenuAction.testGetValue())
531 controller.handleToolbarItemInteraction(item)
533 assertNotNull(Events.browserMenuAction.testGetValue())
534 val snapshot = Events.browserMenuAction.testGetValue()!!
535 assertEquals(1, snapshot.size)
536 assertEquals("add_to_top_sites", snapshot.single().extra?.getValue("item"))
538 verify { addPinnedSiteUseCase.invoke(selectedTab.content.title, selectedTab.content.url) }
539 verify { snackbar.setText("Added to shortcuts!") }
543 fun `GIVEN a shortcut page is open WHEN remove from shortcuts is pressed THEN show snackbar`() = runTestOnMain {
544 val snackbarMessage = "Site removed"
545 val item = ToolbarMenu.Item.RemoveFromTopSites
546 val removePinnedSiteUseCase: TopSitesUseCases.RemoveTopSiteUseCase =
547 mockk(relaxed = true)
548 val topSite: TopSite = mockk()
549 every { topSite.url } returns selectedTab.content.url
550 coEvery { pinnedSiteStorage.getPinnedSites() } returns listOf(topSite)
551 every { topSitesUseCase.removeTopSites } returns removePinnedSiteUseCase
553 snackbarParent.context.getString(R.string.snackbar_top_site_removed)
554 } returns snackbarMessage
556 val controller = createController(scope = this, store = browserStore)
557 assertNull(Events.browserMenuAction.testGetValue())
559 controller.handleToolbarItemInteraction(item)
561 assertNotNull(Events.browserMenuAction.testGetValue())
562 val snapshot = Events.browserMenuAction.testGetValue()!!
563 assertEquals(1, snapshot.size)
564 assertEquals("remove_from_top_sites", snapshot.single().extra?.getValue("item"))
566 verify { snackbar.setText(snackbarMessage) }
567 verify { removePinnedSiteUseCase.invoke(topSite) }
571 fun `WHEN addon extensions menu item is pressed THEN navigate to addons manager`() = runTest {
572 val item = ToolbarMenu.Item.AddonsManager
574 val controller = createController(scope = this, store = browserStore)
575 assertNull(Events.browserMenuAction.testGetValue())
577 controller.handleToolbarItemInteraction(item)
579 assertNotNull(Events.browserMenuAction.testGetValue())
580 val snapshot = Events.browserMenuAction.testGetValue()!!
581 assertEquals(1, snapshot.size)
582 assertEquals("addons_manager", snapshot.single().extra?.getValue("item"))
586 fun `WHEN Add To Home Screen menu item is pressed THEN add site`() = runTest {
587 val item = ToolbarMenu.Item.AddToHomeScreen
589 val controller = createController(scope = this, store = browserStore)
590 assertNull(Events.browserMenuAction.testGetValue())
592 controller.handleToolbarItemInteraction(item)
594 assertNotNull(Events.browserMenuAction.testGetValue())
595 val snapshot = Events.browserMenuAction.testGetValue()!!
596 assertEquals(1, snapshot.size)
597 assertEquals("add_to_homescreen", snapshot.single().extra?.getValue("item"))
601 fun `IF reader mode is inactive WHEN share menu item is pressed THEN navigate to share screen`() = runTest {
602 val item = ToolbarMenu.Item.Share
603 val title = "Mozilla"
604 val url = "https://mozilla.org"
605 val regularTab = createTab(
607 readerState = ReaderState(active = false, activeUrl = "https://1234.org"),
610 browserStore = BrowserStore(BrowserState(tabs = listOf(regularTab), selectedTabId = regularTab.id))
611 val controller = createController(scope = this, store = browserStore)
612 assertNull(Events.browserMenuAction.testGetValue())
614 controller.handleToolbarItemInteraction(item)
616 assertNotNull(Events.browserMenuAction.testGetValue())
617 val snapshot = Events.browserMenuAction.testGetValue()!!
618 assertEquals(1, snapshot.size)
619 assertEquals("share", snapshot.single().extra?.getValue("item"))
622 navController.navigate(
624 NavGraphDirections.actionGlobalShareFragment(
625 sessionId = browserStore.state.selectedTabId,
626 data = arrayOf(ShareData(url = "https://mozilla.org", title = "Mozilla")),
635 fun `IF reader mode is active WHEN share menu item is pressed THEN navigate to share screen`() = runTest {
636 val item = ToolbarMenu.Item.Share
637 val title = "Mozilla"
638 val readerUrl = "moz-extension://1234"
639 val readerTab = createTab(
641 readerState = ReaderState(active = true, activeUrl = "https://mozilla.org"),
644 browserStore = BrowserStore(BrowserState(tabs = listOf(readerTab), selectedTabId = readerTab.id))
645 val controller = createController(scope = this, store = browserStore)
646 assertNull(Events.browserMenuAction.testGetValue())
648 controller.handleToolbarItemInteraction(item)
650 assertNotNull(Events.browserMenuAction.testGetValue())
651 val snapshot = Events.browserMenuAction.testGetValue()!!
652 assertEquals(1, snapshot.size)
653 assertEquals("share", snapshot.single().extra?.getValue("item"))
656 navController.navigate(
658 NavGraphDirections.actionGlobalShareFragment(
659 sessionId = browserStore.state.selectedTabId,
660 data = arrayOf(ShareData(url = "https://mozilla.org", title = "Mozilla")),
669 fun `WHEN Find In Page menu item is pressed THEN launch finder`() = runTest {
670 val item = ToolbarMenu.Item.FindInPage
672 var launcherInvoked = false
673 val controller = createController(
675 store = browserStore,
676 findInPageLauncher = {
677 launcherInvoked = true
680 controller.handleToolbarItemInteraction(item)
682 assertTrue(launcherInvoked)
686 fun `IF one or more collection exists WHEN Save To Collection menu item is pressed THEN navigate to save collection page`() = runTest {
687 val item = ToolbarMenu.Item.SaveToCollection
688 val cachedTabCollections: List<TabCollection> = mockk(relaxed = true)
689 every { tabCollectionStorage.cachedTabCollections } returns cachedTabCollections
691 val controller = createController(scope = this, store = browserStore)
692 assertNull(Events.browserMenuAction.testGetValue())
694 controller.handleToolbarItemInteraction(item)
696 assertNotNull(Events.browserMenuAction.testGetValue())
697 val snapshot = Events.browserMenuAction.testGetValue()!!
698 assertEquals(1, snapshot.size)
699 assertEquals("save_to_collection", snapshot.single().extra?.getValue("item"))
701 assertNotNull(Collections.saveButton.testGetValue())
702 val recordedEvents = Collections.saveButton.testGetValue()!!
703 assertEquals(1, recordedEvents.size)
704 val eventExtra = recordedEvents.single().extra
705 assertNotNull(eventExtra)
706 assertTrue(eventExtra!!.containsKey("from_screen"))
708 DefaultBrowserToolbarMenuController.TELEMETRY_BROWSER_IDENTIFIER,
709 eventExtra["from_screen"],
712 val directions = BrowserFragmentDirections.actionGlobalCollectionCreationFragment(
713 saveCollectionStep = SaveCollectionStep.SelectCollection,
714 tabIds = arrayOf(selectedTab.id),
715 selectedTabIds = arrayOf(selectedTab.id),
717 verify { navController.navigate(directionsEq(directions), null) }
721 fun `IF no collection exists WHEN Save To Collection menu item is pressed THEN navigate to create collection page`() = runTest {
722 val item = ToolbarMenu.Item.SaveToCollection
723 val cachedTabCollectionsEmpty: List<TabCollection> = emptyList()
724 every { tabCollectionStorage.cachedTabCollections } returns cachedTabCollectionsEmpty
726 val controller = createController(scope = this, store = browserStore)
727 assertNull(Events.browserMenuAction.testGetValue())
729 controller.handleToolbarItemInteraction(item)
731 assertNotNull(Events.browserMenuAction.testGetValue())
732 val snapshot = Events.browserMenuAction.testGetValue()!!
733 assertEquals(1, snapshot.size)
734 assertEquals("save_to_collection", snapshot.single().extra?.getValue("item"))
736 assertNotNull(Collections.saveButton.testGetValue())
737 val recordedEvents = Collections.saveButton.testGetValue()!!
738 assertEquals(1, recordedEvents.size)
739 val eventExtra = recordedEvents.single().extra
740 assertNotNull(eventExtra)
741 assertTrue(eventExtra!!.containsKey("from_screen"))
743 DefaultBrowserToolbarMenuController.TELEMETRY_BROWSER_IDENTIFIER,
744 eventExtra["from_screen"],
746 val directions = BrowserFragmentDirections.actionGlobalCollectionCreationFragment(
747 saveCollectionStep = SaveCollectionStep.NameCollection,
748 tabIds = arrayOf(selectedTab.id),
749 selectedTabIds = arrayOf(selectedTab.id),
751 verify { navController.navigate(directionsEq(directions), null) }
755 fun `WHEN New Tab menu item is pressed THEN navigate to a new tab home`() = runTest {
756 val item = ToolbarMenu.Item.NewTab
758 val controller = createController(scope = this, store = browserStore)
760 controller.handleToolbarItemInteraction(item)
763 navController.navigate(
765 NavGraphDirections.actionGlobalHome(
766 focusOnAddressBar = true,
774 fun `GIVEN account exists and the user is signed in WHEN sign in to sync menu item is pressed THEN navigate to account settings`() = runTest {
775 val item = ToolbarMenu.Item.SyncAccount(AccountState.AUTHENTICATED)
776 val accountSettingsDirections = BrowserFragmentDirections.actionGlobalAccountSettingsFragment()
777 val controller = createController(scope = this, store = browserStore)
779 controller.handleToolbarItemInteraction(item)
781 verify { navController.navigate(accountSettingsDirections, null) }
785 fun `GIVEN account exists and the user is not signed in WHEN sign in to sync menu item is pressed THEN navigate to account problem fragment`() = runTest {
786 val item = ToolbarMenu.Item.SyncAccount(AccountState.NEEDS_REAUTHENTICATION)
787 val accountProblemDirections = BrowserFragmentDirections.actionGlobalAccountProblemFragment()
788 val controller = createController(scope = this, store = browserStore)
790 controller.handleToolbarItemInteraction(item)
792 verify { navController.navigate(accountProblemDirections, null) }
796 fun `GIVEN account doesn't exist WHEN sign in to sync menu item is pressed THEN navigate to sign in`() = runTest {
797 val item = ToolbarMenu.Item.SyncAccount(AccountState.NO_ACCOUNT)
798 val turnOnSyncDirections = BrowserFragmentDirections.actionGlobalTurnOnSync()
799 val controller = createController(scope = this, store = browserStore)
801 controller.handleToolbarItemInteraction(item)
803 verify { navController.navigate(turnOnSyncDirections, null) }
806 @Suppress("LongParameterList")
807 private fun createController(
808 scope: CoroutineScope,
810 activity: HomeActivity = this.activity,
811 customTabSessionId: String? = null,
812 findInPageLauncher: () -> Unit = { },
813 bookmarkTapped: (String, String) -> Unit = { _, _ -> },
814 ) = DefaultBrowserToolbarMenuController(
817 navController = navController,
819 findInPageLauncher = findInPageLauncher,
820 browserAnimator = browserAnimator,
821 customTabSessionId = customTabSessionId,
822 openInFenixIntent = openInFenixIntent,
824 snackbarParent = snackbarParent,
825 tabCollectionStorage = tabCollectionStorage,
826 bookmarkTapped = bookmarkTapped,
827 readerModeController = readerModeController,
828 sessionFeature = sessionFeatureWrapper,
829 topSitesStorage = topSitesStorage,
830 pinnedSiteStorage = pinnedSiteStorage,
831 browserStore = browserStore,