diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 192827c5..86c56f9b 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -100,6 +100,12 @@ emerge { publishableApiKey.set(System.getenv("REAPER_API_KEY")) } + performance { + projectPath.set(":performance") + tag.set("oneoff") + enabled.set(true) + } + vcs { gitHub { repoName.set("hackernews") diff --git a/android/performance/.gitignore b/android/performance/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/android/performance/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/android/performance/build.gradle.kts b/android/performance/build.gradle.kts new file mode 100644 index 00000000..49390343 --- /dev/null +++ b/android/performance/build.gradle.kts @@ -0,0 +1,21 @@ +// This is a com.android.test project which is automatically configured by the Emerge Tools Gradle plugin: +// +// - The SDK version targets are automatically set to be identical to the app project. +// - The same build types as your app project are automatically created. +// - Test libraries including UI Automator and Junit and are automatically added as dependencies. +// +// The configuration can be modified in this file as needed. + +plugins { + id("org.jetbrains.kotlin.android") +} + +dependencies { + // Emerge's Performance Testing SDK (Required): + implementation("com.emergetools.test:performance:2.1.1") + // Emerge's UIAutomator helper library (Optional): https://github.com/EmergeTools/relax + implementation("com.emergetools.test:relax:0.1.0") + + // Add additional dependencies here as needed. + // Note Espresso is not supported as it degrades performance. +} diff --git a/android/performance/src/main/AndroidManifest.xml b/android/performance/src/main/AndroidManifest.xml new file mode 100644 index 00000000..76073216 --- /dev/null +++ b/android/performance/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest> +</manifest> diff --git a/android/performance/src/main/java/com/emergetools/hackernews/ExamplePerformanceTest.kt b/android/performance/src/main/java/com/emergetools/hackernews/ExamplePerformanceTest.kt new file mode 100644 index 00000000..b714e35b --- /dev/null +++ b/android/performance/src/main/java/com/emergetools/hackernews/ExamplePerformanceTest.kt @@ -0,0 +1,70 @@ +package com.emergetools.hackernews + +import android.content.Context +import android.content.Intent +import androidx.test.core.app.ApplicationProvider +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.uiautomator.By +import androidx.test.uiautomator.UiDevice +import androidx.test.uiautomator.Until +import com.emergetools.test.annotations.EmergeInit +import com.emergetools.test.annotations.EmergeSetup +import com.emergetools.test.annotations.EmergeTest + +private const val LAUNCH_TIMEOUT = 5000L +private const val APP_PACKAGE_NAME = "com.emergetools.hackernews" + +/** + * An example performance test class. + * + * Performance test classes can have multiple tests, but tests in a given class share @EmergeInit and @EmergeSetup + * methods. For tests that require a different init or setup multiple test classes are supported. + * + * Note that each test (ie. each method annotated with @EmergeTest) will be run on a separate device, they cannot + * impact each other in any way. + */ +class ExamplePerformanceTest { + + @EmergeInit + fun init() { + // OPTIONAL + // Runs just once after installing the app on the test device before any other method. + // Typically this is used to log into the app, if needed. + // Only one @EmergeInit method per class is supported. + } + + @EmergeSetup + fun setup() { + // OPTIONAL + // Runs once before each test iteration. + // Typically this is used to navigate through to the screen where the performance test is meant to begin. + // Only one @EmergeSetup method per class is supported. + } + + @EmergeTest + fun myPerformanceTest() { + // REQUIRED + // The performance test. This is where the app should go through a short flow whose performance is critical. + // This might involve launching a screen or any other operation supported by UI Automator. + // As an example here we launch the application from the home screen. + + val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + device.pressHome() + + // Wait for launcher + device.wait(Until.hasObject(By.pkg(device.launcherPackageName).depth(0)), LAUNCH_TIMEOUT) + + // Launch the app + val context = ApplicationProvider.getApplicationContext<Context>() + val intent = checkNotNull(context.packageManager.getLaunchIntentForPackage(APP_PACKAGE_NAME)) { + "Could not get launch intent for package $APP_PACKAGE_NAME" + } + // Clear out any previous instances + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) + + // Wait for the app to appear + device.wait(Until.hasObject(By.pkg(APP_PACKAGE_NAME).depth(0)), LAUNCH_TIMEOUT) + } +} diff --git a/android/settings.gradle.kts b/android/settings.gradle.kts index 10f1afc5..3b81df2a 100644 --- a/android/settings.gradle.kts +++ b/android/settings.gradle.kts @@ -21,3 +21,4 @@ dependencyResolutionManagement { rootProject.name = "Hacker News" include(":app") +include(":performance")