From c6687d976ee18501790ad8bf1abfc6d484216a4c Mon Sep 17 00:00:00 2001 From: Jeff Boek Date: Tue, 25 Aug 2020 21:46:25 -0700 Subject: [PATCH] For #13507 - Adds tests for ReviewPromptController --- app/lint.xml | 2 + .../components/ReviewPromptController.kt | 26 ++-- .../org/mozilla/fenix/home/HomeFragment.kt | 3 - .../java/org/mozilla/fenix/utils/Settings.kt | 2 - .../components/ReviewPromptControllerTest.kt | 144 ++++++++++++++++++ 5 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 app/src/test/java/org/mozilla/fenix/components/ReviewPromptControllerTest.kt diff --git a/app/lint.xml b/app/lint.xml index cf2226aea..aa99dd31f 100644 --- a/app/lint.xml +++ b/app/lint.xml @@ -7,6 +7,8 @@ + + diff --git a/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt b/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt index 36109b893..a3cbb91ce 100644 --- a/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt +++ b/app/src/main/java/org/mozilla/fenix/components/ReviewPromptController.kt @@ -26,7 +26,7 @@ interface ReviewSettings { */ class FenixReviewSettings( val settings: Settings -): ReviewSettings { +) : ReviewSettings { override var numberOfAppLaunches: Int get() = settings.numberOfAppLaunches set(value) { settings.numberOfAppLaunches = value } @@ -43,14 +43,16 @@ class FenixReviewSettings( class ReviewPromptController( private val context: Context, private val reviewSettings: ReviewSettings, - private val timeNowInMillis: () -> Long = { System.currentTimeMillis() } + private val timeNowInMillis: () -> Long = { System.currentTimeMillis() }, + private val tryPromptReview: suspend (Activity) -> Unit = { + val manager = ReviewManagerFactory.create(context) + val reviewInfo = manager.requestReview() + manager.launchReview(it, reviewInfo) + } ) { suspend fun promptReview(activity: Activity) { if (shouldShowPrompt()) { - val manager = ReviewManagerFactory.create(context) - val reviewInfo = manager.requestReview() - manager.launchReview(activity, reviewInfo) - + tryPromptReview(activity) reviewSettings.lastReviewPromptTimeInMillis = timeNowInMillis() } } @@ -63,14 +65,18 @@ class ReviewPromptController( fun shouldShowPrompt(): Boolean { if (!reviewSettings.isDefaultBrowser) { return false } - val hasOpenedFiveTimes = reviewSettings.numberOfAppLaunches >= 5 - val apprxFourMonthsAgo = timeNowInMillis() - (APPRX_MONTH_IN_MILLIS * 4) - val hasNotBeenPromptedLastFourMonths = reviewSettings.lastReviewPromptTimeInMillis <= apprxFourMonthsAgo + val hasOpenedFiveTimes = reviewSettings.numberOfAppLaunches >= NUMBER_OF_LAUNCHES_REQUIRED + val now = timeNowInMillis() + val apprxFourMonthsAgo = now - (APPRX_MONTH_IN_MILLIS * NUMBER_OF_MONTHS_TO_PASS) + val lastPrompt = reviewSettings.lastReviewPromptTimeInMillis + val hasNotBeenPromptedLastFourMonths = lastPrompt == 0L || lastPrompt <= apprxFourMonthsAgo return hasOpenedFiveTimes && hasNotBeenPromptedLastFourMonths } companion object { private const val APPRX_MONTH_IN_MILLIS: Long = 1000L * 60L * 60L * 24L * 30L + private const val NUMBER_OF_LAUNCHES_REQUIRED = 5 + private const val NUMBER_OF_MONTHS_TO_PASS = 4 } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index cac266fe2..98e16c9c2 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -42,9 +42,6 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE import com.google.android.material.snackbar.Snackbar -import com.google.android.play.core.ktx.launchReview -import com.google.android.play.core.ktx.requestReview -import com.google.android.play.core.review.ReviewManagerFactory import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.view.* import kotlinx.android.synthetic.main.no_collections_message.view.* diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index c953fdd50..b4f096fdc 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -12,7 +12,6 @@ import android.content.SharedPreferences import android.content.pm.ShortcutManager import android.os.Build import android.view.accessibility.AccessibilityManager -import androidx.annotation.RequiresApi import androidx.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting.PRIVATE import androidx.lifecycle.LifecycleOwner @@ -40,7 +39,6 @@ import org.mozilla.fenix.settings.logins.SavedLoginsSortingStrategyMenu import org.mozilla.fenix.settings.logins.SortingStrategy import org.mozilla.fenix.settings.registerOnSharedPreferenceChangeListener import java.security.InvalidParameterException -import java.time.LocalDate private const val AUTOPLAY_USER_SETTING = "AUTOPLAY_USER_SETTING" diff --git a/app/src/test/java/org/mozilla/fenix/components/ReviewPromptControllerTest.kt b/app/src/test/java/org/mozilla/fenix/components/ReviewPromptControllerTest.kt new file mode 100644 index 000000000..0a9fdbbfc --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/components/ReviewPromptControllerTest.kt @@ -0,0 +1,144 @@ +/* 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 + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runBlockingTest +import mozilla.components.support.test.robolectric.testContext +import org.junit.Test +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.assertFalse +import org.junit.runner.RunWith +import org.mozilla.fenix.HomeActivity +import org.mozilla.fenix.helpers.FenixRobolectricTestRunner + +class TestReviewSettings( + override var numberOfAppLaunches: Int = 0, + var isDefault: Boolean = false, + override var lastReviewPromptTimeInMillis: Long = 0 +) : ReviewSettings { + override val isDefaultBrowser: Boolean + get() = isDefault +} + +@ExperimentalCoroutinesApi +@RunWith(FenixRobolectricTestRunner::class) +class ReviewPromptControllerTest { + @Test + fun promptReviewDoesNotSetMillis() = runBlockingTest { + var promptWasCalled = false + val settings = TestReviewSettings( + numberOfAppLaunches = 5, + isDefault = false, + lastReviewPromptTimeInMillis = 0L + ) + + val controller = ReviewPromptController( + testContext, + settings, + { 100L }, + { promptWasCalled = true } + ) + + controller.promptReview(HomeActivity()) + assertEquals(settings.lastReviewPromptTimeInMillis, 0L) + assertFalse(promptWasCalled) + } + + @Test + fun promptReviewSetsMillisIfSuccessful() = runBlockingTest { + var promptWasCalled = false + val settings = TestReviewSettings( + numberOfAppLaunches = 5, + isDefault = true, + lastReviewPromptTimeInMillis = 0L + ) + + val controller = ReviewPromptController( + testContext, + settings, + { 100L }, + { promptWasCalled = true } + ) + + controller.promptReview(HomeActivity()) + assertEquals(100L, settings.lastReviewPromptTimeInMillis) + assertTrue(promptWasCalled) + } + + @Test + fun trackApplicationLaunch() { + val settings = TestReviewSettings( + numberOfAppLaunches = 4, + isDefault = true, + lastReviewPromptTimeInMillis = 0L + ) + + val controller = ReviewPromptController( + testContext, + settings, + { 100L } + ) + + assertEquals(4, settings.numberOfAppLaunches) + controller.trackApplicationLaunch() + assertEquals(5, settings.numberOfAppLaunches) + } + + @Test + fun shouldShowPrompt() { + val settings = TestReviewSettings( + numberOfAppLaunches = 5, + isDefault = true, + lastReviewPromptTimeInMillis = 0L + ) + + val controller = ReviewPromptController( + testContext, + settings, + { 1598416882805L } + ) + + // Test first success criteria + assertTrue(controller.shouldShowPrompt()) + + // Test with last prompt approx 4 months earlier + settings.apply { + numberOfAppLaunches = 5 + isDefault = true + lastReviewPromptTimeInMillis = 1588048882804L + } + + assertTrue(controller.shouldShowPrompt()) + + // Test without being the default browser + settings.apply { + numberOfAppLaunches = 5 + isDefault = false + lastReviewPromptTimeInMillis = 1595824882805L + } + + assertFalse(controller.shouldShowPrompt()) + + // Test with number of app launches < 5 + settings.apply { + numberOfAppLaunches = 4 + isDefault = true + lastReviewPromptTimeInMillis = 0L + } + + assertFalse(controller.shouldShowPrompt()) + + // Test with last prompt less than 4 months ago + settings.apply { + numberOfAppLaunches = 5 + isDefault = true + lastReviewPromptTimeInMillis = 1595824882905L + } + + assertFalse(controller.shouldShowPrompt()) + } +}