From db359a0572ec94dcddb57faa96d1064eea992322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Falc=C3=B3n?= Date: Mon, 13 Apr 2026 13:02:21 +0100 Subject: [PATCH] test: expand browser coverage for account types and transactions (#279) ## Summary - add browser coverage for manual credit card, investment, retirement, and other account creation flows - replace placeholder transaction search coverage with real filter assertions and add edit/delete transaction browser tests - keep the new coverage focused on the existing account and transaction browser test files ## Testing - vendor/bin/pint --dirty --format agent - php artisan test --compact tests/Browser/BankAccountsTest.php tests/Browser/TransactionsTest.php --- tests/Browser/BankAccountsTest.php | 66 +++++++++++++++ tests/Browser/TransactionsTest.php | 132 ++++++++++++++++++++++++++++- 2 files changed, 197 insertions(+), 1 deletion(-) diff --git a/tests/Browser/BankAccountsTest.php b/tests/Browser/BankAccountsTest.php index d90da3e5..d805c36f 100644 --- a/tests/Browser/BankAccountsTest.php +++ b/tests/Browser/BankAccountsTest.php @@ -9,6 +9,35 @@ use Laravel\Pennant\Feature; use function Pest\Laravel\actingAs; +function createManualAccountTypeViaUi($page, string $displayName, string $bankName, string $type, string $currency = 'EUR', ?string $balance = null): void +{ + $page->assertSee('Bank accounts') + ->click('Create Account') + ->wait(0.5) + ->fill('#display_name', $displayName) + ->click('[data-testid="bank-select"]') + ->wait(0.5) + ->fill('input[placeholder="Search bank..."]', $bankName) + ->wait(0.5) + ->click($bankName) + ->click('button[name="type"]') + ->wait(0.5) + ->click("[role=\"option\"]:has-text(\"{$type}\")") + ->wait(0.3) + ->click('button[name="currency_code"]') + ->wait(0.5) + ->click("[role=\"option\"]:has-text(\"{$currency}\")") + ->wait(0.3); + + if ($balance !== null) { + $page->fill('#balance', $balance); + } + + $page->click('[data-testid="submit-account"]') + ->wait(2) + ->assertNoJavascriptErrors(); +} + it('can view bank accounts page', function () { $user = User::factory()->onboarded()->create(); @@ -144,6 +173,43 @@ it('can create a loan account with balance and loan details', function () { expect($loan->loanDetail->original_amount)->toBe(25000000); }); +it('can create the remaining manual account types', function (string $typeLabel, AccountType $type, ?string $balance) { + $user = User::factory()->onboarded()->create(); + $bank = Bank::factory()->create(['name' => 'Coverage Bank', 'logo' => null]); + + actingAs($user); + + $page = visit('/settings/accounts'); + + createManualAccountTypeViaUi( + $page, + "{$typeLabel} Coverage Account", + 'Coverage Bank', + $typeLabel, + 'EUR', + $balance, + ); + + $account = Account::query() + ->where('user_id', $user->id) + ->where('type', $type) + ->first(); + + expect($account)->not->toBeNull(); + expect($account->currency_code)->toBe('EUR'); + + if ($balance === null) { + expect($account->balances)->toHaveCount(0); + } else { + expect($account->balances)->toHaveCount(1); + } +})->with([ + 'credit card' => ['Credit Card', AccountType::CreditCard, null], + 'investment' => ['Investment', AccountType::Investment, '125000'], + 'retirement' => ['Retirement / Pension', AccountType::Retirement, '250000'], + 'others' => ['Others', AccountType::Others, null], +]); + it('can create a real estate account linked to an existing loan', function () { $user = User::factory()->onboarded()->create(); diff --git a/tests/Browser/TransactionsTest.php b/tests/Browser/TransactionsTest.php index cf6e05b3..32ea1a13 100644 --- a/tests/Browser/TransactionsTest.php +++ b/tests/Browser/TransactionsTest.php @@ -3,6 +3,7 @@ use App\Models\Account; use App\Models\Bank; use App\Models\Category; +use App\Models\Transaction; use App\Models\User; use function Pest\Laravel\actingAs; @@ -101,12 +102,141 @@ it('shows empty state when no transactions exist', function () { it('can filter transactions by search text', function () { $user = User::factory()->onboarded()->create(); + $bank = Bank::factory()->create(['name' => 'Filter Bank']); + $category = Category::factory()->create([ + 'user_id' => $user->id, + 'name' => 'Groceries', + ]); + $account = Account::factory()->create([ + 'user_id' => $user->id, + 'bank_id' => $bank->id, + 'name' => 'Daily Account', + 'currency_code' => 'USD', + 'type' => 'checking', + ]); + + Transaction::factory()->plaintext()->create([ + 'user_id' => $user->id, + 'account_id' => $account->id, + 'category_id' => $category->id, + 'description' => 'Weekly groceries', + 'amount' => -4500, + ]); + + Transaction::factory()->plaintext()->create([ + 'user_id' => $user->id, + 'account_id' => $account->id, + 'category_id' => $category->id, + 'description' => 'Electric bill', + 'amount' => -8000, + ]); actingAs($user); $page = visit('/transactions'); $page->assertSee('Transactions') - ->wait(2) + ->waitForText('Weekly groceries', 10) + ->assertSee('Electric bill') + ->fill('input[placeholder="Search description or notes..."]', 'groceries') + ->wait(1) + ->assertSee('Weekly groceries') + ->assertDontSee('Electric bill') + ->assertNoJavascriptErrors(); +}); + +it('can edit an existing transaction from the list', function () { + $user = User::factory()->onboarded()->create(); + $bank = Bank::factory()->create(['name' => 'Edit Tx Bank']); + $category = Category::factory()->create([ + 'user_id' => $user->id, + 'name' => 'Groceries', + ]); + $replacementCategory = Category::factory()->create([ + 'user_id' => $user->id, + 'name' => 'Dining Out', + ]); + $account = Account::factory()->create([ + 'user_id' => $user->id, + 'bank_id' => $bank->id, + 'name' => 'Editing Account', + 'currency_code' => 'USD', + 'type' => 'checking', + ]); + + $transaction = Transaction::factory()->plaintext()->create([ + 'user_id' => $user->id, + 'account_id' => $account->id, + 'category_id' => $category->id, + 'description' => 'Original transaction note', + 'amount' => -3200, + 'notes' => 'Original note', + 'source' => 'manually_created', + ]); + + actingAs($user); + + $page = visit('/transactions'); + + $page->assertSee('Transactions') + ->waitForText('Original transaction note', 10) + ->click('Original transaction note') + ->wait(1) + ->assertSee('Edit Transaction') + ->fill('#description', 'Updated dinner transaction') + ->click('[data-testid="category-select"]') + ->wait(1) + ->click('Dining Out') + ->fill('#notes', 'Updated note for browser test') + ->click('[data-testid="submit-transaction"]') + ->wait(3) + ->waitForText('Updated dinner transaction', 10) + ->assertSee('Dining Out') + ->assertNoJavascriptErrors(); + + $updatedTransaction = $transaction->fresh(); + + expect($updatedTransaction->description)->toBe('Updated dinner transaction'); + expect($updatedTransaction->notes)->toBe('Updated note for browser test'); + expect($updatedTransaction->category_id)->toBe($replacementCategory->id); +}); + +it('can delete a transaction from the actions menu', function () { + $user = User::factory()->onboarded()->create(); + $bank = Bank::factory()->create(['name' => 'Delete Tx Bank']); + $category = Category::factory()->create([ + 'user_id' => $user->id, + 'name' => 'Household', + ]); + $account = Account::factory()->create([ + 'user_id' => $user->id, + 'bank_id' => $bank->id, + 'name' => 'Delete Account', + 'currency_code' => 'USD', + 'type' => 'checking', + ]); + + $transaction = Transaction::factory()->plaintext()->create([ + 'user_id' => $user->id, + 'account_id' => $account->id, + 'category_id' => $category->id, + 'description' => 'Disposable transaction', + 'amount' => -1500, + ]); + + actingAs($user); + + $page = visit('/transactions'); + + $page->assertSee('Transactions') + ->waitForText('Disposable transaction', 10) + ->click('button:has-text("Open menu")') + ->wait(0.5) + ->click('Delete') + ->wait(0.5) + ->assertSee('Delete Transaction') + ->click('button:has-text("Delete")') + ->wait(3) + ->assertDontSee('Disposable transaction') ->assertNoJavascriptErrors(); });