From 2a2cb3871b8c8a8efdec387942e93428a82d6ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vi=CC=81ctor=20Falco=CC=81n?= Date: Thu, 2 Jul 2026 15:19:54 +0200 Subject: [PATCH] test(banking): cover intra-run cross-page dedup The pagination test only used distinct ids and the fingerprint dedup test used separate sync calls, so nothing exercised the same transaction appearing on two pages of a single sync being deduped from the in-memory set. Add that scenario. --- .../TransactionSyncServiceTest.php | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/Feature/OpenBanking/TransactionSyncServiceTest.php b/tests/Feature/OpenBanking/TransactionSyncServiceTest.php index 5e0a4119..721272f7 100644 --- a/tests/Feature/OpenBanking/TransactionSyncServiceTest.php +++ b/tests/Feature/OpenBanking/TransactionSyncServiceTest.php @@ -562,6 +562,42 @@ test('sync dedupes external ids case-insensitively like the production collation expect($account->transactions()->count())->toBe(1); }); +test('sync dedupes a transaction that repeats across pages in one run', function () { + $user = User::factory()->onboarded()->create(); + $connection = BankingConnection::factory()->create(['user_id' => $user->id]); + $account = Account::factory()->connected()->create([ + 'user_id' => $user->id, + 'banking_connection_id' => $connection->id, + 'external_account_id' => 'ext-123', + ]); + + $payload = [ + 'transaction_id' => 'txn-dup', + 'transaction_amount' => ['amount' => '50.00', 'currency' => 'EUR'], + 'credit_debit_indicator' => 'DBIT', + 'booking_date' => '2025-01-15', + 'remittance_information' => ['Repeated across pages'], + ]; + + $mockProvider = Mockery::mock(BankingProviderInterface::class); + $mockProvider->shouldReceive('getTransactions') + ->once() + ->ordered() + ->andReturn(['transactions' => [$payload], 'continuation_key' => 'page2']); + $mockProvider->shouldReceive('getTransactions') + ->once() + ->ordered() + ->andReturn(['transactions' => [$payload], 'continuation_key' => null]); + + $service = new TransactionSyncService($mockProvider, new TransactionDescriptionFormatter); + $created = $service->sync($account, '2025-01-01', '2025-01-31'); + + // The second occurrence is folded into the in-memory set from the first + // insert, so it is deduped without relying on the unique-index backstop. + expect($created)->toBe(1); + expect($account->transactions()->count())->toBe(1); +}); + test('sync checks for duplicates once per run regardless of batch size', function () { $user = User::factory()->onboarded()->create(); $connection = BankingConnection::factory()->create(['user_id' => $user->id]);