diff --git a/parsely/build.gradle b/parsely/build.gradle index c1206c88..0d1dc896 100644 --- a/parsely/build.gradle +++ b/parsely/build.gradle @@ -75,6 +75,7 @@ dependencies { androidTestImplementation "org.assertj:assertj-core:$assertJVersion" androidTestImplementation "com.squareup.okhttp3:mockwebserver:$mockWebServerVersion" androidTestImplementation 'androidx.test:runner:1.5.2' + androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' androidTestUtil 'androidx.test:orchestrator:1.4.2' } diff --git a/parsely/src/androidTest/java/com/parsely/parselyandroid/FunctionalTests.kt b/parsely/src/androidTest/java/com/parsely/parselyandroid/FunctionalTests.kt index e82fd24e..e2248069 100644 --- a/parsely/src/androidTest/java/com/parsely/parselyandroid/FunctionalTests.kt +++ b/parsely/src/androidTest/java/com/parsely/parselyandroid/FunctionalTests.kt @@ -3,6 +3,9 @@ package com.parsely.parselyandroid import android.app.Activity import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.UiSelector import com.fasterxml.jackson.annotation.JsonIgnoreProperties import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.core.type.TypeReference @@ -12,7 +15,10 @@ import java.io.FileInputStream import java.io.ObjectInputStream import java.lang.reflect.Field import java.nio.file.Path +import java.util.concurrent.TimeUnit import kotlin.io.path.Path +import kotlin.time.Duration +import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.runBlocking @@ -70,6 +76,43 @@ class FunctionalTests { } } + /** + * In this scenario, the consumer application: + * 1. Goes to the background + * 2. Is re-launched + * This pattern occurs twice, which allows us to confirm the following assertions: + * 1. The event request is triggered when the consumer application is moved to the background + * 2. If the consumer application is sent to the background again within a short interval, + * the request is not duplicated. + */ + @Test + fun appSendsEventsWhenMovedToBackgroundAndDoesntSendDuplicatedRequestWhenItsMovedToBackgroundAgainQuickly() { + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + ActivityScenario.launch(SampleActivity::class.java).use { scenario -> + scenario.onActivity { activity: Activity -> + beforeEach(activity) + server.enqueue(MockResponse().setResponseCode(200)) + server.enqueue(MockResponse().setResponseCode(200)) + parselyTracker = initializeTracker(activity, flushInterval = 1.hours) + + repeat(20) { + parselyTracker.trackPageview("url", null, null, null) + } + } + + device.pressHome() + device.pressRecentApps() + device.findObject(UiSelector().descriptionContains("com.parsely")).click() + device.pressHome() + + val firstRequest = server.takeRequest(10000, TimeUnit.MILLISECONDS)?.toMap() + val secondRequest = server.takeRequest(10000, TimeUnit.MILLISECONDS)?.toMap() + + assertThat(firstRequest!!["events"]).hasSize(20) + assertThat(secondRequest).isNull() + } + } + private fun RecordedRequest.toMap(): Map> { val listType: TypeReference>> = object : TypeReference>>() {} @@ -90,7 +133,10 @@ class FunctionalTests { } } - private fun initializeTracker(activity: Activity): ParselyTracker { + private fun initializeTracker( + activity: Activity, + flushInterval: Duration = defaultFlushInterval + ): ParselyTracker { return ParselyTracker.sharedInstance( siteId, flushInterval.inWholeSeconds.toInt(), activity.application ).apply { @@ -103,7 +149,7 @@ class FunctionalTests { private companion object { const val siteId = "123" const val localStorageFileName = "parsely-events.ser" - val flushInterval = 10.seconds + val defaultFlushInterval = 10.seconds } class SampleActivity : Activity()