For #4231 added unit tests for most recent apps

fennec/beta
Mihai Branescu 5 years ago committed by Emily Kager
parent fdbf63fb97
commit 9d972fa1d0

@ -45,7 +45,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
mDevice.waitNotNull( mDevice.waitNotNull(
Until.findObject( Until.findObject(
By.text("SHARE A LINK") By.text("ALL ACTIONS")
), waitingTime ), waitingTime
) )
} }
@ -55,7 +55,7 @@ class LibrarySubMenusMultipleSelectionToolbarRobot {
mDevice.waitNotNull( mDevice.waitNotNull(
Until.findObject( Until.findObject(
By.text("SHARE A LINK") By.text("ALL ACTIONS")
), waitingTime ), waitingTime
) )
} }

@ -48,7 +48,7 @@ class ThreeDotMenuMainRobot {
fun verifyReaderViewAppearance(visible: Boolean) = assertReaderViewAppearanceButton(visible) fun verifyReaderViewAppearance(visible: Boolean) = assertReaderViewAppearanceButton(visible)
fun clickShareButton() { fun clickShareButton() {
shareButton().click() shareButton().click()
mDevice.waitNotNull(Until.findObject(By.text("SHARE A LINK")), waitingTime) mDevice.waitNotNull(Until.findObject(By.text("ALL ACTIONS")), waitingTime)
} }
fun verifyShareTabButton() = assertShareTabButton() fun verifyShareTabButton() = assertShareTabButton()
@ -293,7 +293,7 @@ private fun assertSendToDeviceTitle() = SendToDeviceTitle()
.check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE))) .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
private fun ShareALinkTitle() = private fun ShareALinkTitle() =
onView(allOf(withText(R.string.share_link_all_apps_subheader), withResourceName("apps_link_header"))) onView(allOf(withText("ALL ACTIONS"), withResourceName("apps_link_header")))
private fun assertShareALinkTitle() = ShareALinkTitle() private fun assertShareALinkTitle() = ShareALinkTitle()

@ -31,12 +31,13 @@ import org.mozilla.fenix.share.listadapters.SyncShareOption
class ShareViewModel(application: Application) : AndroidViewModel(application) { class ShareViewModel(application: Application) : AndroidViewModel(application) {
companion object { companion object {
private const val RECENT_APPS_LIMIT = 6 internal const val RECENT_APPS_LIMIT = 6
} }
private val connectivityManager by lazy { application.getSystemService<ConnectivityManager>() } private val connectivityManager by lazy { application.getSystemService<ConnectivityManager>() }
private val fxaAccountManager = application.components.backgroundServices.accountManager private val fxaAccountManager = application.components.backgroundServices.accountManager
private val recentAppsStorage = RecentAppsStorage(application.applicationContext) @VisibleForTesting
internal var recentAppsStorage = RecentAppsStorage(application.applicationContext)
private val devicesListLiveData = MutableLiveData<List<SyncShareOption>>(emptyList()) private val devicesListLiveData = MutableLiveData<List<SyncShareOption>>(emptyList())
private val appsListLiveData = MutableLiveData<List<AppShareOption>>(emptyList()) private val appsListLiveData = MutableLiveData<List<AppShareOption>>(emptyList())
@ -131,8 +132,9 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) {
connectivityManager?.unregisterNetworkCallback(networkCallback) connectivityManager?.unregisterNetworkCallback(networkCallback)
} }
@VisibleForTesting
@WorkerThread @WorkerThread
private fun getIntentActivities(shareIntent: Intent, context: Context): List<ResolveInfo>? { fun getIntentActivities(shareIntent: Intent, context: Context): List<ResolveInfo>? {
return context.packageManager.queryIntentActivities(shareIntent, 0) return context.packageManager.queryIntentActivities(shareIntent, 0)
} }

