"method path" for every operation carrying a `company` header */ function companyHeaderOperations(array $document): array { $matches = []; foreach ($document['paths'] as $path => $operations) { foreach ($operations as $method => $operation) { if (! is_array($operation)) { continue; } foreach ($operation['parameters'] ?? [] as $parameter) { if (($parameter['name'] ?? null) === 'company' && ($parameter['in'] ?? null) === 'header') { $matches[] = "{$method} {$path}"; } } } } return $matches; } it('generates a valid OpenAPI document for the v1 API', function () { $document = openApiDocument(); expect($document['openapi'] ?? '')->toStartWith('3.') ->and($document['info']['title'])->toBe('InvoiceShelf API') ->and($document['info']['version'])->toBe(trim((string) file_get_contents(base_path('version.md')))) ->and($document['paths'])->not->toBeEmpty(); }); it('advertises bearer token authentication', function () { $document = openApiDocument(); $scheme = collect($document['components']['securitySchemes'] ?? []) ->firstWhere('scheme', 'bearer'); expect($scheme)->not->toBeNull() ->and($scheme['type'])->toBe('http'); }); it('adds the company header to company-scoped routes', function () { expect(companyHeaderOperations(openApiDocument()))->not->toBeEmpty(); }); it('does not add the company header to unauthenticated bootstrap routes', function () { $document = openApiDocument(); // /auth/login runs before any tenant is resolved, so it must not require the header. $loginOperations = $document['paths']['/auth/login'] ?? []; $hasCompanyHeader = false; foreach ($loginOperations as $operation) { if (! is_array($operation)) { continue; } foreach ($operation['parameters'] ?? [] as $parameter) { if (($parameter['name'] ?? null) === 'company') { $hasCompanyHeader = true; } } } expect($hasCompanyHeader)->toBeFalse(); });