You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/test/java/org/mozilla/fenix/browser/OpenInAppOnboardingObserver...

168 lines
6.9 KiB
Kotlin

/* 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.browser
import android.content.Context
import android.view.ViewGroup
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.navigation.NavController
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.runs
import io.mockk.spyk
import io.mockk.verify
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import mozilla.components.browser.state.action.ContentAction
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.feature.app.links.AppLinksUseCases
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.rule.MainCoroutineRule
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.utils.Settings
@ExperimentalCoroutinesApi
@RunWith(FenixRobolectricTestRunner::class)
class OpenInAppOnboardingObserverTest {
private lateinit var store: BrowserStore
private lateinit var lifecycleOwner: MockedLifecycleOwner
private lateinit var openInAppOnboardingObserver: OpenInAppOnboardingObserver
private lateinit var navigationController: NavController
private lateinit var settings: Settings
private lateinit var appLinksUseCases: AppLinksUseCases
private lateinit var context: Context
private lateinit var container: ViewGroup
private lateinit var infoBanner: InfoBanner
private val testDispatcher = TestCoroutineDispatcher()
@get:Rule
val coroutinesTestRule = MainCoroutineRule(testDispatcher)
@Before
fun setUp() {
store = BrowserStore(
BrowserState(
tabs = listOf(
createTab(url = "https://www.mozilla.org", id = "1")
), selectedTabId = "1"
)
)
lifecycleOwner = MockedLifecycleOwner(Lifecycle.State.STARTED)
navigationController = mockk(relaxed = true)
settings = mockk(relaxed = true)
appLinksUseCases = mockk(relaxed = true)
container = mockk(relaxed = true)
context = mockk(relaxed = true)
infoBanner = mockk(relaxed = true)
openInAppOnboardingObserver = spyk(OpenInAppOnboardingObserver(
context = context,
store = store,
lifecycleOwner = lifecycleOwner,
navController = navigationController,
settings = settings,
appLinksUseCases = appLinksUseCases,
container = container
))
every { openInAppOnboardingObserver.createInfoBanner() } returns infoBanner
}
@After
fun teardown() {
openInAppOnboardingObserver.stop()
}
@Test
fun `GIVEN user configured to open links in external app WHEN page finishes loading THEN do not show banner`() {
every { settings.openLinksInExternalApp } returns true
every { settings.shouldShowOpenInAppCfr } returns true
every { appLinksUseCases.appLinkRedirect.invoke(any()).hasExternalApp() } returns true
store.dispatch(ContentAction.UpdateLoadingStateAction("1", true)).joinBlocking()
openInAppOnboardingObserver.start()
store.dispatch(ContentAction.UpdateLoadingStateAction("1", false)).joinBlocking()
verify(exactly = 0) { infoBanner.showBanner() }
}
@Test
fun `GIVEN user has not configured to open links in external app WHEN page finishes loading THEN show banner`() {
every { settings.openLinksInExternalApp } returns false
every { settings.shouldShowOpenInAppCfr } returns true
every { appLinksUseCases.appLinkRedirect.invoke(any()).hasExternalApp() } returns true
store.dispatch(ContentAction.UpdateLoadingStateAction("1", true)).joinBlocking()
openInAppOnboardingObserver.start()
store.dispatch(ContentAction.UpdateLoadingStateAction("1", false)).joinBlocking()
verify(exactly = 1) { infoBanner.showBanner() }
}
@Test
fun `GIVEN banner was already displayed WHEN page finishes loading THEN do not show banner`() {
every { settings.openLinksInExternalApp } returns false
every { settings.shouldShowOpenInAppCfr } returns false
every { appLinksUseCases.appLinkRedirect.invoke(any()).hasExternalApp() } returns true
store.dispatch(ContentAction.UpdateLoadingStateAction("1", true)).joinBlocking()
openInAppOnboardingObserver.start()
store.dispatch(ContentAction.UpdateLoadingStateAction("1", false)).joinBlocking()
verify(exactly = 0) { infoBanner.showBanner() }
}
@Test
fun `GIVEN banner should be displayed WHEN no application found THEN do not show banner`() {
every { settings.openLinksInExternalApp } returns false
every { settings.shouldShowOpenInAppCfr } returns true
every { appLinksUseCases.appLinkRedirect.invoke(any()).hasExternalApp() } returns false
store.dispatch(ContentAction.UpdateLoadingStateAction("1", true)).joinBlocking()
openInAppOnboardingObserver.start()
store.dispatch(ContentAction.UpdateLoadingStateAction("1", false)).joinBlocking()
verify(exactly = 0) { infoBanner.showBanner() }
}
@Test
fun `GIVEN banner is displayed WHEN user navigates to different domain THEN banner is dismissed`() {
every { settings.openLinksInExternalApp } returns false
every { settings.shouldShowOpenInAppCfr } returns true
every { appLinksUseCases.appLinkRedirect.invoke(any()).hasExternalApp() } returns true
every { context.components.analytics.metrics.track(any()) } just runs
store.dispatch(ContentAction.UpdateLoadingStateAction("1", true)).joinBlocking()
openInAppOnboardingObserver.start()
store.dispatch(ContentAction.UpdateLoadingStateAction("1", false)).joinBlocking()
verify(exactly = 1) { infoBanner.showBanner() }
verify(exactly = 0) { infoBanner.dismiss() }
store.dispatch(ContentAction.UpdateUrlAction("1", "https://www.mozilla.org/en-US/")).joinBlocking()
verify(exactly = 0) { infoBanner.dismiss() }
store.dispatch(ContentAction.UpdateUrlAction("1", "https://www.firefox.com")).joinBlocking()
verify(exactly = 1) { infoBanner.dismiss() }
}
internal class MockedLifecycleOwner(initialState: Lifecycle.State) : LifecycleOwner {
val lifecycleRegistry = LifecycleRegistry(this).apply {
currentState = initialState
}
override fun getLifecycle(): Lifecycle = lifecycleRegistry
}
}