Fake the external currency-rate provider in balance-evolution tests
The stray-request guard added earlier surfaced five non-hermetic tests that
reached the real currency-rate CDN (cdn.jsdelivr.net / currency-api.pages.dev)
without an Http::fake(): four balance-evolution cases in AccountControllerTest
and one loan projection case in LoanTest. They passed on main only because CI
has network access and the request actually went out; under the guard the
unfaked request now throws, returning 500.
Adds a fakeCurrencyApi() helper in tests/Pest.php that stubs the provider's
/currencies/{code}.min.json endpoint with a deterministic 1:1 rate in the exact
shape the services parse ($response->json($currency)), and calls it from both
files' beforeEach. The stub returns null for non-matching URLs, so it never
shadows another test's own fakes nor the stray-request guard.
Note: a single global default fake in Pest.php was rejected on purpose — Laravel
resolves stubs first-match-wins in registration order, so a beforeEach-level
fake would shadow the per-test currency fakes in CurrencyConversionServiceTest
and ExchangeRateServiceTest and break their assertions.
This commit is contained in:
parent
f803a4a9b0
commit
269b90ccb5
|
|
@ -14,6 +14,11 @@ use App\Models\User;
|
|||
beforeEach(function () {
|
||||
config(['landing.hide_auth_buttons' => false]);
|
||||
|
||||
// The balance-evolution endpoint converts account currency via the external
|
||||
// currency-rate provider; fake it so these tests stay hermetic under the
|
||||
// stray-request guard instead of hitting the CDN.
|
||||
fakeCurrencyApi();
|
||||
|
||||
$this->user = User::factory()->onboarded()->create();
|
||||
$this->actingAs($this->user);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ use function Pest\Laravel\assertDatabaseHas;
|
|||
use function Pest\Laravel\assertDatabaseMissing;
|
||||
|
||||
beforeEach(function () {
|
||||
// The balance-evolution endpoint converts account currency via the external
|
||||
// currency-rate provider; fake it so these tests stay hermetic under the
|
||||
// stray-request guard instead of hitting the CDN.
|
||||
fakeCurrencyApi();
|
||||
|
||||
$this->user = User::factory()->onboarded()->create();
|
||||
$this->bank = Bank::factory()->create();
|
||||
$this->service = app(LoanAmortizationService::class);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use App\Services\Banking\BalanceSyncService;
|
|||
use App\Services\Banking\Sync\BankingConnectionSyncerFactory;
|
||||
use App\Services\Banking\TransactionSyncService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\Client\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Stripe\Collection as StripeCollection;
|
||||
|
|
@ -303,3 +304,37 @@ function runSync(
|
|||
|
||||
$job->handle(app(BankingConnectionSyncerFactory::class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake the external currency-rate provider (the jsdelivr CDN and its pages.dev
|
||||
* fallback) that CurrencyConversionService and ExchangeRateService fetch from,
|
||||
* returning a deterministic 1:1 rate for every currency. Tests that trigger a
|
||||
* currency conversion (e.g. the balance-evolution endpoint) can call this in
|
||||
* their setup to stay hermetic under the stray-request guard.
|
||||
*
|
||||
* The stub only matches the provider's `/currencies/{code}.min.json` path and
|
||||
* returns null otherwise, so it never shadows another test's own Http::fake()
|
||||
* nor the stray-request guard for unrelated hosts.
|
||||
*/
|
||||
function fakeCurrencyApi(): void
|
||||
{
|
||||
Http::fake(function (Request $request) {
|
||||
if (! preg_match('#/currencies/([a-z0-9]+)\.min\.json#i', $request->url(), $matches)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$currency = strtolower($matches[1]);
|
||||
|
||||
return Http::response([
|
||||
'date' => '2024-01-01',
|
||||
$currency => [
|
||||
'usd' => 1.0,
|
||||
'eur' => 1.0,
|
||||
'gbp' => 1.0,
|
||||
'jpy' => 1.0,
|
||||
'btc' => 1.0,
|
||||
'eth' => 1.0,
|
||||
],
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue