From 1ab5fe3eb967918af92ba226739a678e31e4919c Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Mon, 6 Jul 2020 13:04:43 -0700 Subject: [PATCH] Add method to test fragments in roboletric (#12261) --- .../java/org/mozilla/fenix/HomeActivity.kt | 6 +-- .../java/org/mozilla/fenix/NavHostActivity.kt | 20 ++++++++ .../addons/AddonPermissionsDetailsFragment.kt | 16 +++---- .../java/org/mozilla/fenix/ext/Fragment.kt | 4 +- .../library/bookmarks/BookmarkFragment.kt | 4 +- .../bookmarks/edit/EditBookmarkFragment.kt | 16 +++---- .../search/AddSearchEngineFragment.kt | 5 +- .../SitePermissionsExceptionsFragment.kt | 4 +- .../org/mozilla/fenix/MockNavHostActivity.kt | 48 +++++++++++++++++++ .../AddonPermissionsDetailsFragmentTest.kt | 47 ++++++++++++++++++ 10 files changed, 140 insertions(+), 30 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/NavHostActivity.kt create mode 100644 app/src/test/java/org/mozilla/fenix/MockNavHostActivity.kt create mode 100644 app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragmentTest.kt diff --git a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt index 541dbf6dc..c59a39990 100644 --- a/app/src/main/java/org/mozilla/fenix/HomeActivity.kt +++ b/app/src/main/java/org/mozilla/fenix/HomeActivity.kt @@ -63,8 +63,8 @@ import org.mozilla.fenix.exceptions.ExceptionsFragmentDirections import org.mozilla.fenix.ext.alreadyOnDestination import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.nav -import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.resetPoliciesAfter +import org.mozilla.fenix.ext.settings import org.mozilla.fenix.home.HomeFragmentDirections import org.mozilla.fenix.home.intent.CrashReporterIntentProcessor import org.mozilla.fenix.home.intent.DeepLinkIntentProcessor @@ -100,7 +100,7 @@ import org.mozilla.fenix.utils.RunWhenReadyQueue * - browser screen */ @SuppressWarnings("TooManyFunctions", "LargeClass") -open class HomeActivity : LocaleAwareAppCompatActivity() { +open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity { private var webExtScope: CoroutineScope? = null lateinit var themeManager: ThemeManager @@ -392,7 +392,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity() { * Returns the [supportActionBar], inflating it if necessary. * Everyone should call this instead of supportActionBar. */ - fun getSupportActionBarAndInflateIfNecessary(): ActionBar { + override fun getSupportActionBarAndInflateIfNecessary(): ActionBar { if (!isToolbarInflated) { navigationToolbar = navigationToolbarStub.inflate() as Toolbar diff --git a/app/src/main/java/org/mozilla/fenix/NavHostActivity.kt b/app/src/main/java/org/mozilla/fenix/NavHostActivity.kt new file mode 100644 index 000000000..a194c0eb4 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/NavHostActivity.kt @@ -0,0 +1,20 @@ +/* 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 + +import androidx.appcompat.app.ActionBar + +/** + * Interface for the main activity in a single-activity architecture. + * All fragments will be displayed inside this activity. + */ +interface NavHostActivity { + + /** + * Returns the support action bar, inflating it if necessary. + * Everyone should call this instead of supportActionBar. + */ + fun getSupportActionBarAndInflateIfNecessary(): ActionBar +} diff --git a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt index 933b01e2c..28ef5e567 100644 --- a/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragment.kt @@ -5,10 +5,11 @@ package org.mozilla.fenix.addons import android.content.Intent -import android.net.Uri +import android.content.Intent.ACTION_VIEW import android.os.Bundle import android.view.View import androidx.annotation.StringRes +import androidx.core.net.toUri import androidx.fragment.app.Fragment import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager @@ -26,7 +27,7 @@ private const val LEARN_MORE_URL = /** * A fragment to show the permissions of an add-on. */ -class AddonPermissionsDetailsFragment : Fragment(R.layout.fragment_add_on_permissions), View.OnClickListener { +class AddonPermissionsDetailsFragment : Fragment(R.layout.fragment_add_on_permissions) { private val args by navArgs() @@ -55,12 +56,9 @@ class AddonPermissionsDetailsFragment : Fragment(R.layout.fragment_add_on_permis } private fun bindLearnMore(view: View) { - view.learn_more_label.setOnClickListener(this) - } - - override fun onClick(v: View?) { - val intent = - Intent(Intent.ACTION_VIEW).setData(Uri.parse(LEARN_MORE_URL)) - startActivity(intent) + view.learn_more_label.setOnClickListener { + val intent = Intent(ACTION_VIEW, LEARN_MORE_URL.toUri()) + startActivity(intent) + } } } diff --git a/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt b/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt index 7da50f968..92433aae5 100644 --- a/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt +++ b/app/src/main/java/org/mozilla/fenix/ext/Fragment.kt @@ -13,7 +13,7 @@ import androidx.navigation.NavOptions import androidx.navigation.Navigator import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.findNavController -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.Components @@ -43,7 +43,7 @@ fun Fragment.getPreferenceKey(@StringRes resourceId: Int): String = getString(re */ fun Fragment.showToolbar(title: String) { (requireActivity() as AppCompatActivity).title = title - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary().show() } /** diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt index 6507c8668..decb6bef8 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkFragment.kt @@ -37,7 +37,7 @@ import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.support.base.feature.UserInteractionHandler -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.StoreProvider @@ -147,7 +147,7 @@ class BookmarkFragment : LibraryPageFragment(), UserInteractionHan override fun onResume() { super.onResume() - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary().show() // Reload bookmarks when returning to this fragment in case they have been edited val args by navArgs() diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt index 1c2ece81c..a578b898f 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/edit/EditBookmarkFragment.kt @@ -31,7 +31,7 @@ import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.support.ktx.android.content.getColorFromAttr import mozilla.components.support.ktx.android.view.hideKeyboard -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.metrics.Event @@ -111,15 +111,13 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) { } private fun initToolbar() { - val activity = activity as? AppCompatActivity - val actionBar = (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary() + val activity = activity as AppCompatActivity + val actionBar = (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary() val toolbar = activity.findViewById(R.id.navigationToolbar) - context?.let { - toolbar?.setToolbarColors( - foreground = it.getColorFromAttr(R.attr.primaryText), - background = it.getColorFromAttr(R.attr.foundation) - ) - } + toolbar?.setToolbarColors( + foreground = activity.getColorFromAttr(R.attr.primaryText), + background = activity.getColorFromAttr(R.attr.foundation) + ) actionBar.show() } diff --git a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt index 5df5129bc..f210513db 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/search/AddSearchEngineFragment.kt @@ -14,7 +14,6 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.CompoundButton -import androidx.appcompat.app.AppCompatActivity import androidx.constraintlayout.widget.ConstraintLayout import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope @@ -36,6 +35,7 @@ import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.searchengine.CustomSearchEngineStore import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.ext.showToolbar import org.mozilla.fenix.settings.SupportUtils import java.util.Locale @@ -115,8 +115,7 @@ class AddSearchEngineFragment : Fragment(), CompoundButton.OnCheckedChangeListen override fun onResume() { super.onResume() - (activity as AppCompatActivity).title = getString(R.string.search_engine_add_custom_search_engine_title) - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + showToolbar(getString(R.string.search_engine_add_custom_search_engine_title)) } override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { diff --git a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt index f177e0cd4..813e24591 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/sitepermissions/SitePermissionsExceptionsFragment.kt @@ -28,7 +28,7 @@ import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.launch import mozilla.components.feature.sitepermissions.SitePermissions -import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.NavHostActivity import org.mozilla.fenix.R import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.loadIntoView @@ -44,7 +44,7 @@ class SitePermissionsExceptionsFragment : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - (activity as HomeActivity).getSupportActionBarAndInflateIfNecessary().show() + (activity as NavHostActivity).getSupportActionBarAndInflateIfNecessary().show() } override fun onViewCreated(rootView: View, savedInstanceState: Bundle?) { diff --git a/app/src/test/java/org/mozilla/fenix/MockNavHostActivity.kt b/app/src/test/java/org/mozilla/fenix/MockNavHostActivity.kt new file mode 100644 index 000000000..b6d40b6ac --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/MockNavHostActivity.kt @@ -0,0 +1,48 @@ +/* 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 + +import androidx.appcompat.app.ActionBar +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import io.mockk.mockk +import org.robolectric.Robolectric + +class MockNavHostActivity : AppCompatActivity(), NavHostActivity { + + private val mockActionBar = mockk(relaxed = true) + + override fun getSupportActionBarAndInflateIfNecessary() = mockActionBar +} + +/** + * Set up an added [Fragment] to a [FragmentActivity] that has been initialized to a resumed state. + * + * Variant of [mozilla.components.support.test.robolectric.createAddedTestFragment] that uses + * a custom Fenix activity to hold the fragment. + * + * @param fragmentTag the name that will be used to tag the fragment inside the [FragmentManager]. + * @param fragmentFactory a lambda function that returns a Fragment that will be added to the Activity. + * + * @return The same [Fragment] that was returned from [fragmentFactory] after it got added to the + * Activity. + */ +inline fun createAddedTestFragmentInNavHostActivity( + fragmentTag: String = "test", + fragmentFactory: () -> T +): T { + val activity = Robolectric.buildActivity(MockNavHostActivity::class.java) + .create() + .start() + .resume() + .get() + + return fragmentFactory().also { + activity.supportFragmentManager.beginTransaction() + .add(it, fragmentTag) + .commitNow() + } +} diff --git a/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragmentTest.kt b/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragmentTest.kt new file mode 100644 index 000000000..3c767fe89 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/addons/AddonPermissionsDetailsFragmentTest.kt @@ -0,0 +1,47 @@ +/* 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.addons + +import android.content.Intent.ACTION_VIEW +import androidx.core.net.toUri +import kotlinx.android.synthetic.main.fragment_add_on_permissions.* +import mozilla.components.feature.addons.Addon +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import org.mozilla.fenix.createAddedTestFragmentInNavHostActivity +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner +import org.robolectric.Shadows.shadowOf + +@RunWith(FenixRobolectricTestRunner::class) +class AddonPermissionsDetailsFragmentTest { + + private val addon = Addon( + id = "", + translatableName = mapOf( + Addon.DEFAULT_LOCALE to "Some blank addon" + ) + ) + + @Test + fun `trigger view intent when learn more is clicked`() { + val fragment = createAddedTestFragmentInNavHostActivity { + AddonPermissionsDetailsFragment().apply { + arguments = AddonPermissionsDetailsFragmentArgs(addon).toBundle() + } + } + + assertEquals("Some blank addon", fragment.activity?.title) + + fragment.learn_more_label.performClick() + + val intent = shadowOf(fragment.activity).peekNextStartedActivity() + assertEquals(ACTION_VIEW, intent.action) + assertEquals( + "https://support.mozilla.org/kb/permission-request-messages-firefox-extensions".toUri(), + intent.data + ) + } +}