whisper-money/tests/Feature/OpenBanking/IndexaCapitalBalanceSyncTes...

166 lines
5.6 KiB
PHP

<?php
use App\Models\Account;
use App\Models\BankingConnection;
use App\Models\User;
use App\Services\Banking\IndexaCapitalBalanceSyncService;
use App\Services\Banking\IndexaCapitalClient;
use Illuminate\Support\Facades\Http;
test('syncs historical balances from indexa capital portfolios', function () {
$user = User::factory()->onboarded()->create();
$connection = BankingConnection::factory()->indexaCapital()->create([
'user_id' => $user->id,
]);
$account = Account::factory()->connected()->create([
'user_id' => $user->id,
'banking_connection_id' => $connection->id,
'external_account_id' => 'IC-001',
]);
Http::fake([
'api.indexacapital.com/accounts/IC-001/performance' => Http::response([
'portfolios' => [
['date' => now()->toDateString(), 'total_amount' => 15234.56],
['date' => now()->subDay()->toDateString(), 'total_amount' => 15200.00],
['date' => now()->subDays(2)->toDateString(), 'total_amount' => 15100.00],
],
]),
]);
$client = new IndexaCapitalClient('test-token');
$service = new IndexaCapitalBalanceSyncService;
$service->sync($account, $client);
expect($account->balances()->count())->toBe(3);
$latest = $account->balances()->orderBy('balance_date', 'desc')->first();
expect($latest->balance)->toBe(1523456);
expect($latest->balance_date->toDateString())->toBe(now()->toDateString());
});
test('syncs all available historical data', function () {
$user = User::factory()->onboarded()->create();
$connection = BankingConnection::factory()->indexaCapital()->create([
'user_id' => $user->id,
]);
$account = Account::factory()->connected()->create([
'user_id' => $user->id,
'banking_connection_id' => $connection->id,
'external_account_id' => 'IC-001',
]);
Http::fake([
'api.indexacapital.com/accounts/IC-001/performance' => Http::response([
'portfolios' => [
['date' => now()->toDateString(), 'total_amount' => 10000.00],
['date' => now()->subMonths(12)->toDateString(), 'total_amount' => 9000.00],
['date' => now()->subYears(3)->toDateString(), 'total_amount' => 8000.00],
['date' => now()->subYears(5)->toDateString(), 'total_amount' => 7000.00],
],
]),
]);
$client = new IndexaCapitalClient('test-token');
$service = new IndexaCapitalBalanceSyncService;
$service->sync($account, $client);
expect($account->balances()->count())->toBe(4);
});
test('updates existing balance for same date', function () {
$user = User::factory()->onboarded()->create();
$connection = BankingConnection::factory()->indexaCapital()->create([
'user_id' => $user->id,
]);
$account = Account::factory()->connected()->create([
'user_id' => $user->id,
'banking_connection_id' => $connection->id,
'external_account_id' => 'IC-001',
]);
$account->balances()->create([
'balance_date' => now()->toDateString(),
'balance' => 100000,
]);
Http::fake([
'api.indexacapital.com/accounts/IC-001/performance' => Http::response([
'portfolios' => [
['date' => now()->toDateString(), 'total_amount' => 20000.00],
],
]),
]);
$client = new IndexaCapitalClient('test-token');
$service = new IndexaCapitalBalanceSyncService;
$service->sync($account, $client);
expect($account->balances()->count())->toBe(1);
expect($account->balances()->first()->balance)->toBe(2000000);
});
test('skips account without external_account_id', function () {
$user = User::factory()->onboarded()->create();
$account = Account::factory()->create([
'user_id' => $user->id,
'external_account_id' => null,
]);
$client = Mockery::mock(IndexaCapitalClient::class);
$client->shouldNotReceive('getPerformance');
$service = new IndexaCapitalBalanceSyncService;
$service->sync($account, $client);
expect($account->balances()->count())->toBe(0);
});
test('handles missing portfolios gracefully', function () {
$user = User::factory()->onboarded()->create();
$connection = BankingConnection::factory()->indexaCapital()->create([
'user_id' => $user->id,
]);
$account = Account::factory()->connected()->create([
'user_id' => $user->id,
'banking_connection_id' => $connection->id,
'external_account_id' => 'IC-001',
]);
Http::fake([
'api.indexacapital.com/accounts/IC-001/performance' => Http::response([
'plan_expected_return' => 0.046,
]),
]);
$client = new IndexaCapitalClient('test-token');
$service = new IndexaCapitalBalanceSyncService;
$service->sync($account, $client);
expect($account->balances()->count())->toBe(0);
});
test('handles empty portfolios array gracefully', function () {
$user = User::factory()->onboarded()->create();
$connection = BankingConnection::factory()->indexaCapital()->create([
'user_id' => $user->id,
]);
$account = Account::factory()->connected()->create([
'user_id' => $user->id,
'banking_connection_id' => $connection->id,
'external_account_id' => 'IC-001',
]);
Http::fake([
'api.indexacapital.com/accounts/IC-001/performance' => Http::response([
'portfolios' => [],
]),
]);
$client = new IndexaCapitalClient('test-token');
$service = new IndexaCapitalBalanceSyncService;
$service->sync($account, $client);
expect($account->balances()->count())->toBe(0);
});