Loading app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt +37 −31 Original line number Diff line number Diff line Loading @@ -5,12 +5,14 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding import android.view.View import android.widget.Button import androidx.annotation.VisibleForTesting import androidx.appcompat.content.res.AppCompatResources.getDrawable import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.onboarding_automatic_signin.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch import mozilla.components.service.fxa.manager.SignInWithShareableAccountResult import mozilla.components.service.fxa.sharing.ShareableAccount Loading @@ -20,36 +22,51 @@ import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components class OnboardingAutomaticSignInViewHolder(view: View) : RecyclerView.ViewHolder(view) { class OnboardingAutomaticSignInViewHolder( view: View, private val scope: CoroutineScope = MainScope() ) : RecyclerView.ViewHolder(view) { private lateinit var shareableAccount: ShareableAccount private val headerText = view.header_text init { view.turn_on_sync_button.setOnClickListener { it.context.components.analytics.metrics.track(Event.OnboardingAutoSignIn) scope.launch { onClick(it.turn_on_sync_button) } } } it.turn_on_sync_button.text = it.context.getString( R.string.onboarding_firefox_account_signing_in fun bind(account: ShareableAccount) { shareableAccount = account headerText.text = itemView.context.getString( R.string.onboarding_firefox_account_auto_signin_header_2, account.email ) it.turn_on_sync_button.isEnabled = false val icon = getDrawable(itemView.context, R.drawable.ic_onboarding_avatar_anonymous) headerText.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon) } @VisibleForTesting internal suspend fun onClick(button: Button) { val context = button.context context.components.analytics.metrics.track(Event.OnboardingAutoSignIn) button.text = context.getString(R.string.onboarding_firefox_account_signing_in) button.isEnabled = false CoroutineScope(Dispatchers.Main).launch { val result = view.context.components.backgroundServices.accountManager .signInWithShareableAccountAsync(shareableAccount).await() when (result) { val accountManager = context.components.backgroundServices.accountManager when (accountManager.signInWithShareableAccountAsync(shareableAccount).await()) { SignInWithShareableAccountResult.Failure -> { // Failed to sign-in (e.g. bad credentials). Allow to try again. it.turn_on_sync_button.text = it.context.getString( R.string.onboarding_firefox_account_auto_signin_confirm ) it.turn_on_sync_button.isEnabled = true button.text = context.getString(R.string.onboarding_firefox_account_auto_signin_confirm) button.isEnabled = true FenixSnackbar.make( view = it, view = button, duration = Snackbar.LENGTH_SHORT, isDisplayedWithBrowserToolbar = false ).setText( it.context.getString(R.string.onboarding_firefox_account_automatic_signin_failed) context.getString(R.string.onboarding_firefox_account_automatic_signin_failed) ).show() } SignInWithShareableAccountResult.WillRetry, SignInWithShareableAccountResult.Success -> { Loading @@ -57,17 +74,6 @@ class OnboardingAutomaticSignInViewHolder(view: View) : RecyclerView.ViewHolder( } } } } } fun bind(account: ShareableAccount) { shareableAccount = account headerText.text = itemView.context.getString( R.string.onboarding_firefox_account_auto_signin_header_2, account.email ) val icon = getDrawable(itemView.context, R.drawable.ic_onboarding_avatar_anonymous) headerText.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon) } companion object { const val LAYOUT_ID = R.layout.onboarding_automatic_signin Loading app/src/test/java/org/mozilla/fenix/components/TestCore.kt +1 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ import mozilla.components.feature.pwa.WebAppShortcutManager class TestCore(context: Context) : Core(context) { override val engine = mockk<Engine>(relaxed = true) { every { this@mockk getProperty "settings" } returns mockk<Settings>() every { this@mockk getProperty "settings" } returns mockk<Settings>(relaxed = true) } override val sessionManager = SessionManager(engine) override val store = mockk<BrowserStore>() Loading app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolderTest.kt 0 → 100644 +105 −0 Original line number Diff line number Diff line /* 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.home.sessioncontrol.viewholders.onboarding import android.view.LayoutInflater import android.view.View import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject import io.mockk.unmockkObject import io.mockk.verify import kotlinx.android.synthetic.main.onboarding_automatic_signin.view.* import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runBlockingTest import mozilla.components.service.fxa.manager.SignInWithShareableAccountResult import mozilla.components.service.fxa.sharing.ShareableAccount import mozilla.components.support.test.robolectric.testContext import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.components.BackgroundServices import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.ext.components import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @ExperimentalCoroutinesApi @RunWith(FenixRobolectricTestRunner::class) class OnboardingAutomaticSignInViewHolderTest { private lateinit var view: View private lateinit var backgroundServices: BackgroundServices private lateinit var snackbar: FenixSnackbar @Before fun setup() { view = LayoutInflater.from(testContext) .inflate(OnboardingAutomaticSignInViewHolder.LAYOUT_ID, null) snackbar = mockk(relaxed = true) mockkObject(FenixSnackbar.Companion) backgroundServices = testContext.components.backgroundServices every { FenixSnackbar.make(any(), any(), any(), any()) } returns snackbar } @After fun teardown() { unmockkObject(FenixSnackbar.Companion) } @Test fun `bind updates header text`() { val holder = OnboardingAutomaticSignInViewHolder(view) holder.bind(mockk { every { email } returns "email@example.com" }) assertEquals( "You are signed in as email@example.com on another Firefox browser on this phone. Would you like to sign in with this account?", view.header_text.text ) assertTrue(view.turn_on_sync_button.isEnabled) } @Test fun `sign in on click`() = runBlocking { val account = mockk<ShareableAccount> { every { email } returns "email@example.com" } every { backgroundServices.accountManager.signInWithShareableAccountAsync(account) } returns CompletableDeferred(SignInWithShareableAccountResult.Success) val holder = OnboardingAutomaticSignInViewHolder(view, scope = this) holder.bind(account) holder.onClick(view.turn_on_sync_button) assertEquals("Signing in…", view.turn_on_sync_button.text) assertFalse(view.turn_on_sync_button.isEnabled) } @Test fun `show error if sign in fails`() = runBlockingTest { val account = mockk<ShareableAccount> { every { email } returns "email@example.com" } every { backgroundServices.accountManager.signInWithShareableAccountAsync(account) } returns CompletableDeferred(SignInWithShareableAccountResult.Failure) val holder = OnboardingAutomaticSignInViewHolder(view, scope = this) holder.bind(account) holder.onClick(view.turn_on_sync_button) assertEquals("Yes, sign me in", view.turn_on_sync_button.text) assertTrue(view.turn_on_sync_button.isEnabled) verify { snackbar.setText("Failed to sign-in") } } } app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingFinishViewHolderTest.kt 0 → 100644 +39 −0 Original line number Diff line number Diff line /* 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.home.sessioncontrol.viewholders.onboarding import android.view.LayoutInflater import android.view.View import io.mockk.mockk import io.mockk.verify import kotlinx.android.synthetic.main.onboarding_finish.view.* import mozilla.components.support.test.robolectric.testContext import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.home.sessioncontrol.OnboardingInteractor @RunWith(FenixRobolectricTestRunner::class) class OnboardingFinishViewHolderTest { private lateinit var view: View private lateinit var interactor: OnboardingInteractor @Before fun setup() { view = LayoutInflater.from(testContext) .inflate(OnboardingFinishViewHolder.LAYOUT_ID, null) interactor = mockk(relaxed = true) } @Test fun `call interactor on click`() { OnboardingFinishViewHolder(view, interactor) view.finish_button.performClick() verify { interactor.onStartBrowsingClicked() } } } app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingHeaderViewHolderTest.kt 0 → 100644 +34 −0 Original line number Diff line number Diff line /* 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.home.sessioncontrol.viewholders.onboarding import android.view.LayoutInflater import android.view.View import kotlinx.android.synthetic.main.onboarding_header.view.* import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class OnboardingHeaderViewHolderTest { private lateinit var view: View @Before fun setup() { view = LayoutInflater.from(testContext) .inflate(OnboardingHeaderViewHolder.LAYOUT_ID, null) } @Test fun `bind header text`() { OnboardingHeaderViewHolder(view) assertEquals("Welcome to Firefox Preview!", view.header_text.text) } } Loading
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolder.kt +37 −31 Original line number Diff line number Diff line Loading @@ -5,12 +5,14 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding import android.view.View import android.widget.Button import androidx.annotation.VisibleForTesting import androidx.appcompat.content.res.AppCompatResources.getDrawable import androidx.recyclerview.widget.RecyclerView import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.onboarding_automatic_signin.view.* import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch import mozilla.components.service.fxa.manager.SignInWithShareableAccountResult import mozilla.components.service.fxa.sharing.ShareableAccount Loading @@ -20,36 +22,51 @@ import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.ext.components class OnboardingAutomaticSignInViewHolder(view: View) : RecyclerView.ViewHolder(view) { class OnboardingAutomaticSignInViewHolder( view: View, private val scope: CoroutineScope = MainScope() ) : RecyclerView.ViewHolder(view) { private lateinit var shareableAccount: ShareableAccount private val headerText = view.header_text init { view.turn_on_sync_button.setOnClickListener { it.context.components.analytics.metrics.track(Event.OnboardingAutoSignIn) scope.launch { onClick(it.turn_on_sync_button) } } } it.turn_on_sync_button.text = it.context.getString( R.string.onboarding_firefox_account_signing_in fun bind(account: ShareableAccount) { shareableAccount = account headerText.text = itemView.context.getString( R.string.onboarding_firefox_account_auto_signin_header_2, account.email ) it.turn_on_sync_button.isEnabled = false val icon = getDrawable(itemView.context, R.drawable.ic_onboarding_avatar_anonymous) headerText.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon) } @VisibleForTesting internal suspend fun onClick(button: Button) { val context = button.context context.components.analytics.metrics.track(Event.OnboardingAutoSignIn) button.text = context.getString(R.string.onboarding_firefox_account_signing_in) button.isEnabled = false CoroutineScope(Dispatchers.Main).launch { val result = view.context.components.backgroundServices.accountManager .signInWithShareableAccountAsync(shareableAccount).await() when (result) { val accountManager = context.components.backgroundServices.accountManager when (accountManager.signInWithShareableAccountAsync(shareableAccount).await()) { SignInWithShareableAccountResult.Failure -> { // Failed to sign-in (e.g. bad credentials). Allow to try again. it.turn_on_sync_button.text = it.context.getString( R.string.onboarding_firefox_account_auto_signin_confirm ) it.turn_on_sync_button.isEnabled = true button.text = context.getString(R.string.onboarding_firefox_account_auto_signin_confirm) button.isEnabled = true FenixSnackbar.make( view = it, view = button, duration = Snackbar.LENGTH_SHORT, isDisplayedWithBrowserToolbar = false ).setText( it.context.getString(R.string.onboarding_firefox_account_automatic_signin_failed) context.getString(R.string.onboarding_firefox_account_automatic_signin_failed) ).show() } SignInWithShareableAccountResult.WillRetry, SignInWithShareableAccountResult.Success -> { Loading @@ -57,17 +74,6 @@ class OnboardingAutomaticSignInViewHolder(view: View) : RecyclerView.ViewHolder( } } } } } fun bind(account: ShareableAccount) { shareableAccount = account headerText.text = itemView.context.getString( R.string.onboarding_firefox_account_auto_signin_header_2, account.email ) val icon = getDrawable(itemView.context, R.drawable.ic_onboarding_avatar_anonymous) headerText.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon) } companion object { const val LAYOUT_ID = R.layout.onboarding_automatic_signin Loading
app/src/test/java/org/mozilla/fenix/components/TestCore.kt +1 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ import mozilla.components.feature.pwa.WebAppShortcutManager class TestCore(context: Context) : Core(context) { override val engine = mockk<Engine>(relaxed = true) { every { this@mockk getProperty "settings" } returns mockk<Settings>() every { this@mockk getProperty "settings" } returns mockk<Settings>(relaxed = true) } override val sessionManager = SessionManager(engine) override val store = mockk<BrowserStore>() Loading
app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingAutomaticSignInViewHolderTest.kt 0 → 100644 +105 −0 Original line number Diff line number Diff line /* 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.home.sessioncontrol.viewholders.onboarding import android.view.LayoutInflater import android.view.View import io.mockk.every import io.mockk.mockk import io.mockk.mockkObject import io.mockk.unmockkObject import io.mockk.verify import kotlinx.android.synthetic.main.onboarding_automatic_signin.view.* import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runBlockingTest import mozilla.components.service.fxa.manager.SignInWithShareableAccountResult import mozilla.components.service.fxa.sharing.ShareableAccount import mozilla.components.support.test.robolectric.testContext import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.components.BackgroundServices import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.ext.components import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @ExperimentalCoroutinesApi @RunWith(FenixRobolectricTestRunner::class) class OnboardingAutomaticSignInViewHolderTest { private lateinit var view: View private lateinit var backgroundServices: BackgroundServices private lateinit var snackbar: FenixSnackbar @Before fun setup() { view = LayoutInflater.from(testContext) .inflate(OnboardingAutomaticSignInViewHolder.LAYOUT_ID, null) snackbar = mockk(relaxed = true) mockkObject(FenixSnackbar.Companion) backgroundServices = testContext.components.backgroundServices every { FenixSnackbar.make(any(), any(), any(), any()) } returns snackbar } @After fun teardown() { unmockkObject(FenixSnackbar.Companion) } @Test fun `bind updates header text`() { val holder = OnboardingAutomaticSignInViewHolder(view) holder.bind(mockk { every { email } returns "email@example.com" }) assertEquals( "You are signed in as email@example.com on another Firefox browser on this phone. Would you like to sign in with this account?", view.header_text.text ) assertTrue(view.turn_on_sync_button.isEnabled) } @Test fun `sign in on click`() = runBlocking { val account = mockk<ShareableAccount> { every { email } returns "email@example.com" } every { backgroundServices.accountManager.signInWithShareableAccountAsync(account) } returns CompletableDeferred(SignInWithShareableAccountResult.Success) val holder = OnboardingAutomaticSignInViewHolder(view, scope = this) holder.bind(account) holder.onClick(view.turn_on_sync_button) assertEquals("Signing in…", view.turn_on_sync_button.text) assertFalse(view.turn_on_sync_button.isEnabled) } @Test fun `show error if sign in fails`() = runBlockingTest { val account = mockk<ShareableAccount> { every { email } returns "email@example.com" } every { backgroundServices.accountManager.signInWithShareableAccountAsync(account) } returns CompletableDeferred(SignInWithShareableAccountResult.Failure) val holder = OnboardingAutomaticSignInViewHolder(view, scope = this) holder.bind(account) holder.onClick(view.turn_on_sync_button) assertEquals("Yes, sign me in", view.turn_on_sync_button.text) assertTrue(view.turn_on_sync_button.isEnabled) verify { snackbar.setText("Failed to sign-in") } } }
app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingFinishViewHolderTest.kt 0 → 100644 +39 −0 Original line number Diff line number Diff line /* 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.home.sessioncontrol.viewholders.onboarding import android.view.LayoutInflater import android.view.View import io.mockk.mockk import io.mockk.verify import kotlinx.android.synthetic.main.onboarding_finish.view.* import mozilla.components.support.test.robolectric.testContext import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.home.sessioncontrol.OnboardingInteractor @RunWith(FenixRobolectricTestRunner::class) class OnboardingFinishViewHolderTest { private lateinit var view: View private lateinit var interactor: OnboardingInteractor @Before fun setup() { view = LayoutInflater.from(testContext) .inflate(OnboardingFinishViewHolder.LAYOUT_ID, null) interactor = mockk(relaxed = true) } @Test fun `call interactor on click`() { OnboardingFinishViewHolder(view, interactor) view.finish_button.performClick() verify { interactor.onStartBrowsingClicked() } } }
app/src/test/java/org/mozilla/fenix/home/sessioncontrol/viewholders/onboarding/OnboardingHeaderViewHolderTest.kt 0 → 100644 +34 −0 Original line number Diff line number Diff line /* 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.home.sessioncontrol.viewholders.onboarding import android.view.LayoutInflater import android.view.View import kotlinx.android.synthetic.main.onboarding_header.view.* import mozilla.components.support.test.robolectric.testContext import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class OnboardingHeaderViewHolderTest { private lateinit var view: View @Before fun setup() { view = LayoutInflater.from(testContext) .inflate(OnboardingHeaderViewHolder.LAYOUT_ID, null) } @Test fun `bind header text`() { OnboardingHeaderViewHolder(view) assertEquals("Welcome to Firefox Preview!", view.header_text.text) } }