Http::response([[ 'qc' => 0, 'qc_conflict' => 0, 'type' => 'Мобильный', 'phone' => '+7 921 555-12-34', 'provider' => 'МегаФон', 'region' => 'Санкт-Петербург и область', 'city' => null, 'timezone' => 'UTC+3', ]], 200)]); $resp = app(DaDataPhoneClient::class)->cleanPhone('79215551234'); expect($resp->qc)->toBe(0) ->and($resp->provider)->toBe('МегаФон') ->and($resp->region)->toBe('Санкт-Петербург и область') ->and($resp->type)->toBe('Мобильный') ->and($resp->raw)->toBeArray(); }); it('parses qc=3 multiple response', function (): void { Http::fake(['cleaner.dadata.ru/*' => Http::response([[ 'qc' => 3, 'region' => 'Москва', 'provider' => 'МТС', 'type' => 'Мобильный', ]], 200)]); expect(app(DaDataPhoneClient::class)->cleanPhone('79991234567')->qc)->toBe(3); }); it('sends Token auth, X-Secret header and json-array body', function (): void { config(['services.dadata.api_key' => 'KEY', 'services.dadata.secret' => 'SEC']); Http::fake(['cleaner.dadata.ru/*' => Http::response([['qc' => 0, 'region' => 'Москва']], 200)]); app(DaDataPhoneClient::class)->cleanPhone('79161234567'); Http::assertSent(function ($request): bool { return $request->url() === 'https://cleaner.dadata.ru/api/v1/clean/phone' && $request->hasHeader('Authorization', 'Token KEY') && $request->hasHeader('X-Secret', 'SEC') && $request->body() === '["79161234567"]'; }); }); it('throws DaDataTimeoutException on connection error', function (): void { Http::fake(fn () => throw new ConnectionException('timeout')); expect(fn () => app(DaDataPhoneClient::class)->cleanPhone('79215551234')) ->toThrow(DaDataTimeoutException::class); }); it('throws DaDataException on persistent 5xx', function (): void { Http::fake(['cleaner.dadata.ru/*' => Http::response('upstream error', 500)]); expect(fn () => app(DaDataPhoneClient::class)->cleanPhone('79215551234')) ->toThrow(DaDataException::class); }); it('retries once on 5xx then succeeds', function (): void { Http::fakeSequence('cleaner.dadata.ru/*') ->push('upstream error', 500) ->push([['qc' => 0, 'region' => 'Москва', 'provider' => 'МТС']], 200); $resp = app(DaDataPhoneClient::class)->cleanPhone('79161234567'); expect($resp->qc)->toBe(0); Http::assertSentCount(2); }); it('does not retry on 4xx client error', function (): void { Http::fake(['cleaner.dadata.ru/*' => Http::response('bad request', 400)]); expect(fn () => app(DaDataPhoneClient::class)->cleanPhone('79161234567')) ->toThrow(DaDataException::class); Http::assertSentCount(1); });