For #23893 - Add telemetry for Contile services

upstream-sync
Gabriel Luong 2 years ago committed by mergify[bot]
parent ae1a2f3625
commit 56022546f2

@ -4786,6 +4786,7 @@ voice_search:
tags:
- Search
- Voice
top_sites:
open_default:
type: event
@ -5088,6 +5089,141 @@ top_sites:
notification_emails:
- android-probes@mozilla.com
expires: 111
context_id:
type: uuid
description: |
A UUID that is unjoinable with other browser metrics. This ID will not be
shared with AdM, only for internal uses. This ID is shared across all
contextual services features.
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- highly_sensitive
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_tile_id:
type: quantity
description: |
A unique identifier provided by the AdM for the sponsored TopSites tile
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- technical
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
unit: integer
metadata:
tags:
- TopSites
contile_advertiser:
type: string
description: |
Advertiser brand for the sponsored TopSites tile
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- technical
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_reporting_url:
type: url
description: |
The AdM reporting endpoint (impression_url for “impression” event,
click_url for “click” event).
lifetime: ping
send_in_pings:
- topsites-impression
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- technical
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_impression:
type: event
description: |
A user saw a Contile top site
extra_keys:
source:
description: The source of the event, example "newtab", "urlbar"
type: string
position:
description: The tile placement (1-based)
type: quantity
send_in_pings:
- topsites-impression
- events
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
contile_click:
type: event
description: |
A user clicked a Contile top site
extra_keys:
source:
description: The source of the event, example "newtab", "urlbar"
type: string
position:
description: The tile placement (1-based)
type: quantity
send_in_pings:
- topsites-impression
- events
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
data_sensitivity:
- interaction
notification_emails:
- android-probes@mozilla.com
expires: 112
metadata:
tags:
- TopSites
app_theme:
dark_theme_selected:
@ -5113,7 +5249,6 @@ app_theme:
notification_emails:
- android-probes@mozilla.com
expires: 108
metadata:
tags:
- Themes

@ -30,3 +30,16 @@ first-session:
- https://github.com/mozilla-mobile/fenix/pull/8074#issuecomment-586512202
notification_emails:
- android-probes@mozilla.com
topsites-impression:
description: |
Recorded when a sponsored top site is rendered and visible on the home
screen. Visibility is qualified as when the homepage is brought to the
front of the Browser, and sponsored tiles are 100% visible on screen.
include_client_id: false
bugs:
- https://github.com/mozilla-mobile/fenix/issues/23893
data_reviews:
- https://github.com/mozilla-mobile/fenix/pull/23945
notification_emails:
- android-probes@mozilla.com

