From 433a69e4544c1daf37bf30a0e186977fa475ab8b Mon Sep 17 00:00:00 2001 From: Wojtek Zieba Date: Tue, 7 Nov 2023 19:30:16 +0100 Subject: [PATCH] tests: add functional test for validating correct behavior on app on stop I had to use UI Automator as I couldn't find any other way to make the test app go to ON_STOP state. --- parsely/build.gradle | 1 + .../parsely/parselyandroid/FunctionalTests.kt | 46 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) 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..41acc036 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,38 @@ class FunctionalTests { } } + /** + * In this scenario, the consumer application goes to the background, re-launches the app, + * and moves to the background again. It asserts, that only one payload has been sent. + */ + @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>>() {} @@ -80,6 +118,7 @@ class FunctionalTests { @JsonIgnoreProperties(ignoreUnknown = true) data class Event( @JsonProperty("idsite") var idsite: String, + @JsonProperty("pvid") var pvid: String, ) private val locallyStoredEvents @@ -90,7 +129,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 +145,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()