config()->set('services.exa.key', 'test-key')); it('не настроено, когда ключа нет', function () { config()->set('services.exa.key', ''); expect((new ExaBalanceProvider)->fetch()->ok)->toBeFalse(); }); it('жив без суммы, когда пинг 200', function () { config()->set('services.exa.balance_url', ''); config()->set('services.exa.base_url', 'https://api.exa.ai'); Http::fake(['api.exa.ai*' => Http::response([], 200)]); $r = (new ExaBalanceProvider)->fetch(); expect($r->ok)->toBeTrue(); expect($r->balance)->toBeNull(); }); it('деньги при balance_url с числом', function () { config()->set('services.exa.balance_url', 'https://api.exa.ai/billing/balance'); Http::fake(['api.exa.ai/billing/balance' => Http::response(['balance' => 40.0], 200)]); expect((new ExaBalanceProvider)->fetch()->balance)->toBe(40.0); }); it('жив при 404 на пинге (EXA достучались через тоннель — не 2xx, но сервис отвечает)', function () { config()->set('services.exa.balance_url', ''); config()->set('services.exa.base_url', 'https://api.exa.ai'); Http::fake(['api.exa.ai*' => Http::response('Not Found', 404)]); $r = (new ExaBalanceProvider)->fetch(); expect($r->ok)->toBeTrue(); expect($r->balance)->toBeNull(); }); it('мёртв при 5xx на пинге', function () { config()->set('services.exa.balance_url', ''); config()->set('services.exa.base_url', 'https://api.exa.ai'); Http::fake(['api.exa.ai*' => Http::response('err', 503)]); expect((new ExaBalanceProvider)->fetch()->ok)->toBeFalse(); }); it('с настроенным proxy поток не ломается (EXA за Cloudflare ходит через тоннель)', function () { config()->set('services.exa.balance_url', ''); config()->set('services.exa.base_url', 'https://api.exa.ai'); config()->set('services.exa.proxy', 'socks5h://127.0.0.1:10808'); Http::fake(['api.exa.ai*' => Http::response([], 200)]); expect((new ExaBalanceProvider)->fetch()->ok)->toBeTrue(); });