@ -22,9 +22,9 @@ import io.mockk.slot
import io.mockk.verify import io.mockk.verify
import io.mockk.verifyOrder import io.mockk.verifyOrder
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.ObsoleteCoroutinesApi import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineScope
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.feature.session.SessionUseCases import mozilla.components.feature.session.SessionUseCases
import mozilla.components.feature.sitepermissions.SitePermissions import mozilla.components.feature.sitepermissions.SitePermissions
@ -42,16 +42,17 @@ import org.mozilla.fenix.utils.Settings
import org.robolectric.RobolectricTestRunner import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config import org.robolectric.annotation.Config
@ExperimentalCoroutinesApi
@UseExperimental(ObsoleteCoroutinesApi::class) @UseExperimental(ObsoleteCoroutinesApi::class)
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class) @Config(application = TestApplication::class)
class DefaultQuickSettingsControllerTest { class DefaultQuickSettingsControllerTest {
private val context = testContext private val context = testContext
private val store = mockk<QuickSettingsFragmentStore>() private val store = mockk<QuickSettingsFragmentStore>()
private val coroutinesScope = GlobalScope private val coroutinesScope = TestCoroutineScope()
private val navController = mockk<NavController>(relaxed = true) private val navController = mockk<NavController>(relaxed = true)
private val browserSession = mockk<Session>() private val browserSession = mockk<Session>()
private val sitePermissions = SitePermissions(origin = "", savedAt = 123) private val sitePermissions: SitePermissions = SitePermissions(origin = "", savedAt = 123)
private val appSettings = mockk<Settings>(relaxed = true) private val appSettings = mockk<Settings>(relaxed = true)
private val permissionStorage = mockk<PermissionStorage>(relaxed = true) private val permissionStorage = mockk<PermissionStorage>(relaxed = true)
private val reload = mockk<SessionUseCases.ReloadUrlUseCase>(relaxed = true) private val reload = mockk<SessionUseCases.ReloadUrlUseCase>(relaxed = true)
@ -121,9 +122,8 @@ class DefaultQuickSettingsControllerTest {
// We want to verify that the Status is toggled and this event is passed to Controller also. // We want to verify that the Status is toggled and this event is passed to Controller also.
assertThat(sitePermissions.camera).isSameAs(NO_DECISION) assertThat(sitePermissions.camera).isSameAs(NO_DECISION)
verifyOrder { verifyOrder {
sitePermissions.toggle(capture(toggledFeature)).also { val permission = sitePermissions.toggle(capture(toggledFeature))
controller.handlePermissionsChange(it) controller.handlePermissionsChange(permission)
}
} }
// We should also modify View's state. Not necessarily as the last operation. // We should also modify View's state. Not necessarily as the last operation.
verify { verify {

@ -22,11 +22,15 @@ import io.mockk.slot
import io.mockk.spyk import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import io.mockk.verifyOrder import io.mockk.verifyOrder
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineScope
import mozilla.components.concept.engine.prompt.ShareData import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.sync.Device import mozilla.components.concept.sync.Device
import mozilla.components.concept.sync.DeviceType import mozilla.components.concept.sync.DeviceType
import mozilla.components.concept.sync.TabData import mozilla.components.concept.sync.TabData
import mozilla.components.feature.accounts.push.SendTabUseCases import mozilla.components.feature.accounts.push.SendTabUseCases
import mozilla.components.feature.share.RecentAppsStorage
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -44,6 +48,7 @@ import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class) @Config(application = TestApplication::class)
@ExperimentalCoroutinesApi
class ShareControllerTest { class ShareControllerTest {
// Need a valid context to retrieve Strings for example, but we also need it to return our "metrics" // Need a valid context to retrieve Strings for example, but we also need it to return our "metrics"
private val context: Context = spyk(testContext) private val context: Context = spyk(testContext)
@ -58,12 +63,15 @@ class ShareControllerTest {
TabData("title1", "url1") TabData("title1", "url1")
) )
private val textToShare = "${shareData[0].title} ${shareData[0].url}\n\n${shareData[1].title} ${shareData[1].url}" private val textToShare = "${shareData[0].title} ${shareData[0].url}\n\n${shareData[1].title} ${shareData[1].url}"
private val testCoroutineScope = TestCoroutineScope()
private val sendTabUseCases = mockk<SendTabUseCases>(relaxed = true) private val sendTabUseCases = mockk<SendTabUseCases>(relaxed = true)
private val snackbar = mockk<FenixSnackbar>(relaxed = true) private val snackbar = mockk<FenixSnackbar>(relaxed = true)
private val navController = mockk<NavController>(relaxed = true) private val navController = mockk<NavController>(relaxed = true)
private val dismiss = mockk<(ShareController.Result) -> Unit>(relaxed = true) private val dismiss = mockk<(ShareController.Result) -> Unit>(relaxed = true)
private val recentAppStorage = mockk<RecentAppsStorage>(relaxed = true)
private val controller = DefaultShareController( private val controller = DefaultShareController(
context, shareData, sendTabUseCases, snackbar, navController, dismiss context, shareData, sendTabUseCases, snackbar, navController,
recentAppStorage, testCoroutineScope, dismiss
) )
@Before @Before
@ -79,7 +87,7 @@ class ShareControllerTest {
} }
@Test @Test
fun `handleShareToApp should start a new sharing activity and close this`() { fun `handleShareToApp should start a new sharing activity and close this`() = runBlocking {
val appPackageName = "package" val appPackageName = "package"
val appClassName = "activity" val appClassName = "activity"
val appShareOption = AppShareOption("app", mockk(), appPackageName, appClassName) val appShareOption = AppShareOption("app", mockk(), appPackageName, appClassName)
@ -88,8 +96,10 @@ class ShareControllerTest {
// needed for capturing the actual Intent used the `slot` one doesn't have this flag so we // needed for capturing the actual Intent used the `slot` one doesn't have this flag so we
// need to use an Activity Context. // need to use an Activity Context.
val activityContext: Context = mockk<Activity>() val activityContext: Context = mockk<Activity>()
val testController = DefaultShareController(activityContext, shareData, mockk(), mockk(), mockk(), dismiss) val testController = DefaultShareController(activityContext, shareData, mockk(), mockk(), mockk(),
recentAppStorage, testCoroutineScope, dismiss)
every { activityContext.startActivity(capture(shareIntent)) } just Runs every { activityContext.startActivity(capture(shareIntent)) } just Runs
every { recentAppStorage.updateRecentApp(appShareOption.packageName) } just Runs
testController.handleShareToApp(appShareOption) testController.handleShareToApp(appShareOption)
@ -104,6 +114,7 @@ class ShareControllerTest {
assertThat(shareIntent.captured.component!!.className).isEqualTo(appClassName) assertThat(shareIntent.captured.component!!.className).isEqualTo(appClassName)
} }
verifyOrder { verifyOrder {
recentAppStorage.updateRecentApp(appShareOption.packageName)
activityContext.startActivity(shareIntent.captured) activityContext.startActivity(shareIntent.captured)
dismiss(ShareController.Result.SUCCESS) dismiss(ShareController.Result.SUCCESS)
} }
@ -119,7 +130,8 @@ class ShareControllerTest {
// needed for capturing the actual Intent used the `slot` one doesn't have this flag so we // needed for capturing the actual Intent used the `slot` one doesn't have this flag so we
// need to use an Activity Context. // need to use an Activity Context.
val activityContext: Context = mockk<Activity>() val activityContext: Context = mockk<Activity>()
val testController = DefaultShareController(activityContext, shareData, mockk(), snackbar, mockk(), dismiss) val testController = DefaultShareController(activityContext, shareData, mockk(), snackbar,
mockk(), mockk(), testCoroutineScope, dismiss)
every { activityContext.startActivity(capture(shareIntent)) } throws SecurityException() every { activityContext.startActivity(capture(shareIntent)) } throws SecurityException()
every { activityContext.getString(R.string.share_error_snackbar) } returns "Cannot share to this app" every { activityContext.getString(R.string.share_error_snackbar) } returns "Cannot share to this app"
@ -242,7 +254,14 @@ class ShareControllerTest {
@Test @Test
fun `getSuccessMessage should return different strings depending on the number of shared tabs`() { fun `getSuccessMessage should return different strings depending on the number of shared tabs`() {
val controllerWithOneSharedTab = DefaultShareController( val controllerWithOneSharedTab = DefaultShareController(
context, listOf(ShareData(url = "url0", title = "title0")), mockk(), mockk(), mockk(), mockk() context,
listOf(ShareData(url = "url0", title = "title0")),
mockk(),
mockk(),
mockk(),
mockk(),
mockk(),
mockk()
) )
val controllerWithMoreSharedTabs = controller val controllerWithMoreSharedTabs = controller
val expectedTabSharedMessage = context.getString(R.string.sync_sent_tab_snackbar) val expectedTabSharedMessage = context.getString(R.string.sync_sent_tab_snackbar)

@ -11,12 +11,19 @@ import android.content.pm.ResolveInfo
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.ConnectivityManager import android.net.ConnectivityManager
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just
import io.mockk.mockk import io.mockk.mockk
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.spyk import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.runBlockingTest
import mozilla.components.feature.share.RecentApp
import mozilla.components.feature.share.RecentAppsStorage
import mozilla.components.service.fxa.manager.FxaAccountManager import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.support.test.robolectric.testContext import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -27,6 +34,7 @@ import org.mozilla.fenix.TestApplication
import org.mozilla.fenix.ext.application import org.mozilla.fenix.ext.application
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.isOnline import org.mozilla.fenix.ext.isOnline
import org.mozilla.fenix.share.ShareViewModel.Companion.RECENT_APPS_LIMIT
import org.mozilla.fenix.share.listadapters.AppShareOption import org.mozilla.fenix.share.listadapters.AppShareOption
import org.mozilla.fenix.share.listadapters.SyncShareOption import org.mozilla.fenix.share.listadapters.SyncShareOption
import org.robolectric.RobolectricTestRunner import org.robolectric.RobolectricTestRunner
@ -34,6 +42,7 @@ import org.robolectric.annotation.Config
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
@Config(application = TestApplication::class) @Config(application = TestApplication::class)
@ExperimentalCoroutinesApi
class ShareViewModelTest { class ShareViewModelTest {
private val packageName = "org.mozilla.fenix" private val packageName = "org.mozilla.fenix"
@ -67,10 +76,38 @@ class ShareViewModelTest {
} }
@Test @Test
fun `loadDevicesAndApps registers networkCallback`() = runBlocking { fun `loadDevicesAndApps`() = runBlockingTest {
mockkStatic(Dispatchers::class)
every {
Dispatchers.IO
} returns TestCoroutineDispatcher()
viewModel = spyk(viewModel)
val drawable: Drawable = mockk()
val appOptions = ArrayList<AppShareOption>()
val appElement = AppShareOption("Label", drawable, "Package", "Activity")
appOptions.add(appElement)
val recentAppOptions = ArrayList<RecentApp>()
val appEntity: RecentApp = mockk()
every { appEntity.packageName } returns "Package"
recentAppOptions.add(appEntity)
val storage: RecentAppsStorage = mockk(relaxed = true)
viewModel.recentAppsStorage = storage
every { viewModel.buildAppsList(any(), any()) } returns appOptions
every { storage.updateDatabaseWithNewApps(appOptions.map { app -> app.packageName }) } just Runs
every { storage.getRecentAppsUpTo(RECENT_APPS_LIMIT) } returns recentAppOptions
viewModel.loadDevicesAndApps() viewModel.loadDevicesAndApps()
verify { connectivityManager.registerNetworkCallback(any(), eq(viewModel.networkCallback)) } verify {
connectivityManager.registerNetworkCallback(
any(),
any<ConnectivityManager.NetworkCallback>()
)
}
assertEquals(1, viewModel.recentAppsList.value?.size)
assertEquals(0, viewModel.appsList.value?.size)
} }
@Test @Test
@ -115,7 +152,10 @@ class ShareViewModelTest {
every { fxaAccountManager.authenticatedAccount() } returns mockk() every { fxaAccountManager.authenticatedAccount() } returns mockk()
every { fxaAccountManager.accountNeedsReauth() } returns true every { fxaAccountManager.accountNeedsReauth() } returns true
assertEquals(listOf(SyncShareOption.Reconnect), viewModel.buildDeviceList(fxaAccountManager)) assertEquals(
listOf(SyncShareOption.Reconnect),
viewModel.buildDeviceList(fxaAccountManager)
)
} }
private fun createResolveInfo( private fun createResolveInfo(

Loading…
Cancel
Save