@@ -3,28 +3,147 @@ package com.flipcash.benchmark
33import androidx.benchmark.macro.junit4.BaselineProfileRule
44import androidx.test.ext.junit.runners.AndroidJUnit4
55import androidx.test.filters.LargeTest
6+ import androidx.test.platform.app.InstrumentationRegistry
7+ import androidx.test.uiautomator.By
8+ import androidx.test.uiautomator.Until
69import org.junit.Rule
710import org.junit.Test
811import org.junit.runner.RunWith
912
13+ /* *
14+ * Generates a baseline profile by exercising critical user journeys.
15+ *
16+ * Pass a seed phrase via instrumentation args to enable authenticated flows:
17+ * ```
18+ * -Pandroid.testInstrumentationRunnerArguments.SEED_PHRASE="word1 word2 ..."
19+ * ```
20+ *
21+ * Without a seed phrase, only the pre-auth startup path is profiled.
22+ */
1023@RunWith(AndroidJUnit4 ::class )
1124@LargeTest
1225class BaselineProfileGenerator {
1326
1427 @get:Rule
1528 val rule = BaselineProfileRule ()
1629
30+ private val seedPhrase: String?
31+ get() = InstrumentationRegistry .getArguments().getString(" SEED_PHRASE" )
32+
1733 @Test
1834 fun generateBaselineProfile () {
1935 rule.collect(
20- packageName = " com.flipcash.app.android " ,
36+ packageName = PACKAGE_NAME ,
2137 ) {
22- // Cold start the app — this covers the critical startup path
38+ // 1. Cold start — app init, Hilt DI, Compose runtime bootstrap
2339 pressHome()
2440 startActivityAndWait()
41+ device.waitForIdle()
2542
26- // TODO: Add user journey interactions here to cover hot paths
27- // e.g., navigating to balance, scanning, etc.
43+ val seed = seedPhrase
44+ if (seed.isNullOrBlank()) {
45+ // Pre-auth only: exercise login screen navigation
46+ preAuthJourney()
47+ } else {
48+ // Full journey: login then exercise main app screens
49+ login(seed)
50+ scannerJourney()
51+ walletJourney()
52+ giveJourney()
53+ menuJourney()
54+ }
2855 }
2956 }
57+
58+ private fun MacrobenchmarkScope.preAuthJourney () {
59+ // Navigate to seed input — exercises nav transitions, text input composables
60+ device.wait(Until .findObject(By .res(" login_button" )), TIMEOUT )?.click()
61+ device.waitForIdle()
62+
63+ // Back to onboarding — exercises pop transition
64+ device.pressBack()
65+ device.waitForIdle()
66+ }
67+
68+ private fun MacrobenchmarkScope.login (seed : String ) {
69+ // Tap "Log in"
70+ device.wait(Until .findObject(By .res(" login_button" )), TIMEOUT )?.click()
71+ device.wait(Until .findObject(By .res(" seed_input_field" )), TIMEOUT )?.click()
72+
73+ // Enter seed phrase
74+ device.wait(Until .findObject(By .res(" seed_input_field" )), TIMEOUT )?.text = seed
75+ device.waitForIdle()
76+
77+ // Confirm login
78+ device.wait(Until .findObject(By .res(" login_confirm_button" )), TIMEOUT )?.click()
79+
80+ // Wait for scanner screen
81+ device.wait(Until .findObject(By .res(" scanner_view" )), LOGIN_TIMEOUT )
82+ device.waitForIdle()
83+ }
84+
85+ private fun MacrobenchmarkScope.scannerJourney () {
86+ // Scanner is the home screen — let it fully render
87+ device.wait(Until .findObject(By .res(" scanner_view" )), TIMEOUT )
88+ device.waitForIdle()
89+ }
90+
91+ private fun MacrobenchmarkScope.walletJourney () {
92+ // Open wallet sheet
93+ device.wait(Until .findObject(By .text(" Wallet" )), TIMEOUT )?.click()
94+ device.wait(Until .findObject(By .res(" wallet_screen" )), TIMEOUT )
95+ device.waitForIdle()
96+
97+ // Open token info
98+ device.wait(Until .findObject(By .text(" Float" )), TIMEOUT )?.click()
99+ device.wait(Until .findObject(By .res(" token_info_screen" )), TIMEOUT )
100+ device.waitForIdle()
101+
102+ // Back to wallet
103+ device.pressBack()
104+ device.waitForIdle()
105+
106+ // Close sheet — swipe down to return to scanner
107+ dismissSheet()
108+ }
109+
110+ private fun MacrobenchmarkScope.giveJourney () {
111+ // Open give/cash screen
112+ device.wait(Until .findObject(By .text(" Give" )), TIMEOUT )?.click()
113+ device.wait(Until .findObject(By .res(" cash_screen" )), TIMEOUT )
114+ device.waitForIdle()
115+
116+ // Close sheet
117+ dismissSheet()
118+ }
119+
120+ private fun MacrobenchmarkScope.menuJourney () {
121+ // Open menu
122+ device.wait(Until .findObject(By .res(" menu_button" )), TIMEOUT )?.click()
123+ device.wait(Until .findObject(By .res(" menu_screen" )), TIMEOUT )
124+ device.waitForIdle()
125+
126+ // Close sheet
127+ dismissSheet()
128+ }
129+
130+ private fun MacrobenchmarkScope.dismissSheet () {
131+ device.swipe(
132+ device.displayWidth / 2 ,
133+ device.displayHeight / 4 ,
134+ device.displayWidth / 2 ,
135+ device.displayHeight,
136+ 10 ,
137+ )
138+ device.wait(Until .findObject(By .res(" scanner_view" )), TIMEOUT )
139+ device.waitForIdle()
140+ }
141+
142+ companion object {
143+ private const val PACKAGE_NAME = " com.flipcash.app.android"
144+ private const val TIMEOUT = 5_000L
145+ private const val LOGIN_TIMEOUT = 15_000L
146+ }
30147}
148+
149+ private typealias MacrobenchmarkScope = androidx.benchmark.macro.MacrobenchmarkScope
0 commit comments