app

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

commit b38ccc3e956fe6303d661e44fb89211214fcf1cc
parent 81bd94667797153b7be8159d2144c2a1bcd61535
Author: triesap <tyson@radroots.org>
Date:   Sat,  1 Aug 2026 18:29:15 +0000

test: prove the complete account action trace

- exercise every account workflow in one deterministic sequence
- validate state invariants after every transition
- cover idempotent status and typed failure recovery
- verify deterministic selection after confirmed removal

Diffstat:
Mapp/desktop/src/test/kotlin/org/radroots/studio/accounts/state/AccountsReducerTest.kt | 32++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+), 0 deletions(-)

diff --git a/app/desktop/src/test/kotlin/org/radroots/studio/accounts/state/AccountsReducerTest.kt b/app/desktop/src/test/kotlin/org/radroots/studio/accounts/state/AccountsReducerTest.kt @@ -9,6 +9,7 @@ import org.radroots.studio.accounts.model.AccountsAction import org.radroots.studio.accounts.model.AccountsProblem import org.radroots.studio.accounts.model.AccountsState import org.radroots.studio.accounts.model.LoginStatus +import org.radroots.studio.accounts.model.requireValid import org.radroots.studio.accounts.testAccount import org.radroots.studio.accounts.testAccountsState @@ -280,6 +281,37 @@ class AccountsReducerTest { assertEquals(null, finalAccount.pendingRemovalAccountId) } + @Test + fun completeActionTracePreservesEveryStateInvariant() { + val reducer = reducerWithIds("account-1", "account-2") + val actions = listOf( + AccountsAction.EditAddDisplayName("First Account"), + AccountsAction.EditAddServerUrl("https://first.example.test"), + AccountsAction.SubmitAddAccount, + AccountsAction.EditAddDisplayName("Second Account"), + AccountsAction.EditAddServerUrl("https://second.example.test"), + AccountsAction.SubmitAddAccount, + AccountsAction.SelectAccount(AccountId("account-1")), + AccountsAction.LogIn(AccountId("account-1")), + AccountsAction.LogIn(AccountId("account-1")), + AccountsAction.LogOut(AccountId("account-1")), + AccountsAction.RequestRemoveAccount(AccountId("account-2")), + AccountsAction.CancelRemoveAccount, + AccountsAction.RequestRemoveAccount(AccountId("account-1")), + AccountsAction.ConfirmRemoveAccount(AccountId("account-1")), + AccountsAction.SelectAccount(AccountId("missing")), + AccountsAction.DismissProblem, + ) + + val result = actions.fold(AccountsState()) { state, action -> + reducer.reduce(state, action).requireValid() + } + + assertEquals(listOf(AccountId("account-2")), result.accounts.map { it.id }) + assertEquals(AccountId("account-2"), result.selectedAccountId) + assertEquals(null, result.problem) + } + private fun draftState( displayName: String, serverUrl: String,