Skip to content

Commit 1b5cda8

Browse files
committed
perf(benchmark): extend baseline profile to send/chat, search, and cash bill
Broaden the generated baseline profile beyond discovery so more warm paths are AOT-compiled on cold start. Also fixes giveJourney, which tapped "Give" (the nav label is "Cash") and had silently been a no-op — the cash screen/keypad/bill were never profiled. Journey additions to BaselineProfileGenerator (all Maestro-validated, money-safe): - Send -> contact list: pull-to-reveal search, type random chars (empty state), clear; open the first contact and send a text message (fund-free; contact not hardcoded); scroll the message list. - Cash: pull out the smallest bill ($0.01) then Cancel — a self-reclaiming round-trip (net ~0); never Share/Collect. An un-shared bill is auto-reclaimed on relaunch, so a mid-journey failure self-heals. - Refactor both auth branches to a shared authenticatedJourneys(). New testTags (exposed only in UI_TESTABLE variants, not shipping release): - send_contact_list, send_contact_row, send_search_field, send_search_clear - chat_screen, chat_message_list, chat_send_message_button, chat_message_input, chat_send_icon Regenerated profile now covers TokenLeaderboard/TokenInfoScreen/MarketCapChart, ContactList/ContactListScreen, MessengerScreen/MessageList/ChatInput, SearchInput, and CashScreen/AnimatedBill/CashBill. Signed-off-by: Brandon McAnsh <git@bmcreations.dev>
1 parent d01fbae commit 1b5cda8

7 files changed

Lines changed: 10317 additions & 1603 deletions

File tree

apps/flipcash/app/src/release/generated/baselineProfiles/baseline-prof.txt

Lines changed: 10216 additions & 1584 deletions
Large diffs are not rendered by default.

apps/flipcash/benchmark/src/main/kotlin/com/flipcash/benchmark/BaselineProfileGenerator.kt

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,14 @@ class BaselineProfileGenerator {
4848

4949
if (onScanner) {
5050
// Already logged in from a prior iteration
51-
scannerJourney()
52-
discoveryJourney()
53-
walletJourney()
54-
giveJourney()
55-
menuJourney()
51+
authenticatedJourneys()
5652
} else {
5753
val seed = seedPhrase
5854
if (seed.isNullOrBlank()) {
5955
preAuthJourney()
6056
} else {
6157
login(seed)
62-
scannerJourney()
63-
walletJourney()
64-
giveJourney()
65-
menuJourney()
58+
authenticatedJourneys()
6659
}
6760
}
6861
}
@@ -100,12 +93,74 @@ class BaselineProfileGenerator {
10093
device.waitForIdle()
10194
}
10295

96+
/** All authenticated journeys, run from the scanner. */
97+
private fun MacrobenchmarkScope.authenticatedJourneys() {
98+
scannerJourney()
99+
discoveryJourney()
100+
sendChatJourney()
101+
walletJourney()
102+
giveJourney()
103+
menuJourney()
104+
}
105+
103106
private fun MacrobenchmarkScope.scannerJourney() {
104107
// Scanner is the home screen — let it fully render
105108
device.wait(Until.findObject(By.res("scanner_view")), TIMEOUT)
106109
device.waitForIdle()
107110
}
108111

