From 9a20335c6a4a7fa814f1460afbf8384888ee2e88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Falc=C3=B3n?= Date: Wed, 17 Jun 2026 13:28:31 +0200 Subject: [PATCH] fix(transactions): only auto-select account on account pages (#549) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What When the add/edit transaction dialog resets in **create** mode, it no longer auto-selects the first transactional account. The account field starts empty so the user must pick one deliberately. The only exception is the account detail page (`accounts/{uuid}`), which passes `initialAccountId`; there the dialog still pre-selects that account. ## Why Auto-selecting the first account made it easy to accidentally book a transaction to the wrong account. Forcing a deliberate pick (except where the account is unambiguous from context) avoids that. ## How - `edit-transaction-dialog.tsx`: dropped the `availableAccounts[0]` fallback. The field now resolves to `initialAccount?.id ?? ''`. - The existing submit guard (`Account is required`) already covers the empty case. - `Accounts/Show.tsx` already passes `initialAccountId={account.id}`, so the account-page behavior is unchanged; the transactions list passes nothing, so it now starts empty. ## Tests Added two unit tests to `edit-transaction-dialog.test.tsx`: - no `initialAccountId` → account value stays empty (no auto-select) - matching `initialAccountId` → account is pre-selected --- .../edit-transaction-dialog.test.tsx | 87 +++++++++++++++++++ .../transactions/edit-transaction-dialog.tsx | 7 +- tests/Browser/AmountInputTest.php | 18 ++++ 3 files changed, 106 insertions(+), 6 deletions(-) diff --git a/resources/js/components/transactions/edit-transaction-dialog.test.tsx b/resources/js/components/transactions/edit-transaction-dialog.test.tsx index 8333f848..c6c9c4a9 100644 --- a/resources/js/components/transactions/edit-transaction-dialog.test.tsx +++ b/resources/js/components/transactions/edit-transaction-dialog.test.tsx @@ -52,6 +52,32 @@ vi.mock('sonner', () => ({ }, })); +vi.mock('@/components/ui/select', () => ({ + Select: ({ + value, + children, + }: { + value?: string; + children: React.ReactNode; + }) => ( +
+ {children} +
+ ), + SelectTrigger: ({ children }: { children: React.ReactNode }) => ( +
{children}
+ ), + SelectContent: ({ children }: { children: React.ReactNode }) => ( +
{children}
+ ), + SelectItem: ({ children }: { children: React.ReactNode }) => ( +
{children}
+ ), + SelectValue: ({ placeholder }: { placeholder?: string }) => ( + {placeholder} + ), +})); + vi.mock('@/components/ui/dialog', () => ({ Dialog: ({ children, @@ -79,6 +105,11 @@ vi.mock('@/components/ui/dialog', () => ({ describe('EditTransactionDialog', () => { beforeEach(() => { + globalThis.ResizeObserver = class { + observe() {} + unobserve() {} + disconnect() {} + }; Object.defineProperty(globalThis, 'localStorage', { value: { getItem: vi.fn(() => null), @@ -128,4 +159,60 @@ describe('EditTransactionDialog', () => { expect(screen.getByText('Debtor')).toBeInTheDocument(); expect(screen.getByDisplayValue('Victor Falcon')).toBeDisabled(); }); + + const checkingAccount = { + id: 'account-1', + name: 'Checking', + name_iv: null, + encrypted: false, + bank: null, + type: 'checking' as const, + currency_code: 'EUR', + banking_connection_id: null, + external_account_id: null, + linked_at: null, + }; + + it('does not auto-select an account when no initialAccountId is given', () => { + render( + , + ); + + expect(screen.getByTestId('account-value')).toHaveAttribute( + 'data-value', + '', + ); + }); + + it('auto-selects the account matching initialAccountId (account page)', () => { + render( + , + ); + + expect(screen.getByTestId('account-value')).toHaveAttribute( + 'data-value', + 'account-1', + ); + }); }); diff --git a/resources/js/components/transactions/edit-transaction-dialog.tsx b/resources/js/components/transactions/edit-transaction-dialog.tsx index 77053273..c5fe7f03 100644 --- a/resources/js/components/transactions/edit-transaction-dialog.tsx +++ b/resources/js/components/transactions/edit-transaction-dialog.tsx @@ -129,12 +129,7 @@ export function EditTransactionDialog({ const initialAccount = availableAccounts.find( (account) => account.id === initialAccountId, ); - setAccountId( - initialAccount?.id ?? - (availableAccounts.length > 0 - ? availableAccounts[0].id - : ''), - ); + setAccountId(initialAccount?.id ?? ''); setCategoryId('null'); setSelectedLabelIds([]); setNotes(''); diff --git a/tests/Browser/AmountInputTest.php b/tests/Browser/AmountInputTest.php index 1f262c37..961aaea1 100644 --- a/tests/Browser/AmountInputTest.php +++ b/tests/Browser/AmountInputTest.php @@ -47,6 +47,7 @@ it('can create a transaction with amount input', function () { $category = Category::factory()->create(['user_id' => $user->id]); $account = Account::factory()->create([ 'user_id' => $user->id, + 'name' => 'Test Checking', 'currency_code' => 'USD', 'type' => 'checking', ]); @@ -65,6 +66,11 @@ it('can create a transaction with amount input', function () { ->wait(0.5) ->fill('#amount', '123.45') ->wait(0.5) + ->click('[data-testid="account-select"]') + ->wait(2) + ->waitForText('Test Checking', 5) + ->click('[role="option"]:has-text("Test Checking")') + ->wait(0.5) ->click('[data-testid="category-select"]') ->wait(1) ->click($category->name) @@ -89,6 +95,7 @@ it('formats amount when pressing enter', function () { $category = Category::factory()->create(['user_id' => $user->id]); $account = Account::factory()->create([ 'user_id' => $user->id, + 'name' => 'Test Checking', 'currency_code' => 'USD', 'type' => 'checking', ]); @@ -104,6 +111,11 @@ it('formats amount when pressing enter', function () { ->fill('#description', 'Test Transaction Enter') ->fill('#amount', '99.99') ->wait(0.5) + ->click('[data-testid="account-select"]') + ->wait(2) + ->waitForText('Test Checking', 5) + ->click('[role="option"]:has-text("Test Checking")') + ->wait(0.5) ->click('[data-testid="category-select"]') ->wait(0.5) ->click($category->name) @@ -127,6 +139,7 @@ it('accepts negative amounts', function () { $category = Category::factory()->create(['user_id' => $user->id]); $account = Account::factory()->create([ 'user_id' => $user->id, + 'name' => 'Test Checking', 'currency_code' => 'USD', 'type' => 'checking', ]); @@ -141,6 +154,11 @@ it('accepts negative amounts', function () { ->wait(1) ->fill('#description', 'Test Negative Amount') ->fill('#amount', '-50.00') + ->click('[data-testid="account-select"]') + ->wait(2) + ->waitForText('Test Checking', 5) + ->click('[role="option"]:has-text("Test Checking")') + ->wait(0.5) ->click('[data-testid="category-select"]') ->wait(0.5) ->click($category->name)