commit a17801329eedb62102818a63454134616798911b
parent b92c6787a9e38ee63f27c2855b8187986df19ec3
Author: Marcin KoziĆski <mkozinski@mozilla.com>
Date: Mon, 13 Oct 2025 11:30:18 +0000
Bug 1989529 - Add missing tests for PlayStoreReviewPromptController r=android-reviewers,gmalekpour
Differential Revision: https://phabricator.services.mozilla.com/D266150
Diffstat:
4 files changed, 111 insertions(+), 3 deletions(-)
diff --git a/mobile/android/android-components/components/support/test/src/main/java/mozilla/components/support/test/Assertions.kt b/mobile/android/android-components/components/support/test/src/main/java/mozilla/components/support/test/Assertions.kt
@@ -0,0 +1,11 @@
+/* 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 mozilla.components.support.test
+
+/**
+ * Fails the test if this function is used.
+ */
+fun assertUnused(): Nothing =
+ throw AssertionError("Expected unused function, but was called")
diff --git a/mobile/android/fenix/app/build.gradle b/mobile/android/fenix/app/build.gradle
@@ -707,6 +707,7 @@ dependencies {
testImplementation testFixtures(project(':components:feature-downloads'))
testImplementation ComponentsDependencies.mozilla_appservices_full_megazord_libsForTests
+ testImplementation libs.androidx.test.core
testImplementation libs.androidx.test.junit
testImplementation libs.androidx.work.testing
testImplementation libs.kotlinx.coroutines.test
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/PlayStoreReviewPromptControllerTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/PlayStoreReviewPromptControllerTest.kt
@@ -4,9 +4,25 @@
package org.mozilla.fenix.components
+import android.app.Activity
+import android.content.Context
+import androidx.activity.ComponentActivity
+import androidx.lifecycle.Lifecycle
+import androidx.test.core.app.launchActivity
+import com.google.android.gms.tasks.OnCompleteListener
+import com.google.android.gms.tasks.OnFailureListener
+import com.google.android.gms.tasks.OnSuccessListener
+import com.google.android.gms.tasks.Task
+import com.google.android.play.core.review.ReviewInfo
+import com.google.android.play.core.review.ReviewManager
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runTest
+import mozilla.components.support.test.assertUnused
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -16,6 +32,7 @@ import org.robolectric.RobolectricTestRunner
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
+import java.util.concurrent.Executor
@RunWith(RobolectricTestRunner::class)
class PlayStoreReviewPromptControllerTest {
@@ -23,6 +40,43 @@ class PlayStoreReviewPromptControllerTest {
@get:Rule
val gleanTestRule = FenixGleanTestRule(testContext)
+ private val reviewManager = FakeReviewManager(testContext)
+ private val controller = PlayStoreReviewPromptController(
+ manager = reviewManager,
+ numberOfAppLaunches = { 5 },
+ )
+
+ @Test
+ fun `GIVEN activity is resumed WHEN tryPromptReview is called THEN launches review flow`() =
+ runTest {
+ val scenario = launchActivity<ComponentActivity>()
+ scenario.moveToState(Lifecycle.State.RESUMED)
+
+ scenario.onActivity { activity ->
+ launch {
+ controller.tryPromptReview(activity)
+
+ assertTrue(reviewManager.promptHasBeenRequested)
+ }
+ }
+ }
+
+ @Test
+ fun `GIVEN activity is stopped WHEN tryPromptReview is called THEN doesn't run the on complete callback`() =
+ runTest {
+ val scenario = launchActivity<ComponentActivity>()
+ scenario.moveToState(Lifecycle.State.RESUMED)
+ scenario.moveToState(Lifecycle.State.CREATED)
+
+ scenario.onActivity { activity ->
+ launch {
+ controller.tryPromptReview(activity)
+
+ assertFalse(reviewManager.promptHasBeenRequested)
+ }
+ }
+ }
+
@Test
fun reviewPromptWasDisplayed() {
testRecordReviewPromptEventRecordsTheExpectedData("isNoOp=false", "true")
@@ -67,3 +121,47 @@ class PlayStoreReviewPromptControllerTest {
}
}
}
+
+private class FakeReviewManager(context: Context) : ReviewManager {
+ var promptHasBeenRequested = false
+
+ private val wrapped = com.google.android.play.core.review.testing.FakeReviewManager(context)
+
+ override fun requestReviewFlow(): FakeGmsTask<ReviewInfo> {
+ val requestReviewFlow = wrapped.requestReviewFlow()
+ val result = requestReviewFlow.result
+ return FakeGmsTask(result)
+ }
+
+ override fun launchReviewFlow(activity: Activity, reviewInfo: ReviewInfo): FakeGmsTask<Void?> {
+ promptHasBeenRequested = true
+ return FakeGmsTask(null)
+ }
+}
+
+private class FakeGmsTask<T>(private val result: T) : Task<T>() {
+ override fun addOnCompleteListener(activity: Activity, listener: OnCompleteListener<T>): Task<T> {
+ val isNotStopped = (activity as ComponentActivity).lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)
+ if (isNotStopped) {
+ listener.onComplete(this)
+ }
+ return this
+ }
+
+ override fun isSuccessful() = true
+
+ override fun getResult() = result
+
+ override fun <X : Throwable?> getResult(exceptionType: Class<X>) = result
+
+ override fun isComplete() = assertUnused()
+ override fun isCanceled() = assertUnused()
+ override fun getException() = assertUnused()
+ override fun addOnSuccessListener(listener: OnSuccessListener<in T>) = assertUnused()
+ override fun addOnSuccessListener(executor: Executor, listener: OnSuccessListener<in T>) = assertUnused()
+ override fun addOnSuccessListener(activity: Activity, listener: OnSuccessListener<in T>) = assertUnused()
+ override fun addOnFailureListener(listener: OnFailureListener) = assertUnused()
+ override fun addOnFailureListener(executor: Executor, listener: OnFailureListener) = assertUnused()
+ override fun addOnFailureListener(activity: Activity, listener: OnFailureListener) = assertUnused()
+ override fun addOnCompleteListener(listener: OnCompleteListener<T>) = assertUnused()
+}
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddlewareTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/reviewprompt/ReviewPromptMiddlewareTest.kt
@@ -4,6 +4,7 @@
package org.mozilla.fenix.reviewprompt
+import mozilla.components.support.test.assertUnused
import mozilla.components.support.test.ext.joinBlocking
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
@@ -290,9 +291,6 @@ class ReviewPromptMiddlewareTest {
)
}
- private fun assertUnused(): Nothing =
- throw AssertionError("Expected unused function, but was called here ")
-
private class FakeNimbusMessagingHelperInterface(val evalJexlValue: Boolean) :
NimbusMessagingHelperInterface {
override fun evalJexl(expression: String): Boolean = evalJexlValue