Bug 1861694 - Use analysis status to restore (re)analysis state

(cherry picked from commit 860162c33c8519b80b65351d040989c88835cf6b)
fenix/121.0
rahulsainani 6 months ago committed by Ryan VanderMeulen
parent ca0b7e38c9
commit 14e7671ae3

@ -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.
*/

@ -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<String> = emptySet(),
val shoppingSheetExpanded: Boolean? = null,
val productCardState: Map<String, CardState> = emptyMap(),
) {

@ -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(

@ -45,9 +45,9 @@ object ReviewQualityCheckMiddlewareProvider {
): List<ReviewQualityCheckMiddleware> =
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()
}

@ -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<ReviewQualityCheckState, ReviewQualityCheckAction>.updateProductReviewState(
productReviewState: ProductReviewState,
restoreAnalysis: Boolean = false,
) {
dispatch(ReviewQualityCheckAction.UpdateProductReview(productReviewState))
}
private fun Store<ReviewQualityCheckState, ReviewQualityCheckAction>.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
}

@ -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 ->

@ -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<ReviewQualityCheckState, ReviewQualityCheckAction>,
@ -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)
}

@ -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].

@ -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()))

@ -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()
}

@ -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,
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,
)
val testedStore = ReviewQualityCheckStore(
val tested = ReviewQualityCheckStore(
initialState = ReviewQualityCheckState.OptedIn(
productReviewState = ProductAnalysisTestData.analysisPresent(
analysisStatus = AnalysisPresent.AnalysisStatus.UP_TO_DATE,
),
productRecommendationsPreference = false,
productRecommendationsPreference = null,
productRecommendationsExposure = true,
productVendor = ReviewQualityCheckState.ProductVendor.AMAZON,
),
middleware = listOf(
ReviewQualityCheckTelemetryMiddleware(BrowserStore(browserState), appStore),
productVendor = ReviewQualityCheckState.ProductVendor.BEST_BUY,
),
)
val productReviewState = ProductAnalysisTestData.analysisPresent(
analysisStatus = AnalysisPresent.AnalysisStatus.NEEDS_ANALYSIS,
middleware = listOf(ReviewQualityCheckTelemetryMiddleware()),
)
testedStore.dispatch(ReviewQualityCheckAction.UpdateProductReview(productReviewState)).joinBlocking()
testedStore.waitUntilIdle()
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,
),
middleware = listOf(
ReviewQualityCheckTelemetryMiddleware(BrowserStore(browserState), appStore),
productVendor = ReviewQualityCheckState.ProductVendor.BEST_BUY,
),
)
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()

@ -717,23 +717,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"))),
),
),
)
@ -764,7 +760,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(
@ -773,18 +769,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"),
),
),
),
),
)
@ -822,34 +810,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<AppState, AppAction>()
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<ReviewQualityCheckState>()
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
@ -1166,7 +1171,6 @@ class ReviewQualityCheckStoreTest {
ReviewQualityCheckNetworkMiddleware(
reviewQualityCheckService = reviewQualityCheckService,
networkChecker = networkChecker,
appStore = appStore,
scope = this.scope,
),
)

Loading…
Cancel
Save