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.
826 lines
30 KiB
Kotlin
826 lines
30 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.components.metrics
|
|
|
|
import io.mockk.MockKAnnotations
|
|
import io.mockk.every
|
|
import io.mockk.impl.annotations.MockK
|
|
import io.mockk.mockk
|
|
import io.mockk.verify
|
|
import io.mockk.verifyAll
|
|
import mozilla.components.feature.autofill.facts.AutofillFacts
|
|
import mozilla.components.feature.awesomebar.facts.AwesomeBarFacts
|
|
import mozilla.components.feature.awesomebar.provider.BookmarksStorageSuggestionProvider
|
|
import mozilla.components.feature.awesomebar.provider.ClipboardSuggestionProvider
|
|
import mozilla.components.feature.awesomebar.provider.HistoryStorageSuggestionProvider
|
|
import mozilla.components.feature.awesomebar.provider.SearchSuggestionProvider
|
|
import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider
|
|
import mozilla.components.feature.contextmenu.facts.ContextMenuFacts
|
|
import mozilla.components.feature.media.facts.MediaFacts
|
|
import mozilla.components.feature.prompts.dialog.LoginDialogFacts
|
|
import mozilla.components.feature.prompts.facts.CreditCardAutofillDialogFacts
|
|
import mozilla.components.feature.pwa.ProgressiveWebAppFacts
|
|
import mozilla.components.feature.search.telemetry.ads.AdsTelemetry
|
|
import mozilla.components.feature.search.telemetry.incontent.InContentTelemetry
|
|
import mozilla.components.feature.sitepermissions.SitePermissionsFacts
|
|
import mozilla.components.feature.syncedtabs.facts.SyncedTabsFacts
|
|
import mozilla.components.feature.top.sites.facts.TopSitesFacts
|
|
import mozilla.components.support.base.Component
|
|
import mozilla.components.support.base.facts.Action
|
|
import mozilla.components.support.base.facts.Fact
|
|
import mozilla.components.support.base.log.logger.Logger
|
|
import mozilla.components.support.test.robolectric.testContext
|
|
import mozilla.components.support.webextensions.facts.WebExtensionFacts
|
|
import mozilla.telemetry.glean.testing.GleanTestRule
|
|
import org.junit.Assert.assertEquals
|
|
import org.junit.Assert.assertNotNull
|
|
import org.junit.Assert.assertNull
|
|
import org.junit.Before
|
|
import org.junit.Rule
|
|
import org.junit.Test
|
|
import org.junit.runner.RunWith
|
|
import org.mozilla.fenix.GleanMetrics.AndroidAutofill
|
|
import org.mozilla.fenix.GleanMetrics.Awesomebar
|
|
import org.mozilla.fenix.GleanMetrics.BrowserSearch
|
|
import org.mozilla.fenix.GleanMetrics.ContextualMenu
|
|
import org.mozilla.fenix.GleanMetrics.CreditCards
|
|
import org.mozilla.fenix.GleanMetrics.LoginDialog
|
|
import org.mozilla.fenix.GleanMetrics.MediaNotification
|
|
import org.mozilla.fenix.GleanMetrics.PerfAwesomebar
|
|
import org.mozilla.fenix.GleanMetrics.ProgressiveWebApp
|
|
import org.mozilla.fenix.GleanMetrics.SitePermissions
|
|
import org.mozilla.fenix.GleanMetrics.SyncedTabs
|
|
import org.mozilla.fenix.components.metrics.ReleaseMetricController.Companion
|
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
|
import org.mozilla.fenix.search.awesomebar.ShortcutsSuggestionProvider
|
|
import org.mozilla.fenix.utils.Settings
|
|
import mozilla.components.compose.browser.awesomebar.AwesomeBarFacts as ComposeAwesomeBarFacts
|
|
|
|
@RunWith(FenixRobolectricTestRunner::class)
|
|
class MetricControllerTest {
|
|
|
|
@get:Rule
|
|
val gleanTestRule = GleanTestRule(testContext)
|
|
|
|
@MockK(relaxUnitFun = true)
|
|
private lateinit var dataService1: MetricsService
|
|
|
|
@MockK(relaxUnitFun = true)
|
|
private lateinit var dataService2: MetricsService
|
|
|
|
@MockK(relaxUnitFun = true)
|
|
private lateinit var marketingService1: MetricsService
|
|
|
|
@MockK(relaxUnitFun = true)
|
|
private lateinit var marketingService2: MetricsService
|
|
|
|
@Before
|
|
fun setup() {
|
|
MockKAnnotations.init(this)
|
|
|
|
every { dataService1.type } returns MetricServiceType.Data
|
|
every { dataService2.type } returns MetricServiceType.Data
|
|
every { marketingService1.type } returns MetricServiceType.Marketing
|
|
every { marketingService2.type } returns MetricServiceType.Marketing
|
|
}
|
|
|
|
@Test
|
|
fun `debug metric controller emits logs`() {
|
|
val logger = mockk<Logger>(relaxed = true)
|
|
val controller = DebugMetricController(logger)
|
|
|
|
controller.start(MetricServiceType.Data)
|
|
verify { logger.debug("DebugMetricController: start") }
|
|
|
|
controller.stop(MetricServiceType.Data)
|
|
verify { logger.debug("DebugMetricController: stop") }
|
|
}
|
|
|
|
@Test
|
|
fun `release metric controller starts and stops all data services`() {
|
|
var enabled = true
|
|
val controller = ReleaseMetricController(
|
|
services = listOf(dataService1, marketingService1, dataService2, marketingService2),
|
|
isDataTelemetryEnabled = { enabled },
|
|
isMarketingDataTelemetryEnabled = { enabled },
|
|
mockk(),
|
|
)
|
|
|
|
controller.start(MetricServiceType.Data)
|
|
verify { dataService1.start() }
|
|
verify { dataService2.start() }
|
|
|
|
enabled = false
|
|
|
|
controller.stop(MetricServiceType.Data)
|
|
verify { dataService1.stop() }
|
|
verify { dataService2.stop() }
|
|
|
|
verifyAll(inverse = true) {
|
|
marketingService1.start()
|
|
marketingService1.stop()
|
|
marketingService2.start()
|
|
marketingService2.stop()
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `release metric controller starts data service only if enabled`() {
|
|
val controller = ReleaseMetricController(
|
|
services = listOf(dataService1),
|
|
isDataTelemetryEnabled = { false },
|
|
isMarketingDataTelemetryEnabled = { true },
|
|
mockk(),
|
|
)
|
|
|
|
controller.start(MetricServiceType.Data)
|
|
verify(inverse = true) { dataService1.start() }
|
|
|
|
controller.stop(MetricServiceType.Data)
|
|
verify(inverse = true) { dataService1.stop() }
|
|
}
|
|
|
|
@Test
|
|
fun `release metric controller starts service only once`() {
|
|
var enabled = true
|
|
val controller = ReleaseMetricController(
|
|
services = listOf(dataService1),
|
|
isDataTelemetryEnabled = { enabled },
|
|
isMarketingDataTelemetryEnabled = { true },
|
|
mockk(),
|
|
)
|
|
|
|
controller.start(MetricServiceType.Data)
|
|
controller.start(MetricServiceType.Data)
|
|
verify(exactly = 1) { dataService1.start() }
|
|
|
|
enabled = false
|
|
|
|
controller.stop(MetricServiceType.Data)
|
|
controller.stop(MetricServiceType.Data)
|
|
verify(exactly = 1) { dataService1.stop() }
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN AwesomeBar duration fact is processed THEN the correct metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val action = mockk<Action>()
|
|
val duration = 1000L
|
|
var metadata = mapOf<String, Pair<*, Long>>(
|
|
ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair(
|
|
mockk<HistoryStorageSuggestionProvider>(),
|
|
duration,
|
|
),
|
|
)
|
|
var fact = Fact(
|
|
Component.COMPOSE_AWESOMEBAR,
|
|
action,
|
|
ComposeAwesomeBarFacts.Items.PROVIDER_DURATION,
|
|
metadata = metadata,
|
|
)
|
|
// Verify history based suggestions
|
|
assertNull(PerfAwesomebar.historySuggestions.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(PerfAwesomebar.historySuggestions.testGetValue())
|
|
|
|
// Verify bookmark based suggestions
|
|
metadata = mapOf(
|
|
ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair(
|
|
mockk<BookmarksStorageSuggestionProvider>(),
|
|
duration,
|
|
),
|
|
)
|
|
fact = fact.copy(metadata = metadata)
|
|
assertNull(PerfAwesomebar.bookmarkSuggestions.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(PerfAwesomebar.bookmarkSuggestions.testGetValue())
|
|
|
|
// Verify session based suggestions
|
|
metadata = mapOf(
|
|
ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair(
|
|
mockk<SessionSuggestionProvider>(),
|
|
duration,
|
|
),
|
|
)
|
|
fact = fact.copy(metadata = metadata)
|
|
assertNull(PerfAwesomebar.sessionSuggestions.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(PerfAwesomebar.sessionSuggestions.testGetValue())
|
|
|
|
// Verify search engine suggestions
|
|
metadata = mapOf(
|
|
ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair(
|
|
mockk<SearchSuggestionProvider>(),
|
|
duration,
|
|
),
|
|
)
|
|
fact = fact.copy(metadata = metadata)
|
|
assertNull(PerfAwesomebar.searchEngineSuggestions.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(PerfAwesomebar.searchEngineSuggestions.testGetValue())
|
|
|
|
// Verify clipboard based suggestions
|
|
metadata = mapOf(
|
|
ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair(
|
|
mockk<ClipboardSuggestionProvider>(),
|
|
duration,
|
|
),
|
|
)
|
|
fact = fact.copy(metadata = metadata)
|
|
assertNull(PerfAwesomebar.clipboardSuggestions.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(PerfAwesomebar.clipboardSuggestions.testGetValue())
|
|
|
|
// Verify shortcut based suggestions
|
|
metadata = mapOf(
|
|
ComposeAwesomeBarFacts.MetadataKeys.DURATION_PAIR to Pair(
|
|
mockk<ShortcutsSuggestionProvider>(),
|
|
duration,
|
|
),
|
|
)
|
|
fact = fact.copy(metadata = metadata)
|
|
assertNull(PerfAwesomebar.shortcutsSuggestions.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(PerfAwesomebar.shortcutsSuggestions.testGetValue())
|
|
}
|
|
|
|
@Test
|
|
fun `release metric controller starts and stops all marketing services`() {
|
|
var enabled = true
|
|
val controller = ReleaseMetricController(
|
|
services = listOf(dataService1, marketingService1, dataService2, marketingService2),
|
|
isDataTelemetryEnabled = { enabled },
|
|
isMarketingDataTelemetryEnabled = { enabled },
|
|
mockk(),
|
|
)
|
|
|
|
controller.start(MetricServiceType.Marketing)
|
|
verify { marketingService1.start() }
|
|
verify { marketingService2.start() }
|
|
|
|
enabled = false
|
|
|
|
controller.stop(MetricServiceType.Marketing)
|
|
verify { marketingService1.stop() }
|
|
verify { marketingService2.stop() }
|
|
|
|
verifyAll(inverse = true) {
|
|
dataService1.start()
|
|
dataService1.stop()
|
|
dataService2.start()
|
|
dataService2.stop()
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `topsites fact should set value in SharedPreference`() {
|
|
val enabled = true
|
|
val settings: Settings = mockk(relaxed = true)
|
|
val controller = ReleaseMetricController(
|
|
services = listOf(dataService1),
|
|
isDataTelemetryEnabled = { enabled },
|
|
isMarketingDataTelemetryEnabled = { enabled },
|
|
settings,
|
|
)
|
|
|
|
val fact = Fact(
|
|
Component.FEATURE_TOP_SITES,
|
|
Action.INTERACTION,
|
|
TopSitesFacts.Items.COUNT,
|
|
"1",
|
|
)
|
|
|
|
verify(exactly = 0) { settings.topSitesSize = any() }
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
verify(exactly = 1) { settings.topSitesSize = any() }
|
|
}
|
|
|
|
@Test
|
|
fun `web extension fact should set value in SharedPreference`() {
|
|
val enabled = true
|
|
val settings = Settings(testContext)
|
|
val controller = ReleaseMetricController(
|
|
services = listOf(dataService1),
|
|
isDataTelemetryEnabled = { enabled },
|
|
isMarketingDataTelemetryEnabled = { enabled },
|
|
settings,
|
|
)
|
|
val fact = Fact(
|
|
Component.SUPPORT_WEBEXTENSIONS,
|
|
Action.INTERACTION,
|
|
WebExtensionFacts.Items.WEB_EXTENSIONS_INITIALIZED,
|
|
metadata = mapOf(
|
|
"installed" to listOf("test1", "test2", "test3", "test4"),
|
|
"enabled" to listOf("test2", "test4"),
|
|
),
|
|
)
|
|
|
|
assertEquals(settings.installedAddonsCount, 0)
|
|
assertEquals(settings.installedAddonsList, "")
|
|
assertEquals(settings.enabledAddonsCount, 0)
|
|
assertEquals(settings.enabledAddonsList, "")
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
assertEquals(settings.installedAddonsCount, 4)
|
|
assertEquals(settings.installedAddonsList, "test1,test2,test3,test4")
|
|
assertEquals(settings.enabledAddonsCount, 2)
|
|
assertEquals(settings.enabledAddonsList, "test2,test4")
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN processing a fact with FEATURE_PROMPTS component THEN the right metric is recorded with no extras`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val action = mockk<Action>()
|
|
|
|
// Verify display interaction
|
|
assertNull(LoginDialog.displayed.testGetValue())
|
|
var fact = Fact(Component.FEATURE_PROMPTS, action, LoginDialogFacts.Items.DISPLAY)
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(LoginDialog.displayed.testGetValue())
|
|
assertEquals(1, LoginDialog.displayed.testGetValue()!!.size)
|
|
assertNull(LoginDialog.displayed.testGetValue()!!.single().extra)
|
|
|
|
// Verify cancel interaction
|
|
assertNull(LoginDialog.cancelled.testGetValue())
|
|
fact = Fact(Component.FEATURE_PROMPTS, action, LoginDialogFacts.Items.CANCEL)
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(LoginDialog.cancelled.testGetValue())
|
|
assertEquals(1, LoginDialog.cancelled.testGetValue()!!.size)
|
|
assertNull(LoginDialog.cancelled.testGetValue()!!.single().extra)
|
|
|
|
// Verify never save interaction
|
|
assertNull(LoginDialog.neverSave.testGetValue())
|
|
fact = Fact(Component.FEATURE_PROMPTS, action, LoginDialogFacts.Items.NEVER_SAVE)
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(LoginDialog.neverSave.testGetValue())
|
|
assertEquals(1, LoginDialog.neverSave.testGetValue()!!.size)
|
|
assertNull(LoginDialog.neverSave.testGetValue()!!.single().extra)
|
|
|
|
// Verify save interaction
|
|
assertNull(LoginDialog.saved.testGetValue())
|
|
fact = Fact(Component.FEATURE_PROMPTS, action, LoginDialogFacts.Items.SAVE)
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(LoginDialog.saved.testGetValue())
|
|
assertEquals(1, LoginDialog.saved.testGetValue()!!.size)
|
|
assertNull(LoginDialog.saved.testGetValue()!!.single().extra)
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN processing a FEATURE_MEDIA NOTIFICATION fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
// Verify the play action
|
|
var fact = Fact(Component.FEATURE_MEDIA, Action.PLAY, MediaFacts.Items.NOTIFICATION)
|
|
assertNull(MediaNotification.play.testGetValue())
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(MediaNotification.play.testGetValue())
|
|
assertEquals(1, MediaNotification.play.testGetValue()!!.size)
|
|
assertNull(MediaNotification.play.testGetValue()!!.single().extra)
|
|
|
|
// Verify the pause action
|
|
fact = Fact(Component.FEATURE_MEDIA, Action.PAUSE, MediaFacts.Items.NOTIFICATION)
|
|
assertNull(MediaNotification.pause.testGetValue())
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(MediaNotification.pause.testGetValue())
|
|
assertEquals(1, MediaNotification.pause.testGetValue()!!.size)
|
|
assertNull(MediaNotification.pause.testGetValue()!!.single().extra)
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN processing a FEATURE_AUTOFILL fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
var fact = Fact(
|
|
Component.FEATURE_AUTOFILL,
|
|
mockk(relaxed = true),
|
|
AutofillFacts.Items.AUTOFILL_REQUEST,
|
|
metadata = mapOf(AutofillFacts.Metadata.HAS_MATCHING_LOGINS to true),
|
|
)
|
|
|
|
with(controller) {
|
|
assertNull(AndroidAutofill.requestMatchingLogins.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.requestMatchingLogins.testGetValue())
|
|
|
|
fact = fact.copy(metadata = mapOf(AutofillFacts.Metadata.HAS_MATCHING_LOGINS to false))
|
|
assertNull(AndroidAutofill.requestNoMatchingLogins.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.requestNoMatchingLogins.testGetValue())
|
|
|
|
fact = fact.copy(item = AutofillFacts.Items.AUTOFILL_SEARCH, action = Action.DISPLAY, metadata = null)
|
|
assertNull(AndroidAutofill.searchDisplayed.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.searchDisplayed.testGetValue())
|
|
|
|
fact = fact.copy(action = Action.SELECT)
|
|
assertNull(AndroidAutofill.searchItemSelected.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.searchItemSelected.testGetValue())
|
|
|
|
fact = fact.copy(item = AutofillFacts.Items.AUTOFILL_CONFIRMATION, action = Action.CONFIRM)
|
|
assertNull(AndroidAutofill.confirmSuccessful.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.confirmSuccessful.testGetValue())
|
|
|
|
fact = fact.copy(action = Action.DISPLAY)
|
|
assertNull(AndroidAutofill.confirmCancelled.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.confirmCancelled.testGetValue())
|
|
|
|
fact = fact.copy(item = AutofillFacts.Items.AUTOFILL_LOCK, action = Action.CONFIRM)
|
|
assertNull(AndroidAutofill.unlockSuccessful.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.unlockSuccessful.testGetValue())
|
|
|
|
fact = fact.copy(action = Action.DISPLAY)
|
|
assertNull(AndroidAutofill.unlockCancelled.testGetValue())
|
|
|
|
fact.process()
|
|
|
|
assertNotNull(AndroidAutofill.unlockCancelled.testGetValue())
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN processing a ContextualMenu fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val action = mockk<Action>()
|
|
// Verify copy button interaction
|
|
var fact = Fact(
|
|
Component.FEATURE_CONTEXTMENU,
|
|
action,
|
|
ContextMenuFacts.Items.TEXT_SELECTION_OPTION,
|
|
metadata = mapOf("textSelectionOption" to Companion.CONTEXT_MENU_COPY),
|
|
)
|
|
assertNull(ContextualMenu.copyTapped.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(ContextualMenu.copyTapped.testGetValue())
|
|
assertEquals(1, ContextualMenu.copyTapped.testGetValue()!!.size)
|
|
assertNull(ContextualMenu.copyTapped.testGetValue()!!.single().extra)
|
|
|
|
// Verify search button interaction
|
|
fact = Fact(
|
|
Component.FEATURE_CONTEXTMENU,
|
|
action,
|
|
ContextMenuFacts.Items.TEXT_SELECTION_OPTION,
|
|
metadata = mapOf("textSelectionOption" to Companion.CONTEXT_MENU_SEARCH),
|
|
)
|
|
assertNull(ContextualMenu.searchTapped.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(ContextualMenu.searchTapped.testGetValue())
|
|
assertEquals(1, ContextualMenu.searchTapped.testGetValue()!!.size)
|
|
assertNull(ContextualMenu.searchTapped.testGetValue()!!.single().extra)
|
|
|
|
// Verify select all button interaction
|
|
fact = Fact(
|
|
Component.FEATURE_CONTEXTMENU,
|
|
action,
|
|
ContextMenuFacts.Items.TEXT_SELECTION_OPTION,
|
|
metadata = mapOf("textSelectionOption" to Companion.CONTEXT_MENU_SELECT_ALL),
|
|
)
|
|
assertNull(ContextualMenu.selectAllTapped.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(ContextualMenu.selectAllTapped.testGetValue())
|
|
assertEquals(1, ContextualMenu.selectAllTapped.testGetValue()!!.size)
|
|
assertNull(ContextualMenu.selectAllTapped.testGetValue()!!.single().extra)
|
|
|
|
// Verify share button interaction
|
|
fact = Fact(
|
|
Component.FEATURE_CONTEXTMENU,
|
|
action,
|
|
ContextMenuFacts.Items.TEXT_SELECTION_OPTION,
|
|
metadata = mapOf("textSelectionOption" to Companion.CONTEXT_MENU_SHARE),
|
|
)
|
|
assertNull(ContextualMenu.shareTapped.testGetValue())
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(ContextualMenu.shareTapped.testGetValue())
|
|
assertEquals(1, ContextualMenu.shareTapped.testGetValue()!!.size)
|
|
assertNull(ContextualMenu.shareTapped.testGetValue()!!.single().extra)
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN processing a CreditCardAutofillDialog fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val action = mockk<Action>(relaxed = true)
|
|
val itemsToEvents = listOf(
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_FORM_DETECTED to CreditCards.formDetected,
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_SUCCESS to CreditCards.autofilled,
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_SHOWN to CreditCards.autofillPromptShown,
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_EXPANDED to CreditCards.autofillPromptExpanded,
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_PROMPT_DISMISSED to CreditCards.autofillPromptDismissed,
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_CREATED to CreditCards.savePromptCreate,
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_UPDATED to CreditCards.savePromptUpdate,
|
|
CreditCardAutofillDialogFacts.Items.AUTOFILL_CREDIT_CARD_SAVE_PROMPT_SHOWN to CreditCards.savePromptShown,
|
|
)
|
|
|
|
itemsToEvents.forEach { (item, event) ->
|
|
val fact = Fact(Component.FEATURE_PROMPTS, action, item)
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertEquals(1, event.testGetValue()!!.size)
|
|
assertEquals(null, event.testGetValue()!!.single().extra)
|
|
}
|
|
}
|
|
|
|
@Test
|
|
fun `GIVEN pwa facts WHEN they are processed THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val action = mockk<Action>(relaxed = true)
|
|
|
|
// a PWA shortcut from homescreen was opened
|
|
val openPWA = Fact(
|
|
Component.FEATURE_PWA,
|
|
action,
|
|
ProgressiveWebAppFacts.Items.HOMESCREEN_ICON_TAP,
|
|
)
|
|
|
|
assertNull(ProgressiveWebApp.homescreenTap.testGetValue())
|
|
controller.run {
|
|
openPWA.process()
|
|
}
|
|
assertNotNull(ProgressiveWebApp.homescreenTap.testGetValue())
|
|
|
|
// a PWA shortcut was installed
|
|
val installPWA = Fact(
|
|
Component.FEATURE_PWA,
|
|
action,
|
|
ProgressiveWebAppFacts.Items.INSTALL_SHORTCUT,
|
|
)
|
|
|
|
assertNull(ProgressiveWebApp.installTap.testGetValue())
|
|
|
|
controller.run {
|
|
installPWA.process()
|
|
}
|
|
|
|
assertNotNull(ProgressiveWebApp.installTap.testGetValue())
|
|
}
|
|
|
|
@Test
|
|
fun `WHEN processing a suggestion fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
|
|
// Verify synced tabs suggestion clicked
|
|
assertNull(SyncedTabs.syncedTabsSuggestionClicked.testGetValue())
|
|
var fact = Fact(Component.FEATURE_SYNCEDTABS, Action.CANCEL, SyncedTabsFacts.Items.SYNCED_TABS_SUGGESTION_CLICKED)
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(SyncedTabs.syncedTabsSuggestionClicked.testGetValue())
|
|
|
|
// Verify bookmark suggestion clicked
|
|
assertNull(Awesomebar.bookmarkSuggestionClicked.testGetValue())
|
|
fact = Fact(Component.FEATURE_AWESOMEBAR, Action.CANCEL, AwesomeBarFacts.Items.BOOKMARK_SUGGESTION_CLICKED)
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(Awesomebar.bookmarkSuggestionClicked.testGetValue())
|
|
|
|
// Verify clipboard suggestion clicked
|
|
assertNull(Awesomebar.clipboardSuggestionClicked.testGetValue())
|
|
fact = Fact(Component.FEATURE_AWESOMEBAR, Action.CANCEL, AwesomeBarFacts.Items.CLIPBOARD_SUGGESTION_CLICKED)
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(Awesomebar.clipboardSuggestionClicked.testGetValue())
|
|
|
|
// Verify history suggestion clicked
|
|
assertNull(Awesomebar.historySuggestionClicked.testGetValue())
|
|
fact = Fact(Component.FEATURE_AWESOMEBAR, Action.CANCEL, AwesomeBarFacts.Items.HISTORY_SUGGESTION_CLICKED)
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(Awesomebar.historySuggestionClicked.testGetValue())
|
|
|
|
// Verify search action clicked
|
|
assertNull(Awesomebar.searchActionClicked.testGetValue())
|
|
fact = Fact(Component.FEATURE_AWESOMEBAR, Action.CANCEL, AwesomeBarFacts.Items.SEARCH_ACTION_CLICKED)
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(Awesomebar.searchActionClicked.testGetValue())
|
|
|
|
// Verify bookmark opened tab suggestion clicked
|
|
assertNull(Awesomebar.openedTabSuggestionClicked.testGetValue())
|
|
fact = Fact(Component.FEATURE_AWESOMEBAR, Action.CANCEL, AwesomeBarFacts.Items.OPENED_TAB_SUGGESTION_CLICKED)
|
|
|
|
with(controller) {
|
|
fact.process()
|
|
}
|
|
|
|
assertNotNull(Awesomebar.openedTabSuggestionClicked.testGetValue())
|
|
}
|
|
|
|
@Test
|
|
fun `GIVEN advertising search facts WHEN the list is processed THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { false }, mockk())
|
|
val action = mockk<Action>()
|
|
|
|
// an ad was clicked in a Search Engine Result Page
|
|
val addClickedInSearchFact = Fact(
|
|
Component.FEATURE_SEARCH,
|
|
action,
|
|
AdsTelemetry.SERP_ADD_CLICKED,
|
|
"provider",
|
|
)
|
|
|
|
assertNull(BrowserSearch.adClicks["provider"].testGetValue())
|
|
controller.run {
|
|
addClickedInSearchFact.process()
|
|
}
|
|
assertNotNull(BrowserSearch.adClicks["provider"].testGetValue())
|
|
assertEquals(1, BrowserSearch.adClicks["provider"].testGetValue())
|
|
|
|
// the user opened a Search Engine Result Page of one of our search providers which contains ads
|
|
val searchWithAdsOpenedFact = Fact(
|
|
Component.FEATURE_SEARCH,
|
|
action,
|
|
AdsTelemetry.SERP_SHOWN_WITH_ADDS,
|
|
"provider",
|
|
)
|
|
|
|
assertNull(BrowserSearch.withAds["provider"].testGetValue())
|
|
|
|
controller.run {
|
|
searchWithAdsOpenedFact.process()
|
|
}
|
|
|
|
assertNotNull(BrowserSearch.withAds["provider"].testGetValue())
|
|
assertEquals(1, BrowserSearch.withAds["provider"].testGetValue())
|
|
|
|
// the user performed a search
|
|
val inContentSearchFact = Fact(
|
|
Component.FEATURE_SEARCH,
|
|
action,
|
|
InContentTelemetry.IN_CONTENT_SEARCH,
|
|
"provider",
|
|
)
|
|
|
|
assertNull(BrowserSearch.inContent["provider"].testGetValue())
|
|
|
|
controller.run {
|
|
inContentSearchFact.process()
|
|
}
|
|
|
|
assertNotNull(BrowserSearch.inContent["provider"].testGetValue())
|
|
assertEquals(1, BrowserSearch.inContent["provider"].testGetValue())
|
|
|
|
// the user performed another search
|
|
controller.run {
|
|
inContentSearchFact.process()
|
|
}
|
|
|
|
assertEquals(2, BrowserSearch.inContent["provider"].testGetValue())
|
|
}
|
|
|
|
@Test
|
|
fun `GIVEN a site permissions prompt is shown WHEN processing the fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val fact = Fact(
|
|
component = Component.FEATURE_SITEPERMISSIONS,
|
|
action = Action.DISPLAY,
|
|
item = SitePermissionsFacts.Items.PERMISSIONS,
|
|
value = "test",
|
|
)
|
|
assertNull(SitePermissions.promptShown.testGetValue())
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertEquals(1, SitePermissions.promptShown.testGetValue()!!.size)
|
|
assertEquals("test", SitePermissions.promptShown.testGetValue()!!.single().extra!!["permissions"])
|
|
}
|
|
|
|
@Test
|
|
fun `GIVEN site permissions are allowed WHEN processing the fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val fact = Fact(
|
|
component = Component.FEATURE_SITEPERMISSIONS,
|
|
action = Action.CONFIRM,
|
|
item = SitePermissionsFacts.Items.PERMISSIONS,
|
|
value = "allow",
|
|
)
|
|
assertNull(SitePermissions.promptShown.testGetValue())
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertEquals(1, SitePermissions.permissionsAllowed.testGetValue()!!.size)
|
|
assertEquals("allow", SitePermissions.permissionsAllowed.testGetValue()!!.single().extra!!["permissions"])
|
|
}
|
|
|
|
@Test
|
|
fun `GIVEN site permissions are denied WHEN processing the fact THEN the right metric is recorded`() {
|
|
val controller = ReleaseMetricController(emptyList(), { true }, { true }, mockk())
|
|
val fact = Fact(
|
|
component = Component.FEATURE_SITEPERMISSIONS,
|
|
action = Action.CANCEL,
|
|
item = SitePermissionsFacts.Items.PERMISSIONS,
|
|
value = "deny",
|
|
)
|
|
assertNull(SitePermissions.promptShown.testGetValue())
|
|
|
|
controller.run {
|
|
fact.process()
|
|
}
|
|
|
|
assertEquals(1, SitePermissions.permissionsDenied.testGetValue()!!.size)
|
|
assertEquals("deny", SitePermissions.permissionsDenied.testGetValue()!!.single().extra!!["permissions"])
|
|
}
|
|
}
|