app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 13e9a31019a8504b5fa96a7d4ee271351f987e86
parent 85ee2a59c012383d3a86f21df033ba12400d5427
Author: triesap <tyson@radroots.org>
Date:   Sat,  1 Aug 2026 18:39:03 +0000

test: prove the complete account UI journey

- label account inputs for stable accessible interaction
- add two accounts through the integrated Compose surface
- exercise selection, status, cancellation, and confirmation
- return deterministically to the visible empty state

Diffstat:
Mapp/desktop/src/main/kotlin/org/radroots/studio/accounts/ui/AccountsScreen.kt | 3+++
Mapp/desktop/src/test/kotlin/org/radroots/studio/accounts/ui/AccountsScreenTest.kt | 45+++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+), 0 deletions(-)

diff --git a/app/desktop/src/main/kotlin/org/radroots/studio/accounts/ui/AccountsScreen.kt b/app/desktop/src/main/kotlin/org/radroots/studio/accounts/ui/AccountsScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.selected import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp @@ -121,6 +122,7 @@ private fun AddAccountForm( }, modifier = Modifier .fillMaxWidth() + .semantics { contentDescription = "Account display name" } .testTag("add-display-name") .padding(8.dp), decorationBox = { innerTextField -> @@ -137,6 +139,7 @@ private fun AddAccountForm( }, modifier = Modifier .fillMaxWidth() + .semantics { contentDescription = "Account server URL" } .testTag("add-server-url") .padding(8.dp), decorationBox = { innerTextField -> diff --git a/app/desktop/src/test/kotlin/org/radroots/studio/accounts/ui/AccountsScreenTest.kt b/app/desktop/src/test/kotlin/org/radroots/studio/accounts/ui/AccountsScreenTest.kt @@ -1,5 +1,6 @@ package org.radroots.studio.accounts.ui +import java.util.ArrayDeque import androidx.compose.ui.test.ExperimentalTestApi import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsSelected @@ -257,4 +258,48 @@ class AccountsScreenTest { onAllNodesWithTag("account-row:${second.id.value}").assertCountEquals(0) onNodeWithTag("account-row:${first.id.value}").assertIsSelected() } + + @Test + fun integratedAccountJourneyReturnsToTheEmptyState() = runComposeUiTest { + val generatedIds = ArrayDeque(listOf(AccountId("account-1"), AccountId("account-2"))) + val store = AccountsStore( + initialState = AccountsState(), + reducer = AccountsReducer { generatedIds.removeFirst() }, + ) + setContent { + AccountsScreen( + state = store.state.value, + onAction = store::dispatch, + ) + } + + onNodeWithTag("accounts-empty").assertIsDisplayed() + addAccount("First Account", "https://first.example.test") + addAccount("Second Account", "https://second.example.test") + + onNodeWithTag("account-row:account-1").performClick() + onNodeWithTag("account-row:account-1").assertIsSelected() + onNodeWithTag("account-login:account-1", useUnmergedTree = true).performClick() + onNodeWithTag("account-logout:account-1", useUnmergedTree = true).performClick() + + onNodeWithTag("account-remove:account-2", useUnmergedTree = true).performClick() + onNodeWithTag("remove-cancel", useUnmergedTree = true).performClick() + onNodeWithTag("account-row:account-2").assertIsDisplayed() + onNodeWithTag("account-remove:account-2", useUnmergedTree = true).performClick() + onNodeWithTag("remove-confirm", useUnmergedTree = true).performClick() + + onNodeWithTag("account-remove:account-1", useUnmergedTree = true).performClick() + onNodeWithTag("remove-confirm", useUnmergedTree = true).performClick() + onNodeWithTag("accounts-empty").assertIsDisplayed() + onAllNodesWithTag("accounts-list").assertCountEquals(0) + } + + private fun androidx.compose.ui.test.ComposeUiTest.addAccount( + displayName: String, + serverUrl: String, + ) { + onNodeWithTag("add-display-name").performTextInput(displayName) + onNodeWithTag("add-server-url").performTextInput(serverUrl) + onNodeWithTag("add-submit").performClick() + } }