112+
private fun MacrobenchmarkScope.sendChatJourney() {
113+
// Open the Send tab -> contact list
114+
device.wait(Until.findObject(By.text("Send")), TIMEOUT)?.click()
115+
// Dismiss the "N Contacts Already On Flipcash" info dialog if it appears
116+
device.waitForIdle()
117+
device.findObject(By.text("OK"))?.click()
118+
device.wait(Until.findObject(By.res("send_contact_list")), LOGIN_TIMEOUT)
119+
device.waitForIdle()
120+
121+
// Pull down to reveal the search bar, type random chars (exercises the empty
122+
// search state), then clear it.
123+
device.findObject(By.res("send_contact_list"))?.let { list ->
124+
val b = list.visibleBounds
125+
device.swipe(b.centerX(), b.top + 40, b.centerX(), b.centerY() + 200, 20)
126+
}
127+
device.wait(Until.findObject(By.res("send_search_field")), TIMEOUT)?.click()
128+
device.waitForIdle()
129+
device.executeShellCommand("input text zzqxwv")
130+
device.waitForIdle()
131+
device.findObject(By.res("send_search_clear"))?.click()
132+
device.waitForIdle()
133+
device.pressBack() // dismiss the keyboard
134+
135+
// Open the FIRST contact's chat and send a text message. A message is fund-free
136+
// (money-safety: never tap Send Cash / confirm a spend). Contact is not
137+
// hardcoded — send_contact_row resolves to the first row.
138+
device.wait(Until.findObject(By.res("send_contact_row")), TIMEOUT)?.click()
139+
device.wait(Until.findObject(By.res("chat_screen")), LOGIN_TIMEOUT)
140+
device.waitForIdle()
141+
device.findObject(By.res("chat_send_message_button"))?.click()
142+
device.wait(Until.findObject(By.res("chat_message_input")), TIMEOUT)
143+
device.waitForIdle()
144+
device.executeShellCommand("input text BaselineProfileTest")
145+
device.waitForIdle()
146+
device.findObject(By.res("chat_send_icon"))?.click()
147+
device.waitForIdle()
148+
149+
// Scroll the message list so MessageList / bubble composition gets compiled.
150+
flingScroll("chat_message_list", Direction.DOWN, 2)
151+
flingScroll("chat_message_list", Direction.UP, 2)
152+
153+
// Back to the contact list, fling it for coverage, then back to the scanner.
154+
device.pressBack()
155+
device.wait(Until.findObject(By.res("send_contact_list")), TIMEOUT)
156+
device.waitForIdle()
157+
flingScroll("send_contact_list", Direction.UP, 2)
158+
flingScroll("send_contact_list", Direction.DOWN, 1)
159+
device.pressBack()
160+
device.wait(Until.findObject(By.res("scanner_view")), TIMEOUT)
161+
device.waitForIdle()
162+
}
163+
109164
private fun MacrobenchmarkScope.discoveryJourney() {
110165
// Open the Discover tab from the scanner bottom nav
111166
device.wait(Until.findObject(By.text("Discover")), TIMEOUT)?.click()
@@ -208,13 +263,25 @@ class BaselineProfileGenerator {
208263
}
209264

210265
private fun MacrobenchmarkScope.giveJourney() {
211-
// Open give/cash screen
212-
device.wait(Until.findObject(By.text("Give")), TIMEOUT)?.click()
213-
device.wait(Until.findObject(By.res("cash_screen")), TIMEOUT)
266+
// Open the Cash tab (the give/cash screen with the amount keypad)
267+
device.wait(Until.findObject(By.text("Cash")), TIMEOUT)?.click()
268+
device.wait(Until.findObject(By.res("keypad_dot")), TIMEOUT)
214269
device.waitForIdle()
215270

216-
// Close sheet
217-
dismissSheet()
271+
// Pull out the smallest bill ($0.01) to warm the keypad + bill rendering, then
272+
// Cancel to put it straight back — a self-reclaiming round-trip (net ~0).
273+
// MONEY-SAFETY: smallest amount, immediate Cancel, never Share/Collect. If an
274+
// iteration dies between Next and Cancel, the app reclaims the un-shared bill on
275+
// the next relaunch.
276+
device.findObject(By.res("keypad_dot"))?.click()
277+
device.findObject(By.res("keypad_0"))?.click()
278+
device.findObject(By.res("keypad_1"))?.click()
279+
device.findObject(By.text("Next"))?.click()
280+
device.wait(Until.findObject(By.res("cash_bill")), LOGIN_TIMEOUT)
281+
device.waitForIdle()
282+
device.findObject(By.text("Cancel"))?.click()
283+
device.wait(Until.findObject(By.res("scanner_view")), TIMEOUT)
284+
device.waitForIdle()
218285
}
219286

220287
private fun MacrobenchmarkScope.menuJourney() {

apps/flipcash/features/direct-send/src/main/kotlin/com/flipcash/app/directsend/internal/screens/ContactListScreen.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import androidx.compose.runtime.getValue
1717
import androidx.compose.runtime.snapshotFlow
1818
import androidx.compose.ui.Alignment
1919
import androidx.compose.ui.Modifier
20+
import androidx.compose.ui.platform.testTag
2021
import androidx.compose.ui.res.stringResource
2122
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2223
import com.flipcash.app.core.AppRoute
@@ -147,7 +148,9 @@ internal fun ContactListScreen() {
147148
.padding(vertical = CodeTheme.dimens.grid.x3),
148149
) {
149150
SearchInput(
150-
modifier = Modifier.weight(1f),
151+
modifier = Modifier
152+
.weight(1f)
153+
.testTag("send_search_field"),
151154
state = state.searchState,
152155
contentPadding = PaddingValues(start = CodeTheme.dimens.grid.x1),
153156
)

apps/flipcash/features/direct-send/src/main/kotlin/com/flipcash/app/directsend/internal/screens/components/ContactList.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import androidx.compose.material3.Text
3131
import androidx.compose.runtime.Composable
3232
import androidx.compose.ui.Alignment
3333
import androidx.compose.ui.Modifier
34+
import androidx.compose.ui.platform.testTag
3435
import androidx.compose.ui.draw.clip
3536
import androidx.compose.ui.graphics.Brush
3637
import androidx.compose.ui.graphics.Color
@@ -77,6 +78,7 @@ internal fun ContactList(
7778

7879
LazyColumn(
7980
modifier = Modifier
81+
.testTag("send_contact_list")
8082
.verticalScrollStateGradient(
8183
scrollState = listState,
8284
color = CodeTheme.colors.background,
@@ -324,6 +326,7 @@ private fun ContactRowItem(
324326
Row(
325327
modifier = Modifier
326328
.fillMaxWidth()
329+
.testTag("send_contact_row")
327330
.clickable(onClick = onClick)
328331
.padding(vertical = CodeTheme.dimens.inset)
329332
.padding(end = CodeTheme.dimens.inset),

apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/MessengerScreen.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import androidx.compose.ui.graphics.Color
3737
import androidx.compose.ui.graphics.TransformOrigin
3838
import androidx.compose.ui.layout.onSizeChanged
3939
import androidx.compose.ui.platform.LocalDensity
40+
import androidx.compose.ui.platform.testTag
4041
import androidx.compose.ui.res.stringResource
4142
import androidx.compose.ui.text.style.TextAlign
4243
import androidx.compose.ui.unit.dp
@@ -95,6 +96,7 @@ internal fun MessengerScreen(viewModel: ChatViewModel) {
9596
MessageList(
9697
modifier = Modifier
9798
.fillMaxSize()
99+
.testTag("chat_message_list")
98100
.hazeSource(hazeState),
99101
state = state,
100102
contentPadding = overlapPadding,
@@ -274,6 +276,7 @@ private fun UserControlBottomBar(
274276
CodeButton(
275277
modifier = Modifier
276278
.weight(1f)
279+
.testTag("chat_send_message_button")
277280
.hazeEffect(hazeState) {
278281
blurEffect {
279282
style = material
@@ -289,6 +292,7 @@ private fun UserControlBottomBar(
289292
ChatViewModel.UserState.Typing -> {
290293
ChatInput(
291294
modifier = Modifier
295+
.testTag("chat_message_input")
292296
.fillMaxWidth()
293297
.border(
294298
CodeTheme.dimens.border,
@@ -348,7 +352,7 @@ private fun ChatInputScaffold(
348352
var topBarHeight by remember { mutableStateOf(0.dp) }
349353
var bottomBarHeight by remember { mutableStateOf(0.dp) }
350354

351-
Box(modifier = Modifier.imePadding()) {
355+
Box(modifier = Modifier.imePadding().testTag("chat_screen")) {
352356
content(
353357
PaddingValues(
354358
top = topBarHeight,

ui/components/src/main/kotlin/com/getcode/ui/components/SearchInput.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.compose.material.icons.filled.Search
1212
import androidx.compose.material.icons.outlined.Close
1313
import androidx.compose.runtime.Composable
1414
import androidx.compose.ui.Modifier
15+
import androidx.compose.ui.platform.testTag
1516
import androidx.compose.ui.res.stringResource
1617
import com.getcode.theme.CodeTheme
1718
import com.getcode.theme.White50
@@ -41,9 +42,11 @@ fun SearchInput(
4142
trailingIcon = {
4243
if (state.text.isNotEmpty()) {
4344
Icon(
44-
modifier = Modifier.unboundedClickable {
45-
state.clearText()
46-
}.padding(end = CodeTheme.dimens.grid.x3),
45+
modifier = Modifier
46+
.testTag("send_search_clear")
47+
.unboundedClickable {
48+
state.clearText()
49+
}.padding(end = CodeTheme.dimens.grid.x3),
4750
imageVector = Icons.Outlined.Close,
4851
contentDescription = null,
4952
tint = White50,

ui/components/src/main/kotlin/com/getcode/ui/components/chat/ChatInput.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import androidx.compose.runtime.getValue
2121
import androidx.compose.runtime.remember
2222
import androidx.compose.ui.Alignment
2323
import androidx.compose.ui.Modifier
24+
import androidx.compose.ui.platform.testTag
2425
import androidx.compose.ui.draw.clip
2526
import androidx.compose.ui.focus.FocusRequester
2627
import androidx.compose.ui.focus.focusRequester
@@ -98,6 +99,7 @@ fun ChatInput(
9899
trailingIcon = {
99100
Icon(
100101
modifier = Modifier
102+
.testTag("chat_send_icon")
101103
.graphicsLayer {
102104
alpha = sendAlpha
103105
scaleX = sendScale

0 commit comments

Comments
 (0)