set('services.snipe_it', [ 'url' => 'https://inventory.example.test', 'read_token' => 'read-token-for-tests', 'timeout' => 2, 'page_size' => 2, 'retries' => 1, 'retry_delay_ms' => 0, ]); }); it('percorre todas as páginas de equipamentos com os cabeçalhos obrigatórios', function () { Http::fakeSequence() ->push(['total' => 3, 'rows' => [snipeClientRow(1), snipeClientRow(2)]]) ->push(['total' => 3, 'rows' => [snipeClientRow(3)]]); $pages = iterator_to_array(app(SnipeItClient::class)->hardwarePages()); expect($pages)->toHaveCount(2) ->and($pages[0]->offset)->toBe(0) ->and($pages[1]->offset)->toBe(2) ->and($pages[1]->rows[0]['id'])->toBe(3); Http::assertSentCount(2); Http::assertSent(function (Request $request): bool { parse_str((string) parse_url($request->url(), PHP_URL_QUERY), $query); return $request->hasHeader('Authorization', 'Bearer read-token-for-tests') && $request->hasHeader('Accept', 'application/json') && ($query['limit'] ?? null) === '2' && in_array($query['offset'] ?? null, ['0', '2'], true); }); }); it('repete falhas transitórias e recupera', function () { config()->set('services.snipe_it.retries', 2); Http::fakeSequence() ->push(['message' => 'temporarily unavailable'], 503) ->push(['total' => 1, 'rows' => [snipeClientRow(1)]]); $page = app(SnipeItClient::class)->listHardwarePage(); expect($page->total)->toBe(1); Http::assertSentCount(2); }); it('recusa erros transportados num HTTP 200', function () { Http::fake([ '*' => Http::response(['status' => 'error', 'messages' => 'Unauthorized'], 200), ]); expect(fn () => app(SnipeItClient::class)->listHardwarePage()) ->toThrow(SnipeItApiException::class, 'recusou a consulta'); }); /** @return array */ function snipeClientRow(int $id): array { return [ 'id' => $id, 'asset_tag' => "EQ-{$id}", 'name' => "Equipamento {$id}", ]; }