@ -4,10 +4,15 @@
package org.mozilla.fenix.shopping.middleware
import kotlinx.coroutines.test.runTest
import mozilla.components.browser.state.state.BrowserState
import mozilla.components.browser.state.state.createTab
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.service.glean.testing.GleanTestRule
import mozilla.components.support.test.ext.joinBlocking
import mozilla.components.support.test.libstate.ext.waitUntilIdle
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.test.rule.MainCoroutineRule
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
@ -16,8 +21,12 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.GleanMetrics.Shopping
import org.mozilla.fenix.components.AppStore
import org.mozilla.fenix.components.appstate.AppState
import org.mozilla.fenix.components.appstate.shopping.ShoppingState
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.shopping.ProductAnalysisTestData
import org.mozilla.fenix.shopping.fake.FakeReviewQualityCheckTelemetryService
import org.mozilla.fenix.shopping.store.BottomSheetDismissSource
import org.mozilla.fenix.shopping.store.BottomSheetViewState
import org.mozilla.fenix.shopping.store.ReviewQualityCheckAction
@ -31,14 +40,15 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
@get : Rule
val gleanTestRule = GleanTestRule ( testContext )
@get : Rule
val coroutinesTestRule = MainCoroutineRule ( )
private lateinit var store : ReviewQualityCheckStore
@Before
fun setup ( ) {
store = ReviewQualityCheckStore (
middleware = listOf (
ReviewQualityCheckTelemetryMiddleware ( ) ,
) ,
middleware = provideTelemetryMiddleware ( ) ,
)
store . waitUntilIdle ( )
}
@ -53,18 +63,23 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
@Test
fun `WHEN the bottom sheet is closed THEN the bottom sheet closed event is recorded` ( ) {
store . dispatch ( ReviewQualityCheckAction . BottomSheetClosed ( BottomSheetDismissSource . CLICK _OUTSIDE ) ) . joinBlocking ( )
store . dispatch ( ReviewQualityCheckAction . BottomSheetClosed ( BottomSheetDismissSource . CLICK _OUTSIDE ) )
. joinBlocking ( )
store . waitUntilIdle ( )
assertNotNull ( Shopping . surfaceClosed . testGetValue ( ) )
val event = Shopping . surfaceClosed . testGetValue ( ) !!
assertEquals ( 1 , event . size )
assertEquals ( BottomSheetDismissSource . CLICK_OUTSIDE . sourceName , event . single ( ) . extra ?. getValue ( " source " ) )
assertEquals (
BottomSheetDismissSource . CLICK_OUTSIDE . sourceName ,
event . single ( ) . extra ?. getValue ( " source " ) ,
)
}
@Test
fun `WHEN the bottom sheet is displayed THEN the bottom sheet displayed event is recorded` ( ) {
store . dispatch ( ReviewQualityCheckAction . BottomSheetDisplayed ( BottomSheetViewState . HALF _VIEW ) ) . joinBlocking ( )
store . dispatch ( ReviewQualityCheckAction . BottomSheetDisplayed ( BottomSheetViewState . HALF _VIEW ) )
. joinBlocking ( )
store . waitUntilIdle ( )
assertNotNull ( Shopping . surfaceDisplayed . testGetValue ( ) )
@ -122,9 +137,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productVendor = ReviewQualityCheckState . ProductVendor . AMAZON ,
isHighlightsExpanded = false ,
) ,
middleware = listOf (
ReviewQualityCheckTelemetryMiddleware ( ) ,
) ,
middleware = provideTelemetryMiddleware ( ) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . ExpandCollapseHighlights ) . joinBlocking ( )
@ -142,9 +155,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productVendor = ReviewQualityCheckState . ProductVendor . AMAZON ,
isHighlightsExpanded = true ,
) ,
middleware = listOf (
ReviewQualityCheckTelemetryMiddleware ( ) ,
) ,
middleware = provideTelemetryMiddleware ( ) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . ExpandCollapseHighlights ) . joinBlocking ( )
@ -162,9 +173,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productVendor = ReviewQualityCheckState . ProductVendor . AMAZON ,
isSettingsExpanded = false ,
) ,
middleware = listOf (
ReviewQualityCheckTelemetryMiddleware ( ) ,
) ,
middleware = provideTelemetryMiddleware ( ) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . ExpandCollapseSettings ) . joinBlocking ( )
@ -182,9 +191,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productVendor = ReviewQualityCheckState . ProductVendor . AMAZON ,
isSettingsExpanded = true ,
) ,
middleware = listOf (
ReviewQualityCheckTelemetryMiddleware ( ) ,
) ,
middleware = provideTelemetryMiddleware ( ) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . ExpandCollapseSettings ) . joinBlocking ( )
@ -253,7 +260,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productRecommendationsExposure = true ,
productVendor = ReviewQualityCheckState . ProductVendor . BEST _BUY ,
) ,
middleware = listOf( ReviewQualityCheckTelemetryMiddleware ( ) ) ,
middleware = provideTelemetryMiddleware( ) ,
)
tested . dispatch (
@ -278,7 +285,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productRecommendationsExposure = true ,
productVendor = ReviewQualityCheckState . ProductVendor . BEST _BUY ,
) ,
middleware = listOf( ReviewQualityCheckTelemetryMiddleware ( ) ) ,
middleware = provideTelemetryMiddleware( ) ,
)
tested . dispatch (
@ -302,7 +309,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productRecommendationsExposure = true ,
productVendor = ReviewQualityCheckState . ProductVendor . BEST _BUY ,
) ,
middleware = listOf( ReviewQualityCheckTelemetryMiddleware ( ) ) ,
middleware = provideTelemetryMiddleware( ) ,
)
tested . dispatch (
@ -317,20 +324,136 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
}
@Test
fun `WHEN a product recommendation is visible for more than one and a half seconds THEN ad impression telemetry probe is sent` ( ) {
store . dispatch ( ReviewQualityCheckAction . RecommendedProductImpression ( " " ) ) . joinBlocking ( )
store . waitUntilIdle ( )
fun `GIVEN a recommendation impression action is dispatched WHEN app state does not contain key with tab id, product url and aid THEN ad impression telemetry probe is sent` ( ) =
runTest {
var productViewed : String ? = null
val tested = ReviewQualityCheckStore (
middleware = provideTelemetryMiddleware (
reviewQualityCheckTelemetryService = FakeReviewQualityCheckTelemetryService (
recordImpression = {
productViewed = it
} ,
) ,
browserState = BrowserState (
selectedTabId = " tabId " ,
tabs = listOf (
createTab (
id = " tabId " ,
url = " pdp " ,
) ,
) ,
) ,
) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . RecommendedProductImpression ( " productId " ) )
. joinBlocking ( )
tested . waitUntilIdle ( )
assertNotNull ( Shopping . surfaceAdsImpression . testGetValue ( ) )
assertEquals ( " productId " , productViewed )
}
assertNotNull ( Shopping . surfaceAdsImpression . testGetValue ( ) )
}
@Test
fun `WHEN recommendation impression action is dispatched many times and app state does not initially contain key with tab id, product url and aid THEN ad impression telemetry probe is sent only once` ( ) =
runTest {
var productViewed : String ? = null
var impressionCount = 0
val appStore = AppStore ( )
val tested = ReviewQualityCheckStore (
middleware = provideTelemetryMiddleware (
reviewQualityCheckTelemetryService = FakeReviewQualityCheckTelemetryService (
recordImpression = {
productViewed = it
impressionCount ++
} ,
) ,
browserState = BrowserState (
selectedTabId = " tabId " ,
tabs = listOf (
createTab (
id = " tabId " ,
url = " pdp " ,
) ,
) ,
) ,
appStore = appStore ,
) ,
)
tested . waitUntilIdle ( )
for ( i in 1. . 100 ) {
tested . dispatch ( ReviewQualityCheckAction . RecommendedProductImpression ( " productId " ) )
. joinBlocking ( )
tested . waitUntilIdle ( )
appStore . waitUntilIdle ( )
}
assertNotNull ( Shopping . surfaceAdsImpression . testGetValue ( ) )
assertEquals ( " productId " , productViewed )
assertEquals ( 1 , impressionCount )
}
@Test
fun `WHEN a product recommendation is clicked THEN the ad clicked telemetry probe is sent` ( ) {
store . dispatch ( ReviewQualityCheckAction . RecommendedProductClick ( " " , " " ) ) . joinBlocking ( )
store . waitUntilIdle ( )
fun `GIVEN a recommendation impression action is dispatched WHEN app state contains key with tab id, product url and aid THEN ad impression telemetry probe is NOT sent` ( ) =
runTest {
var productViewed : String ? = null
val tested = ReviewQualityCheckStore (
middleware = provideTelemetryMiddleware (
reviewQualityCheckTelemetryService = FakeReviewQualityCheckTelemetryService (
recordImpression = { productViewed = it } ,
) ,
browserState = BrowserState (
selectedTabId = " tabId " ,
tabs = listOf (
createTab (
id = " tabId " ,
url = " pdp " ,
) ,
) ,
) ,
appStore = AppStore (
AppState (
shoppingState = ShoppingState (
recordedProductRecommendationImpressions = setOf (
ShoppingState . ProductRecommendationImpressionKey (
tabId = " tabId " ,
productUrl = " pdp " ,
aid = " productId " ,
) ,
) ,
) ,
) ,
) ,
) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . RecommendedProductImpression ( " productId " ) )
. joinBlocking ( )
tested . waitUntilIdle ( )
assertNull ( Shopping . surfaceAdsImpression . testGetValue ( ) )
assertNull ( productViewed )
}
assertNotNull ( Shopping . surfaceAdsClicked . testGetValue ( ) )
}
@Test
fun `WHEN a product recommendation is clicked THEN the ad clicked telemetry probe is sent` ( ) =
runTest {
var productClicked : String ? = null
val tested = ReviewQualityCheckStore (
middleware = provideTelemetryMiddleware (
reviewQualityCheckTelemetryService = FakeReviewQualityCheckTelemetryService (
recordClick = { productClicked = it } ,
) ,
) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . RecommendedProductClick ( " productId " , " " ) )
. joinBlocking ( )
tested . waitUntilIdle ( )
assertNotNull ( Shopping . surfaceAdsClicked . testGetValue ( ) )
assertEquals ( " productId " , productClicked )
}
@Test
fun `GIVEN the user has opted in WHEN the user switches product recommendations on THEN send enabled product recommendations toggled telemetry probe` ( ) {
@ -341,15 +464,16 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productVendor = ReviewQualityCheckState . ProductVendor . AMAZON ,
isHighlightsExpanded = false ,
) ,
middleware = listOf (
ReviewQualityCheckTelemetryMiddleware ( ) ,
) ,
middleware = provideTelemetryMiddleware ( ) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . ToggleProductRecommendation ) . joinBlocking ( )
tested . waitUntilIdle ( )
assertEquals ( " enabled " , Shopping . surfaceAdsSettingToggled . testGetValue ( ) !! . first ( ) . extra !! [ " action " ] )
assertEquals (
" enabled " ,
Shopping . surfaceAdsSettingToggled . testGetValue ( ) !! . first ( ) . extra !! [ " action " ] ,
)
}
@Test
@ -361,14 +485,28 @@ class ReviewQualityCheckTelemetryMiddlewareTest {
productVendor = ReviewQualityCheckState . ProductVendor . AMAZON ,
isHighlightsExpanded = false ,
) ,
middleware = listOf (
ReviewQualityCheckTelemetryMiddleware ( ) ,
) ,
middleware = provideTelemetryMiddleware ( ) ,
)
tested . waitUntilIdle ( )
tested . dispatch ( ReviewQualityCheckAction . ToggleProductRecommendation ) . joinBlocking ( )
tested . waitUntilIdle ( )
assertEquals ( " disabled " , Shopping . surfaceAdsSettingToggled . testGetValue ( ) !! . first ( ) . extra !! [ " action " ] )
assertEquals (
" disabled " ,
Shopping . surfaceAdsSettingToggled . testGetValue ( ) !! . first ( ) . extra !! [ " action " ] ,
)
}
private fun provideTelemetryMiddleware (
reviewQualityCheckTelemetryService : FakeReviewQualityCheckTelemetryService = FakeReviewQualityCheckTelemetryService ( ) ,
browserState : BrowserState = BrowserState ( ) ,
appStore : AppStore = AppStore ( ) ,
) = listOf (
ReviewQualityCheckTelemetryMiddleware (
reviewQualityCheckTelemetryService ,
BrowserStore ( browserState ) ,
appStore ,
coroutinesTestRule . scope ,
) ,
)
}