From 6af781a5192ebcfcaf58c69cd4b79ca8e8b37035 Mon Sep 17 00:00:00 2001 From: rahulsainani Date: Fri, 24 Nov 2023 11:45:07 +0100 Subject: [PATCH] Bug 1861694 - Use analysis status to restore (re)analysis state --- .../fenix/components/appstate/AppAction.kt | 11 -- .../appstate/shopping/ShoppingState.kt | 3 - .../appstate/shopping/ShoppingStateReducer.kt | 12 -- .../ReviewQualityCheckMiddlewareProvider.kt | 15 +- .../ReviewQualityCheckNetworkMiddleware.kt | 55 +++----- .../middleware/ReviewQualityCheckService.kt | 8 -- .../ReviewQualityCheckTelemetryMiddleware.kt | 16 +-- .../store/ReviewQualityCheckAction.kt | 8 +- .../components/appstate/ShoppingActionTest.kt | 32 ----- .../fake/FakeReviewQualityCheckService.kt | 3 - ...viewQualityCheckTelemetryMiddlewareTest.kt | 130 +++++++----------- .../store/ReviewQualityCheckStoreTest.kt | 64 +++++---- 12 files changed, 116 insertions(+), 241 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt b/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt index e6a67cad65..6a2bb18e0b 100644 --- a/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt +++ b/app/src/main/java/org/mozilla/fenix/components/appstate/AppAction.kt @@ -227,17 +227,6 @@ sealed class AppAction : Action { */ data class ShoppingSheetStateUpdated(val expanded: Boolean) : ShoppingAction() - /** - * [ShoppingAction] used to add a product to a set of products that are being analysed. - */ - data class AddToProductAnalysed(val productPageUrl: String) : ShoppingAction() - - /** - * [ShoppingAction] used to remove a product from the set of products that are being - * analysed. - */ - data class RemoveFromProductAnalysed(val productPageUrl: String) : ShoppingAction() - /** * [ShoppingAction] used to update the expansion state of the highlights card. */ diff --git a/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingState.kt b/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingState.kt index c51b033054..d2287bd55e 100644 --- a/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingState.kt +++ b/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingState.kt @@ -7,14 +7,11 @@ package org.mozilla.fenix.components.appstate.shopping /** * State for shopping feature that's required to live the lifetime of a session. * - * @property productsInAnalysis Set of product urls that are currently being analysed or were being - * analysed when the sheet was closed. * @property shoppingSheetExpanded Boolean indicating if the shopping sheet is expanded and visible. * @property productCardState Map of product url to [CardState] that contains the state of different * cards in the shopping sheet. */ data class ShoppingState( - val productsInAnalysis: Set = emptySet(), val shoppingSheetExpanded: Boolean? = null, val productCardState: Map = emptyMap(), ) { diff --git a/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingStateReducer.kt b/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingStateReducer.kt index 6dbbe3f81d..f8c5b2b59d 100644 --- a/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingStateReducer.kt +++ b/app/src/main/java/org/mozilla/fenix/components/appstate/shopping/ShoppingStateReducer.kt @@ -24,18 +24,6 @@ internal object ShoppingStateReducer { ), ) - is ShoppingAction.AddToProductAnalysed -> state.copy( - shoppingState = state.shoppingState.copy( - productsInAnalysis = state.shoppingState.productsInAnalysis + action.productPageUrl, - ), - ) - - is ShoppingAction.RemoveFromProductAnalysed -> state.copy( - shoppingState = state.shoppingState.copy( - productsInAnalysis = state.shoppingState.productsInAnalysis - action.productPageUrl, - ), - ) - is ShoppingAction.HighlightsCardExpanded -> { val updatedValue = state.shoppingState.productCardState[action.productPageUrl]?.copy( diff --git a/app/src/main/java/org/mozilla/fenix/shopping/di/ReviewQualityCheckMiddlewareProvider.kt b/app/src/main/java/org/mozilla/fenix/shopping/di/ReviewQualityCheckMiddlewareProvider.kt index e4cb6e1f5c..946ff852c1 100644 --- a/app/src/main/java/org/mozilla/fenix/shopping/di/ReviewQualityCheckMiddlewareProvider.kt +++ b/app/src/main/java/org/mozilla/fenix/shopping/di/ReviewQualityCheckMiddlewareProvider.kt @@ -45,9 +45,9 @@ object ReviewQualityCheckMiddlewareProvider { ): List = listOf( providePreferencesMiddleware(settings, browserStore, appStore, scope), - provideNetworkMiddleware(browserStore, appStore, context, scope), + provideNetworkMiddleware(browserStore, context, scope), provideNavigationMiddleware(TabsUseCases.SelectOrAddUseCase(browserStore), context), - provideTelemetryMiddleware(browserStore, appStore), + provideTelemetryMiddleware(), ) private fun providePreferencesMiddleware( @@ -65,13 +65,11 @@ object ReviewQualityCheckMiddlewareProvider { private fun provideNetworkMiddleware( browserStore: BrowserStore, - appStore: AppStore, context: Context, scope: CoroutineScope, ) = ReviewQualityCheckNetworkMiddleware( reviewQualityCheckService = DefaultReviewQualityCheckService(browserStore), networkChecker = DefaultNetworkChecker(context), - appStore = appStore, scope = scope, ) @@ -83,11 +81,6 @@ object ReviewQualityCheckMiddlewareProvider { GetReviewQualityCheckSumoUrl(context), ) - private fun provideTelemetryMiddleware( - browserStore: BrowserStore, - appStore: AppStore, - ) = ReviewQualityCheckTelemetryMiddleware( - browserStore = browserStore, - appStore = appStore, - ) + private fun provideTelemetryMiddleware() = + ReviewQualityCheckTelemetryMiddleware() } diff --git a/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckNetworkMiddleware.kt b/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckNetworkMiddleware.kt index fea0937b9a..a843189367 100644 --- a/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckNetworkMiddleware.kt +++ b/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckNetworkMiddleware.kt @@ -6,11 +6,8 @@ package org.mozilla.fenix.shopping.middleware import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -import mozilla.components.concept.engine.shopping.ProductAnalysis import mozilla.components.lib.state.MiddlewareContext import mozilla.components.lib.state.Store -import org.mozilla.fenix.components.AppStore -import org.mozilla.fenix.components.appstate.AppAction.ShoppingAction import org.mozilla.fenix.shopping.store.ReviewQualityCheckAction import org.mozilla.fenix.shopping.store.ReviewQualityCheckAction.FetchProductAnalysis import org.mozilla.fenix.shopping.store.ReviewQualityCheckAction.RetryProductAnalysis @@ -25,13 +22,11 @@ import org.mozilla.fenix.shopping.store.ReviewQualityCheckState.OptedIn.ProductR * * @param reviewQualityCheckService The service that handles the network requests. * @param networkChecker The [NetworkChecker] instance to check the network status. - * @param appStore The [AppStore] instance to access state and dispatch [ShoppingAction]s. * @param scope The [CoroutineScope] that will be used to launch coroutines. */ class ReviewQualityCheckNetworkMiddleware( private val reviewQualityCheckService: ReviewQualityCheckService, private val networkChecker: NetworkChecker, - private val appStore: AppStore, private val scope: CoroutineScope, ) : ReviewQualityCheckMiddleware { @@ -61,17 +56,19 @@ class ReviewQualityCheckNetworkMiddleware( scope.launch { when (action) { FetchProductAnalysis, RetryProductAnalysis -> { - val productPageUrl = reviewQualityCheckService.selectedTabUrl() val productAnalysis = reviewQualityCheckService.fetchProductReview() val productReviewState = productAnalysis.toProductReviewState() - store.updateProductReviewState(productReviewState) - productPageUrl?.let { - store.restoreAnalysingStateIfRequired( - productPageUrl = productPageUrl, - productReviewState = productReviewState, - productAnalysis = productAnalysis, - ) + // Here the ProductReviewState should only updated after the analysis status API + // returns a result. This makes sure that the UI doesn't show the reanalyse + // button in case the product analysis is already in progress on the backend. + if (productReviewState.isAnalysisPresentOrNoAnalysisPresent() && + reviewQualityCheckService.analysisStatus().isPendingOrInProgress() + ) { + store.updateProductReviewState(productReviewState, true) + store.dispatch(ReviewQualityCheckAction.RestoreReanalysis) + } else { + store.updateProductReviewState(productReviewState) } if (productReviewState is ProductReviewState.AnalysisPresent) { @@ -90,12 +87,6 @@ class ReviewQualityCheckNetworkMiddleware( return@launch } - // add product to the set of products that are being analysed - val productPageUrl = reviewQualityCheckService.selectedTabUrl() - productPageUrl?.let { - appStore.dispatch(ShoppingAction.AddToProductAnalysed(it)) - } - val status = pollForAnalysisStatus() if (status == null || @@ -121,11 +112,6 @@ class ReviewQualityCheckNetworkMiddleware( val productReviewState = productAnalysis.toProductReviewState() store.updateProductReviewState(productReviewState) } - - // remove product from the set of products that are being analysed - productPageUrl?.let { - appStore.dispatch(ShoppingAction.RemoveFromProductAnalysed(it)) - } } is ReviewQualityCheckAction.RecommendedProductClick -> { @@ -141,27 +127,15 @@ class ReviewQualityCheckNetworkMiddleware( private suspend fun pollForAnalysisStatus(): AnalysisStatusDto? = retry( - predicate = { it == AnalysisStatusDto.PENDING || it == AnalysisStatusDto.IN_PROGRESS }, + predicate = { it.isPendingOrInProgress() }, block = { reviewQualityCheckService.analysisStatus() }, ) private fun Store.updateProductReviewState( productReviewState: ProductReviewState, + restoreAnalysis: Boolean = false, ) { - dispatch(ReviewQualityCheckAction.UpdateProductReview(productReviewState)) - } - - private fun Store.restoreAnalysingStateIfRequired( - productPageUrl: String, - productReviewState: ProductReviewState, - productAnalysis: ProductAnalysis?, - ) { - if (productReviewState.isAnalysisPresentOrNoAnalysisPresent() && - productAnalysis?.needsAnalysis == true && - appStore.state.shoppingState.productsInAnalysis.contains(productPageUrl) - ) { - dispatch(ReviewQualityCheckAction.RestoreReanalysis) - } + dispatch(ReviewQualityCheckAction.UpdateProductReview(productReviewState, restoreAnalysis)) } private fun ProductReviewState.isAnalysisPresentOrNoAnalysisPresent() = @@ -182,4 +156,7 @@ class ReviewQualityCheckNetworkMiddleware( } } } + + private fun AnalysisStatusDto?.isPendingOrInProgress(): Boolean = + this == AnalysisStatusDto.PENDING || this == AnalysisStatusDto.IN_PROGRESS } diff --git a/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckService.kt b/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckService.kt index e3af842f1c..27c538d496 100644 --- a/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckService.kt +++ b/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckService.kt @@ -41,11 +41,6 @@ interface ReviewQualityCheckService { */ suspend fun analysisStatus(): AnalysisStatusDto? - /** - * Returns the selected tab url. - */ - fun selectedTabUrl(): String? - /** * Fetches product recommendations related to the product user is browsing in the current tab. * @@ -126,9 +121,6 @@ class DefaultReviewQualityCheckService( } } - override fun selectedTabUrl(): String? = - browserStore.state.selectedTab?.content?.url - override suspend fun productRecommendation(shouldRecordAvailableTelemetry: Boolean): ProductRecommendation? = withContext(Dispatchers.Main) { suspendCoroutine { continuation -> diff --git a/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddleware.kt b/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddleware.kt index 8e0268d248..2c5f9f38cc 100644 --- a/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddleware.kt +++ b/app/src/main/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddleware.kt @@ -4,13 +4,10 @@ package org.mozilla.fenix.shopping.middleware -import mozilla.components.browser.state.selector.selectedTab -import mozilla.components.browser.state.store.BrowserStore import mozilla.components.lib.state.MiddlewareContext import mozilla.components.lib.state.Store import org.mozilla.fenix.GleanMetrics.Shopping import org.mozilla.fenix.GleanMetrics.ShoppingSettings -import org.mozilla.fenix.components.AppStore import org.mozilla.fenix.shopping.store.ReviewQualityCheckAction import org.mozilla.fenix.shopping.store.ReviewQualityCheckMiddleware import org.mozilla.fenix.shopping.store.ReviewQualityCheckState @@ -22,10 +19,7 @@ private const val ACTION_DISABLED = "disabled" /** * Middleware that captures telemetry events for the review quality check feature. */ -class ReviewQualityCheckTelemetryMiddleware( - private val browserStore: BrowserStore, - private val appStore: AppStore, -) : ReviewQualityCheckMiddleware { +class ReviewQualityCheckTelemetryMiddleware : ReviewQualityCheckMiddleware { override fun invoke( context: MiddlewareContext, @@ -108,9 +102,8 @@ class ReviewQualityCheckTelemetryMiddleware( } is ReviewQualityCheckAction.UpdateProductReview -> { - val productPageUrl = browserStore.state.selectedTab?.content?.url val state = store.state - if (state.isStaleAnalysis() && !isProductInAnalysis(productPageUrl)) { + if (state.isStaleAnalysis() && !action.restoreAnalysis) { Shopping.surfaceStaleAnalysisShown.record() } } @@ -167,9 +160,4 @@ class ReviewQualityCheckTelemetryMiddleware( this is ReviewQualityCheckState.OptedIn && this.productReviewState is ReviewQualityCheckState.OptedIn.ProductReviewState.AnalysisPresent && this.productReviewState.analysisStatus == AnalysisStatus.NEEDS_ANALYSIS - - private fun isProductInAnalysis( - productPageUrl: String?, - ): Boolean = - appStore.state.shoppingState.productsInAnalysis.contains(productPageUrl) } diff --git a/app/src/main/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckAction.kt b/app/src/main/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckAction.kt index 67f07ad08f..f40285df3f 100644 --- a/app/src/main/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckAction.kt +++ b/app/src/main/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckAction.kt @@ -89,8 +89,14 @@ sealed interface ReviewQualityCheckAction : Action { /** * Triggered as a result of a [NetworkAction] to update the [ProductReviewState]. + * + * @property productReviewState The product review state to update. + * @property restoreAnalysis Signals whether the analysis will be restored right after the update. */ - data class UpdateProductReview(val productReviewState: ProductReviewState) : UpdateAction, TelemetryAction + data class UpdateProductReview( + val productReviewState: ProductReviewState, + val restoreAnalysis: Boolean, + ) : UpdateAction, TelemetryAction /** * Triggered as a result of a [NetworkAction] to update the [RecommendedProductState]. diff --git a/app/src/test/java/org/mozilla/fenix/components/appstate/ShoppingActionTest.kt b/app/src/test/java/org/mozilla/fenix/components/appstate/ShoppingActionTest.kt index 0aeecd7176..9ea0447969 100644 --- a/app/src/test/java/org/mozilla/fenix/components/appstate/ShoppingActionTest.kt +++ b/app/src/test/java/org/mozilla/fenix/components/appstate/ShoppingActionTest.kt @@ -47,38 +47,6 @@ class ShoppingActionTest { assertEquals(expected, store.state.shoppingState) } - @Test - fun `WHEN product analysed is added THEN state should reflect that`() { - val store = AppStore() - - store.dispatch(AppAction.ShoppingAction.AddToProductAnalysed("pdp")).joinBlocking() - - val expected = ShoppingState( - productsInAnalysis = setOf("pdp"), - ) - - assertEquals(expected, store.state.shoppingState) - } - - @Test - fun `WHEN product analysed is removed THEN state should reflect that`() { - val store = AppStore( - initialState = AppState( - shoppingState = ShoppingState( - productsInAnalysis = setOf("pdp"), - ), - ), - ) - - store.dispatch(AppAction.ShoppingAction.RemoveFromProductAnalysed("pdp")).joinBlocking() - - val expected = ShoppingState( - productsInAnalysis = emptySet(), - ) - - assertEquals(expected, store.state.shoppingState) - } - @Test fun `WHEN product analysis highlights card is expanded THEN state should reflect that`() { val store = AppStore(initialState = AppState(shoppingState = ShoppingState())) diff --git a/app/src/test/java/org/mozilla/fenix/shopping/fake/FakeReviewQualityCheckService.kt b/app/src/test/java/org/mozilla/fenix/shopping/fake/FakeReviewQualityCheckService.kt index a0f365958c..656cef19b8 100644 --- a/app/src/test/java/org/mozilla/fenix/shopping/fake/FakeReviewQualityCheckService.kt +++ b/app/src/test/java/org/mozilla/fenix/shopping/fake/FakeReviewQualityCheckService.kt @@ -13,7 +13,6 @@ class FakeReviewQualityCheckService( private val productAnalysis: (Int) -> ProductAnalysis? = { null }, private val reanalysis: AnalysisStatusDto? = null, private val status: AnalysisStatusDto? = null, - private val selectedTabUrl: String? = null, private val productRecommendation: () -> ProductRecommendation? = { null }, private val recordClick: (String) -> Unit = {}, private val recordImpression: (String) -> Unit = {}, @@ -31,8 +30,6 @@ class FakeReviewQualityCheckService( override suspend fun analysisStatus(): AnalysisStatusDto? = status - override fun selectedTabUrl(): String? = selectedTabUrl - override suspend fun productRecommendation(shouldRecordAvailableTelemetry: Boolean): ProductRecommendation? { return productRecommendation.invoke() } diff --git a/app/src/test/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddlewareTest.kt b/app/src/test/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddlewareTest.kt index e9d81fe0b6..269f8a273c 100644 --- a/app/src/test/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddlewareTest.kt +++ b/app/src/test/java/org/mozilla/fenix/shopping/middleware/ReviewQualityCheckTelemetryMiddlewareTest.kt @@ -4,9 +4,6 @@ package org.mozilla.fenix.shopping.middleware -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 @@ -19,8 +16,6 @@ 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.AppAction import org.mozilla.fenix.helpers.FenixRobolectricTestRunner import org.mozilla.fenix.shopping.ProductAnalysisTestData import org.mozilla.fenix.shopping.store.BottomSheetDismissSource @@ -37,16 +32,12 @@ class ReviewQualityCheckTelemetryMiddlewareTest { val gleanTestRule = GleanTestRule(testContext) private lateinit var store: ReviewQualityCheckStore - private lateinit var browserStore: BrowserStore - private lateinit var appStore: AppStore @Before fun setup() { - browserStore = BrowserStore() - appStore = AppStore() store = ReviewQualityCheckStore( middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(browserStore, appStore), + ReviewQualityCheckTelemetryMiddleware(), ), ) store.waitUntilIdle() @@ -132,7 +123,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest { isHighlightsExpanded = false, ), middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(browserStore, appStore), + ReviewQualityCheckTelemetryMiddleware(), ), ) tested.waitUntilIdle() @@ -152,7 +143,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest { isHighlightsExpanded = true, ), middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(browserStore, appStore), + ReviewQualityCheckTelemetryMiddleware(), ), ) tested.waitUntilIdle() @@ -172,7 +163,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest { isSettingsExpanded = false, ), middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(browserStore, appStore), + ReviewQualityCheckTelemetryMiddleware(), ), ) tested.waitUntilIdle() @@ -192,7 +183,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest { isSettingsExpanded = true, ), middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(browserStore, appStore), + ReviewQualityCheckTelemetryMiddleware(), ), ) tested.waitUntilIdle() @@ -251,91 +242,76 @@ class ReviewQualityCheckTelemetryMiddlewareTest { } @Test - fun `GIVEN a product review has been updated WHEN stale analysis is present and product is not in analysis THEN the stale analysis event is recorded`() { - val productTab = createTab( - url = "pdp", - ) - val browserState = BrowserState( - tabs = listOf(productTab), - selectedTabId = productTab.id, - ) - val testedStore = ReviewQualityCheckStore( - initialState = ReviewQualityCheckState.OptedIn( - productReviewState = ProductAnalysisTestData.analysisPresent( - analysisStatus = AnalysisPresent.AnalysisStatus.UP_TO_DATE, - ), - productRecommendationsPreference = false, - productRecommendationsExposure = true, - productVendor = ReviewQualityCheckState.ProductVendor.AMAZON, - ), - middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(BrowserStore(browserState), appStore), - ), - ) + fun `GIVEN a product review has been updated WHEN restore analysis is false THEN the stale analysis event is recorded`() { val productReviewState = ProductAnalysisTestData.analysisPresent( analysisStatus = AnalysisPresent.AnalysisStatus.NEEDS_ANALYSIS, ) - testedStore.dispatch(ReviewQualityCheckAction.UpdateProductReview(productReviewState)).joinBlocking() - testedStore.waitUntilIdle() + val tested = ReviewQualityCheckStore( + initialState = ReviewQualityCheckState.OptedIn( + productRecommendationsPreference = null, + productRecommendationsExposure = true, + productVendor = ReviewQualityCheckState.ProductVendor.BEST_BUY, + ), + middleware = listOf(ReviewQualityCheckTelemetryMiddleware()), + ) + + tested.dispatch( + ReviewQualityCheckAction.UpdateProductReview( + productReviewState = productReviewState, + restoreAnalysis = false, + ), + ).joinBlocking() + tested.waitUntilIdle() assertNotNull(Shopping.surfaceStaleAnalysisShown.testGetValue()) } @Test - fun `GIVEN a product review has been updated WHEN stale analysis is present and product is being analyzed THEN the stale analysis event is not recorded`() { - val productTab = createTab( - url = "pdp", - ) - appStore.dispatch(AppAction.ShoppingAction.AddToProductAnalysed("pdp")).joinBlocking() - appStore.waitUntilIdle() - val browserState = BrowserState( - tabs = listOf(productTab), - selectedTabId = productTab.id, - ) - val testedStore = ReviewQualityCheckStore( - middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(BrowserStore(browserState), appStore), - ), - ) + fun `GIVEN a product review has been updated WHEN restore analysis is true THEN the stale analysis event is not recorded`() { val productReviewState = ProductAnalysisTestData.analysisPresent( analysisStatus = AnalysisPresent.AnalysisStatus.NEEDS_ANALYSIS, ) + val tested = ReviewQualityCheckStore( + initialState = ReviewQualityCheckState.OptedIn( + productRecommendationsPreference = null, + productRecommendationsExposure = true, + productVendor = ReviewQualityCheckState.ProductVendor.BEST_BUY, + ), + middleware = listOf(ReviewQualityCheckTelemetryMiddleware()), + ) - testedStore.dispatch(ReviewQualityCheckAction.UpdateProductReview(productReviewState)).joinBlocking() - testedStore.waitUntilIdle() + tested.dispatch( + ReviewQualityCheckAction.UpdateProductReview( + productReviewState = productReviewState, + restoreAnalysis = true, + ), + ).joinBlocking() + tested.waitUntilIdle() assertNull(Shopping.surfaceStaleAnalysisShown.testGetValue()) } @Test fun `GIVEN a product review has been updated WHEN it is not a stale analysis THEN the stale analysis event is not recorded`() { - val productTab = createTab( - url = "pdp", - ) - val browserState = BrowserState( - tabs = listOf(productTab), - selectedTabId = productTab.id, - ) - val testedStore = ReviewQualityCheckStore( + val productReviewState = ProductAnalysisTestData.analysisPresent() + + val tested = ReviewQualityCheckStore( initialState = ReviewQualityCheckState.OptedIn( - productReviewState = ProductAnalysisTestData.analysisPresent( - analysisStatus = AnalysisPresent.AnalysisStatus.NEEDS_ANALYSIS, - ), - productRecommendationsPreference = false, + productRecommendationsPreference = null, productRecommendationsExposure = true, - productVendor = ReviewQualityCheckState.ProductVendor.AMAZON, + productVendor = ReviewQualityCheckState.ProductVendor.BEST_BUY, ), - middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(BrowserStore(browserState), appStore), - ), - ) - val productReviewState = ProductAnalysisTestData.analysisPresent( - analysisStatus = AnalysisPresent.AnalysisStatus.REANALYZING, + middleware = listOf(ReviewQualityCheckTelemetryMiddleware()), ) - testedStore.dispatch(ReviewQualityCheckAction.UpdateProductReview(productReviewState)).joinBlocking() - testedStore.waitUntilIdle() + tested.dispatch( + ReviewQualityCheckAction.UpdateProductReview( + productReviewState = productReviewState, + restoreAnalysis = true, + ), + ).joinBlocking() + tested.waitUntilIdle() assertNull(Shopping.surfaceStaleAnalysisShown.testGetValue()) } @@ -366,7 +342,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest { isHighlightsExpanded = false, ), middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(browserStore, appStore), + ReviewQualityCheckTelemetryMiddleware(), ), ) tested.waitUntilIdle() @@ -386,7 +362,7 @@ class ReviewQualityCheckTelemetryMiddlewareTest { isHighlightsExpanded = false, ), middleware = listOf( - ReviewQualityCheckTelemetryMiddleware(browserStore, appStore), + ReviewQualityCheckTelemetryMiddleware(), ), ) tested.waitUntilIdle() diff --git a/app/src/test/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckStoreTest.kt b/app/src/test/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckStoreTest.kt index 15c5948757..e4d5fcd7c2 100644 --- a/app/src/test/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckStoreTest.kt +++ b/app/src/test/java/org/mozilla/fenix/shopping/store/ReviewQualityCheckStoreTest.kt @@ -716,23 +716,19 @@ class ReviewQualityCheckStoreTest { } @Test - fun `GIVEN that the product was being analysed earlier WHEN needsAnalysis is true THEN state should be restored to reanalysing`() = + fun `GIVEN a product analysis WHEN analysis status is in progress or pending THEN state should be updated to reanalysing`() = runTest { val tested = ReviewQualityCheckStore( middleware = provideReviewQualityCheckMiddleware( reviewQualityCheckPreferences = FakeReviewQualityCheckPreferences(isEnabled = true), reviewQualityCheckService = FakeReviewQualityCheckService( productAnalysis = { - ProductAnalysisTestData.productAnalysis(needsAnalysis = true) + ProductAnalysisTestData.productAnalysis() }, reanalysis = AnalysisStatusDto.PENDING, - status = AnalysisStatusDto.COMPLETED, - selectedTabUrl = "pdp", + status = AnalysisStatusDto.IN_PROGRESS, ), networkChecker = FakeNetworkChecker(isConnected = true), - appStore = AppStore( - AppState(shoppingState = ShoppingState(productsInAnalysis = setOf("pdp"))), - ), ), ) @@ -763,7 +759,7 @@ class ReviewQualityCheckStoreTest { } @Test - fun `GIVEN that the product was not being analysed earlier WHEN needsAnalysis is true THEN state should display needs analysis as usual`() = + fun `GIVEN a product analysis WHEN analysis status is completed THEN state should display analysis as usual`() = runTest { val tested = ReviewQualityCheckStore( middleware = provideReviewQualityCheckMiddleware( @@ -772,18 +768,10 @@ class ReviewQualityCheckStoreTest { productAnalysis = { ProductAnalysisTestData.productAnalysis(needsAnalysis = true) }, - reanalysis = AnalysisStatusDto.PENDING, + reanalysis = AnalysisStatusDto.COMPLETED, status = AnalysisStatusDto.COMPLETED, - selectedTabUrl = "pdp", ), networkChecker = FakeNetworkChecker(isConnected = true), - appStore = AppStore( - AppState( - shoppingState = ShoppingState( - productsInAnalysis = setOf("test", "another", "product"), - ), - ), - ), ), ) @@ -821,34 +809,51 @@ class ReviewQualityCheckStoreTest { } @Test - fun `WHEN reanalysis is triggered THEN shopping state should contain the url of the product being analyzed`() = + fun `GIVEN a product analysis WHEN analysis status fails THEN state should display analysis as usual`() = runTest { - val captureActionsMiddleware = CaptureActionsMiddleware() - val appStore = AppStore(middlewares = listOf(captureActionsMiddleware)) val tested = ReviewQualityCheckStore( middleware = provideReviewQualityCheckMiddleware( reviewQualityCheckPreferences = FakeReviewQualityCheckPreferences(isEnabled = true), reviewQualityCheckService = FakeReviewQualityCheckService( - productAnalysis = { ProductAnalysisTestData.productAnalysis() }, - reanalysis = AnalysisStatusDto.PENDING, - status = AnalysisStatusDto.COMPLETED, - selectedTabUrl = "pdp", + productAnalysis = { + ProductAnalysisTestData.productAnalysis() + }, + reanalysis = null, + status = null, ), networkChecker = FakeNetworkChecker(isConnected = true), - appStore = appStore, ), ) + val observedState = mutableListOf() + tested.observeForever { + observedState.add(it) + } + tested.waitUntilIdle() dispatcher.scheduler.advanceUntilIdle() tested.waitUntilIdle() - tested.dispatch(ReviewQualityCheckAction.ReanalyzeProduct).joinBlocking() + tested.dispatch(ReviewQualityCheckAction.FetchProductAnalysis).joinBlocking() tested.waitUntilIdle() dispatcher.scheduler.advanceUntilIdle() - captureActionsMiddleware.assertFirstAction(AppAction.ShoppingAction.AddToProductAnalysed::class) { - assertEquals("pdp", it.productPageUrl) - } + val expected = ReviewQualityCheckState.OptedIn( + productReviewState = ProductAnalysisTestData.analysisPresent(), + productRecommendationsPreference = false, + productRecommendationsExposure = true, + productVendor = ProductVendor.BEST_BUY, + ) + assertEquals(expected, tested.state) + + val notExpected = ReviewQualityCheckState.OptedIn( + productReviewState = ProductAnalysisTestData.analysisPresent( + analysisStatus = AnalysisStatus.REANALYZING, + ), + productRecommendationsPreference = false, + productRecommendationsExposure = true, + productVendor = ProductVendor.BEST_BUY, + ) + assertFalse(observedState.contains(notExpected)) } @Test @@ -1165,7 +1170,6 @@ class ReviewQualityCheckStoreTest { ReviewQualityCheckNetworkMiddleware( reviewQualityCheckService = reviewQualityCheckService, networkChecker = networkChecker, - appStore = appStore, scope = this.scope, ), )