@ -62,6 +62,7 @@ import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.GleanMetrics.PerfStartup
import org.mozilla.fenix.GleanMetrics.Preferences
import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.components.Core
import org.mozilla.fenix.components.metrics.Event
@ -84,6 +85,7 @@ import org.mozilla.fenix.telemetry.TelemetryLifecycleObserver
import org.mozilla.fenix.utils.BrowsersCache
import org.mozilla.fenix.utils.Settings
import org.mozilla.fenix.utils.Settings.Companion.TOP_SITES_PROVIDER_MAX_THRESHOLD
import java.util.UUID
import java.util.concurrent.TimeUnit
/**
@ -578,6 +580,12 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
defaultMozBrowser.set(it)
}
if (settings.contileContextId.isEmpty()) {
settings.contileContextId = TopSites.contextId.generateAndSet().toString()
} else {
TopSites.contextId.set(UUID.fromString(settings.contileContextId))
}
mozillaProducts.set(mozillaProductDetector.getInstalledMozillaProducts(applicationContext))
adjustCampaign.set(settings.adjustCampaignId)

@ -331,6 +331,14 @@ sealed class Event {
get() = hashMapOf(TopSites.longPressKeys.type to topSite.name())
}
data class TopSiteContileImpression(val position: Int, val source: Source) : Event() {
enum class Source { NEWTAB }
}
data class TopSiteContileClick(val position: Int, val source: Source) : Event() {
enum class Source { NEWTAB }
}
data class OnboardingToolbarPosition(val position: Position) : Event() {
enum class Position { TOP, BOTTOM }

@ -558,6 +558,26 @@ private val Event.wrapper: EventWrapper<*>?
{ TopSites.swipeCarousel.record(it) },
{ TopSites.swipeCarouselKeys.valueOf(it) }
)
is Event.TopSiteContileImpression -> EventWrapper<NoExtraKeys>(
{
TopSites.contileImpression.record(
TopSites.ContileImpressionExtra(
position = this.position,
source = this.source.name.lowercase()
)
)
}
)
is Event.TopSiteContileClick -> EventWrapper<NoExtraKeys>(
{
TopSites.contileClick.record(
TopSites.ContileClickExtra(
position = this.position,
source = this.source.name.lowercase()
)
)
}
)
is Event.PocketTopSiteClicked -> EventWrapper<NoExtraKeys>(
{ Pocket.pocketTopSiteClicked.record(it) }
)

@ -29,6 +29,8 @@ import mozilla.components.support.ktx.android.view.showKeyboard
import mozilla.components.support.ktx.kotlin.isUrl
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragmentDirections
@ -119,7 +121,7 @@ interface SessionControlController {
/**
* @see [TopSiteInteractor.onSelectTopSite]
*/
fun handleSelectTopSite(topSite: TopSite)
fun handleSelectTopSite(topSite: TopSite, position: Int)
/**
* @see [TopSiteInteractor.onSettingsClicked]
@ -391,7 +393,7 @@ class DefaultSessionControlController(
metrics.track(Event.CollectionRenamePressed)
}
override fun handleSelectTopSite(topSite: TopSite) {
override fun handleSelectTopSite(topSite: TopSite, position: Int) {
dismissSearchDialogIfDisplayed()
metrics.track(Event.TopSiteOpenInNewTab)
@ -401,7 +403,9 @@ class DefaultSessionControlController(
is TopSite.Default -> Event.TopSiteOpenDefault
is TopSite.Frecent -> Event.TopSiteOpenFrecent
is TopSite.Pinned -> Event.TopSiteOpenPinned
is TopSite.Provided -> Event.TopSiteOpenProvided
is TopSite.Provided -> Event.TopSiteOpenProvided.also {
submitTopSitesImpressionPing(topSite, position)
}
}
)
@ -435,6 +439,21 @@ class DefaultSessionControlController(
activity.openToBrowser(BrowserDirection.FromHome)
}
@VisibleForTesting
internal fun submitTopSitesImpressionPing(topSite: TopSite.Provided, position: Int) {
metrics.track(
Event.TopSiteContileClick(
position = position + 1,
source = Event.TopSiteContileClick.Source.NEWTAB
)
)
topSite.id?.let { TopSites.contileTileId.set(it) }
topSite.title?.let { TopSites.contileAdvertiser.set(it.lowercase()) }
TopSites.contileReportingUrl.set(topSite.clickUrl)
Pings.topsitesImpression.submit()
}
override fun handleTopSiteSettingsClicked() {
metrics.track(Event.TopSiteContileSettings)
navController.nav(

@ -211,8 +211,9 @@ interface TopSiteInteractor {
* Selects the given top site. Called when a user clicks on a top site.
*
* @param topSite The top site that was selected.
* @param position The position of the top site.
*/
fun onSelectTopSite(topSite: TopSite)
fun onSelectTopSite(topSite: TopSite, position: Int)
/**
* Navigates to the Homepage Settings. Called when an user clicks on the "Settings" top site
@ -310,8 +311,8 @@ class SessionControlInteractor(
controller.handleRenameCollectionTapped(collection)
}
override fun onSelectTopSite(topSite: TopSite) {
controller.handleSelectTopSite(topSite)
override fun onSelectTopSite(topSite: TopSite, position: Int) {
controller.handleSelectTopSite(topSite, position)
}
override fun onSettingsClicked() {

@ -8,6 +8,7 @@ import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
import android.widget.PopupWindow
import androidx.annotation.VisibleForTesting
import androidx.appcompat.content.res.AppCompatResources.getDrawable
import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
@ -17,6 +18,8 @@ import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.components.feature.top.sites.TopSite
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.R
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.databinding.TopSiteItemBinding
@ -36,10 +39,6 @@ class TopSiteItemViewHolder(
private val binding = TopSiteItemBinding.bind(view)
init {
binding.topSiteItem.setOnClickListener {
interactor.onSelectTopSite(topSite)
}
binding.topSiteItem.setOnLongClickListener {
interactor.onTopSiteMenuOpened()
it.context.components.analytics.metrics.track(Event.TopSiteLongPress(topSite))
@ -72,7 +71,11 @@ class TopSiteItemViewHolder(
}
}
fun bind(topSite: TopSite) {
fun bind(topSite: TopSite, position: Int) {
binding.topSiteItem.setOnClickListener {
interactor.onSelectTopSite(topSite, position)
}
binding.topSiteTitle.text = topSite.title
if (topSite is TopSite.Pinned || topSite is TopSite.Default) {
@ -89,6 +92,7 @@ class TopSiteItemViewHolder(
itemView.context.components.core.client.bitmapForUrl(topSite.imageUrl)?.let { bitmap ->
withContext(Main) {
binding.faviconImage.setImageBitmap(bitmap)
submitTopSitesImpressionPing(topSite, position)
}
}
}
@ -121,6 +125,21 @@ class TopSiteItemViewHolder(
this.topSite = topSite
}
@VisibleForTesting
internal fun submitTopSitesImpressionPing(topSite: TopSite.Provided, position: Int) {
itemView.context.components.analytics.metrics.track(
Event.TopSiteContileImpression(
position = position + 1,
source = Event.TopSiteContileImpression.Source.NEWTAB
)
)
topSite.id?.let { TopSites.contileTileId.set(it) }
topSite.title?.let { TopSites.contileAdvertiser.set(it.lowercase()) }
TopSites.contileReportingUrl.set(topSite.impressionUrl)
Pings.topsitesImpression.submit()
}
private fun onTouchEvent(
v: View,
event: MotionEvent,

@ -25,7 +25,7 @@ class TopSitesAdapter(
override fun onBindViewHolder(holder: TopSiteItemViewHolder, position: Int) {
StartupTimeline.onTopSitesItemBound(holder)
holder.bind(getItem(position))
holder.bind(getItem(position), position)
}
override fun onBindViewHolder(
@ -38,7 +38,7 @@ class TopSitesAdapter(
} else {
when (payloads[0]) {
is TopSite -> {
holder.bind((payloads[0] as TopSite))
holder.bind((payloads[0] as TopSite), position)
}
}
}

@ -176,6 +176,11 @@ class Settings(private val appContext: Context) : PreferencesHolder {
default = ""
)
var contileContextId by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_contile_context_id),
default = ""
)
var currentWallpaper by stringPreference(
appContext.getPreferenceKey(R.string.pref_key_current_wallpaper),
default = WallpaperManager.defaultWallpaper.name

@ -188,6 +188,8 @@
<string name="pref_key_adjust_adgroup" translatable="false">pref_key_adjust_adgroup</string>
<string name="pref_key_adjust_creative" translatable="false">pref_key_adjust_creative</string>
<string name="pref_key_contile_context_id" translatable="false">pref_key_contile_context_id</string>
<!-- Wallpaper Settings -->
<string name="pref_key_wallpapers" translatable="false">pref_key_wallpapers</string>
<string name="pref_key_current_wallpaper" translatable="false">pref_key_current_wallpaper</string>

@ -19,8 +19,10 @@ import mozilla.components.concept.engine.webextension.Metadata
import mozilla.components.concept.engine.webextension.WebExtension
import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker
import mozilla.components.service.glean.testing.GleanTestRule
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@ -29,6 +31,7 @@ import org.mozilla.fenix.GleanMetrics.Addons
import org.mozilla.fenix.GleanMetrics.Metrics
import org.mozilla.fenix.GleanMetrics.Preferences
import org.mozilla.fenix.GleanMetrics.SearchDefaultEngine
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.components.metrics.MozillaProductDetector
import org.mozilla.fenix.components.toolbar.ToolbarPosition
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -87,7 +90,7 @@ class FenixApplicationTest {
fun `WHEN setStartupMetrics is called THEN sets some base metrics`() {
val expectedAppName = "org.mozilla.fenix"
val expectedAppInstallSource = "org.mozilla.install.source"
val settings: Settings = mockk()
val settings = spyk(Settings(testContext))
val application = spyk(application)
val packageManager: PackageManager = mockk()
@ -142,6 +145,9 @@ class FenixApplicationTest {
every { application.reportHomeScreenMetrics(settings) } just Runs
every { settings.inactiveTabsAreEnabled } returns true
assertTrue(settings.contileContextId.isEmpty())
assertFalse(TopSites.contextId.testHasValue())
application.setStartupMetrics(browserStore, settings, browsersCache, mozillaProductDetector)
// Verify that browser defaults metrics are set.
@ -181,10 +187,20 @@ class FenixApplicationTest {
assertEquals(true, Preferences.inactiveTabsEnabled.testGetValue())
assertEquals(expectedAppInstallSource, Metrics.installSource.testGetValue())
val contextId = TopSites.contextId.testGetValue().toString()
assertTrue(TopSites.contextId.testHasValue())
assertEquals(contextId, settings.contileContextId)
// Verify that search engine defaults are NOT set. This test does
// not mock most of the objects telemetry is collected from.
assertFalse(SearchDefaultEngine.code.testHasValue())
assertFalse(SearchDefaultEngine.name.testHasValue())
assertFalse(SearchDefaultEngine.searchUrl.testHasValue())
application.setStartupMetrics(browserStore, settings, browsersCache, mozillaProductDetector)
assertEquals(contextId, TopSites.contextId.testGetValue().toString())
assertEquals(contextId, settings.contileContextId)
}
}

@ -23,6 +23,7 @@ import org.mozilla.fenix.GleanMetrics.RecentBookmarks
import org.mozilla.fenix.GleanMetrics.RecentlyVisitedHomepage
import org.mozilla.fenix.GleanMetrics.SyncedTabs
import org.mozilla.fenix.GleanMetrics.TabsTray
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class)
@ -373,4 +374,45 @@ class GleanMetricsServiceTest {
gleanService.track(Event.CreditCardManagementCardTapped)
assertTrue(CreditCards.managementCardTapped.testHasValue())
}
@Test
fun `GIVEN contile top site events WHEN the event is track THEN verify the event is correctly recorded`() {
assertFalse(TopSites.contileImpression.testHasValue())
gleanService.track(
Event.TopSiteContileImpression(
position = 1,
source = Event.TopSiteContileImpression.Source.NEWTAB
)
)
assertTrue(TopSites.contileImpression.testHasValue())
var event = TopSites.contileImpression.testGetValue()
assertEquals(1, event.size)
assertEquals("top_sites", event[0].category)
assertEquals("contile_impression", event[0].name)
assertEquals("1", event[0].extra!!["position"])
assertEquals("newtab", event[0].extra!!["source"])
assertFalse(TopSites.contileClick.testHasValue())
gleanService.track(
Event.TopSiteContileClick(
position = 2,
source = Event.TopSiteContileClick.Source.NEWTAB
)
)
assertTrue(TopSites.contileClick.testHasValue())
event = TopSites.contileClick.testGetValue()
assertEquals(1, event.size)
assertEquals("top_sites", event[0].category)
assertEquals("contile_click", event[0].name)
assertEquals("2", event[0].extra!!["position"])
assertEquals("newtab", event[0].extra!!["source"])
}
}

@ -43,6 +43,8 @@ import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragmentDirections
@ -399,7 +401,7 @@ class DefaultSessionControlControllerTest {
every { controller.getAvailableSearchEngines() } returns listOf(searchEngine)
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenDefault) }
@ -425,7 +427,7 @@ class DefaultSessionControlControllerTest {
every { controller.getAvailableSearchEngines() } returns listOf(searchEngine)
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify {
@ -452,7 +454,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking()
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenDefault) }
@ -481,7 +483,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking()
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenDefault) }
@ -514,7 +516,7 @@ class DefaultSessionControlControllerTest {
every { any<SearchState>().selectedOrDefaultSearchEngine } returns googleSearchEngine
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify {
metrics.track(
@ -550,7 +552,7 @@ class DefaultSessionControlControllerTest {
every { any<SearchState>().selectedOrDefaultSearchEngine } returns googleSearchEngine
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify {
metrics.track(
@ -582,7 +584,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking()
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenPinned) }
@ -611,7 +613,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking()
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenPinned) }
@ -640,7 +642,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("US", "US"))).joinBlocking()
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenFrecent) }
@ -669,7 +671,7 @@ class DefaultSessionControlControllerTest {
store.dispatch(SearchAction.SetRegionAction(RegionState("DE", "FR"))).joinBlocking()
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position = 0)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenFrecent) }
@ -695,11 +697,12 @@ class DefaultSessionControlControllerTest {
impressionUrl = "",
createdAt = 0
)
val position = 0
val controller = spyk(createController())
every { controller.getAvailableSearchEngines() } returns listOf(searchEngine)
controller.handleSelectTopSite(topSite)
controller.handleSelectTopSite(topSite, position)
verify { metrics.track(Event.TopSiteOpenInNewTab) }
verify { metrics.track(Event.TopSiteOpenProvided) }
@ -710,9 +713,41 @@ class DefaultSessionControlControllerTest {
startLoading = true
)
}
verify { controller.submitTopSitesImpressionPing(topSite, position) }
verify { activity.openToBrowser(BrowserDirection.FromHome) }
}
@Test
fun `GIVEN a provided top site WHEN the provided top site is clicked THEN submit a top site impression ping`() {
val controller = spyk(createController())
val topSite = TopSite.Provided(
id = 3,
title = "Mozilla",
url = "https://mozilla.com",
clickUrl = "https://mozilla.com/click",
imageUrl = "https://test.com/image2.jpg",
impressionUrl = "https://example.com",
createdAt = 3
)
val position = 0
controller.submitTopSitesImpressionPing(topSite, position)
verify {
metrics.track(
Event.TopSiteContileClick(
position = position + 1,
source = Event.TopSiteContileClick.Source.NEWTAB
)
)
TopSites.contileTileId.set(3)
TopSites.contileAdvertiser.set("mozilla")
TopSites.contileReportingUrl.set(topSite.clickUrl)
Pings.topsitesImpression.submit()
}
}
@Test
fun handleStartBrowsingClicked() {
var hideOnboardingInvoked = false

@ -17,6 +17,10 @@ import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.GleanMetrics.Pings
import org.mozilla.fenix.GleanMetrics.TopSites
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.databinding.TopSiteItemBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -28,6 +32,7 @@ class TopSiteItemViewHolderTest {
private lateinit var binding: TopSiteItemBinding
private lateinit var interactor: TopSiteInteractor
private lateinit var lifecycleOwner: LifecycleOwner
private lateinit var metrics: MetricController
private val pocket = TopSite.Default(
id = 1L,
@ -41,22 +46,24 @@ class TopSiteItemViewHolderTest {
binding = TopSiteItemBinding.inflate(LayoutInflater.from(testContext))
interactor = mockk(relaxed = true)
lifecycleOwner = mockk(relaxed = true)
metrics = mockk(relaxed = true)
every { testContext.components.core.icons } returns BrowserIcons(testContext, mockk(relaxed = true))
every { testContext.components.analytics.metrics } returns metrics
}
@Test
fun `calls interactor on click`() {
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket, position = 0)
binding.topSiteItem.performClick()
verify { interactor.onSelectTopSite(pocket) }
verify { interactor.onSelectTopSite(pocket, position = 0) }
}
@Test
fun `calls interactor on long click`() {
every { testContext.components.analytics } returns mockk(relaxed = true)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pocket, position = 0)
binding.topSiteItem.performLongClick()
verify { interactor.onTopSiteMenuOpened() }
@ -71,7 +78,7 @@ class TopSiteItemViewHolderTest {
createdAt = 0
)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(defaultTopSite)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(defaultTopSite, position = 0)
val pinIndicator = binding.topSiteTitle.compoundDrawables[0]
assertNotNull(pinIndicator)
@ -86,7 +93,7 @@ class TopSiteItemViewHolderTest {
createdAt = 0
)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pinnedTopSite)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(pinnedTopSite, position = 0)
val pinIndicator = binding.topSiteTitle.compoundDrawables[0]
assertNotNull(pinIndicator)
@ -101,9 +108,39 @@ class TopSiteItemViewHolderTest {
createdAt = 0
)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(frecentTopSite)
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).bind(frecentTopSite, position = 0)
val pinIndicator = binding.topSiteTitle.compoundDrawables[0]
assertNull(pinIndicator)
}
@Test
fun `GIVEN a provided top site and position WHEN the provided top site is shown THEN submit a top site impression ping`() {
val topSite = TopSite.Provided(
id = 3,
title = "Mozilla",
url = "https://mozilla.com",
clickUrl = "https://mozilla.com/click",
imageUrl = "https://test.com/image2.jpg",
impressionUrl = "https://example.com",
createdAt = 3
)
val position = 0
TopSiteItemViewHolder(binding.root, lifecycleOwner, interactor).submitTopSitesImpressionPing(topSite, position)
verify {
metrics.track(
Event.TopSiteContileImpression(
position = position + 1,
source = Event.TopSiteContileImpression.Source.NEWTAB
)
)
TopSites.contileTileId.set(3)
TopSites.contileAdvertiser.set("mozilla")
TopSites.contileReportingUrl.set(topSite.impressionUrl)
Pings.topsitesImpression.submit()
}
}
}

Loading…
Cancel
Save