UNPKG

@furystack/rest

Version:
665 lines 25.7 kB
import { describe, it, expectTypeOf } from 'vitest'; describe('ConvertOpenApiPath', () => { it('Should convert single {param} to :param', () => { expectTypeOf().toEqualTypeOf(); }); it('Should convert multiple params', () => { expectTypeOf().toEqualTypeOf(); }); it('Should pass through paths without params', () => { expectTypeOf().toEqualTypeOf(); }); it('Should handle root path', () => { expectTypeOf().toEqualTypeOf(); }); it('Should handle param at the end', () => { expectTypeOf().toEqualTypeOf(); }); it('Should handle adjacent segments with params', () => { expectTypeOf().toEqualTypeOf(); }); }); describe('JsonSchemaToType', () => { describe('Primitive types', () => { it('Should map string', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map number', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map integer to number', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map boolean', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map null', () => { expectTypeOf().toEqualTypeOf(); }); }); describe('String enums', () => { it('Should map string enum to union', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map single-value enum', () => { expectTypeOf().toEqualTypeOf(); }); }); describe('Arrays', () => { it('Should map string array', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map number array', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map nested object array', () => { expectTypeOf().toEqualTypeOf(); }); }); describe('Objects', () => { it('Should map object with all-optional properties', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map object with required properties', () => { expectTypeOf().toEqualTypeOf(); }); it('Should map object with all required properties', () => { expectTypeOf().toHaveProperty('name'); expectTypeOf().toEqualTypeOf(); expectTypeOf().toEqualTypeOf(); }); it('Should map object without properties to Record<string, unknown>', () => { expectTypeOf().toEqualTypeOf(); }); }); describe('Fallback', () => { it('Should return unknown for unrecognized schemas', () => { expectTypeOf().toEqualTypeOf(); }); it('Should return unknown for empty object', () => { expectTypeOf().toEqualTypeOf(); }); }); }); describe('OpenApiToRestApi', () => { describe('HTTP methods', () => { it('Should extract GET endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { get: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toExtend(); expectTypeOf().toHaveProperty('GET'); }); it('Should extract POST endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { post: { responses: { '201': { description: 'Created' } } } }, }, }; expectTypeOf().toHaveProperty('POST'); }); it('Should extract PUT endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items/{id}': { put: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toHaveProperty('PUT'); }); it('Should extract DELETE endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items/{id}': { delete: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toHaveProperty('DELETE'); }); it('Should extract PATCH endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items/{id}': { patch: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toHaveProperty('PATCH'); }); it('Should extract HEAD endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { head: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toHaveProperty('HEAD'); }); it('Should extract OPTIONS endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { options: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toHaveProperty('OPTIONS'); }); it('Should extract TRACE endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { trace: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toHaveProperty('TRACE'); }); it('Should handle multiple methods on the same path', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { get: { responses: { '200': { description: 'OK' } } }, post: { responses: { '201': { description: 'Created' } } }, }, }, }; expectTypeOf().toHaveProperty('GET'); expectTypeOf().toHaveProperty('POST'); }); it('Should only include methods that have endpoints', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { get: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().not.toHaveProperty('POST'); expectTypeOf().not.toHaveProperty('PUT'); expectTypeOf().not.toHaveProperty('DELETE'); expectTypeOf().not.toHaveProperty('PATCH'); }); }); describe('Response types', () => { it('Should extract typed 200 response', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users': { get: { responses: { '200': { description: 'OK', content: { 'application/json': { schema: { type: 'array', items: { type: 'string' } } } }, }, }, }, }, }, }; expectTypeOf().toExtend(); }); it('Should extract typed 201 response', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users': { post: { responses: { '201': { description: 'Created', content: { 'application/json': { schema: { type: 'object', properties: { id: { type: 'string' } } }, }, }, }, }, }, }, }, }; expectTypeOf().toEqualTypeOf(); }); it('Should return unknown for responses without schemas', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/health': { get: { responses: { '200': { description: 'OK' } } } }, }, }; expectTypeOf().toEqualTypeOf(); }); it('Should return unknown for non-JSON content types', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/file': { get: { responses: { '200': { description: 'OK', content: { 'application/octet-stream': { schema: { type: 'string' } } }, }, }, }, }, }, }; expectTypeOf().toEqualTypeOf(); }); }); describe('Path parameters', () => { it('Should extract single path parameter', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users/{id}': { get: { responses: { '200': { description: 'OK' } } }, }, }, }; expectTypeOf().toHaveProperty('id'); expectTypeOf().toBeString(); }); it('Should extract multiple path parameters', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users/{userId}/posts/{postId}': { get: { responses: { '200': { description: 'OK' } } }, }, }, }; expectTypeOf().toHaveProperty('userId'); expectTypeOf().toHaveProperty('postId'); expectTypeOf().toBeString(); expectTypeOf().toBeString(); }); it('Should not have url property for paths without params', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users': { get: { responses: { '200': { description: 'OK' } } }, }, }, }; expectTypeOf().not.toHaveProperty('url'); }); }); describe('Request body', () => { it('Should extract JSON request body', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users': { post: { requestBody: { content: { 'application/json': { schema: { type: 'object', properties: { name: { type: 'string' }, email: { type: 'string' } }, required: ['name', 'email'], }, }, }, }, responses: { '201': { description: 'Created' } }, }, }, }, }; expectTypeOf().toExtend(); }); it('Should not have body property when no request body', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { get: { responses: { '200': { description: 'OK' } } }, }, }, }; expectTypeOf().not.toHaveProperty('body'); }); }); describe('Query parameters', () => { it('Should extract typed query parameters', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/search': { get: { parameters: [ { name: 'q', in: 'query', schema: { type: 'string' } }, { name: 'limit', in: 'query', schema: { type: 'integer' } }, ], responses: { '200': { description: 'OK' } }, }, }, }, }; expectTypeOf().toEqualTypeOf(); }); it('Should default to string for query params without schema', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/search': { get: { parameters: [{ name: 'q', in: 'query' }], responses: { '200': { description: 'OK' } }, }, }, }, }; expectTypeOf().toEqualTypeOf(); }); it('Should not mix path params into query', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users/{id}': { get: { parameters: [ { name: 'id', in: 'path', required: true, schema: { type: 'string' } }, { name: 'fields', in: 'query', schema: { type: 'string' } }, ], responses: { '200': { description: 'OK' } }, }, }, }, }; expectTypeOf().toHaveProperty('fields'); expectTypeOf().toBeString(); expectTypeOf().toHaveProperty('id'); expectTypeOf().toBeString(); }); it('Should not have query property when no query parameters', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { get: { parameters: [{ name: 'id', in: 'path', required: true, schema: { type: 'string' } }], responses: { '200': { description: 'OK' } }, }, }, }, }; expectTypeOf().not.toHaveProperty('query'); }); }); describe('Edge cases', () => { it('Should handle document with no paths', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, }; expectTypeOf().toExtend(); }); it('Should handle document with empty paths', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: {}, }; expectTypeOf().toExtend(); }); it('Should handle multiple paths', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/a': { get: { responses: { '200': { description: 'OK' } } } }, '/b': { get: { responses: { '200': { description: 'OK' } } } }, '/c': { post: { responses: { '201': { description: 'Created' } } } }, }, }; expectTypeOf().toHaveProperty('/a'); expectTypeOf().toHaveProperty('/b'); expectTypeOf().toHaveProperty('/c'); }); }); describe('$ref resolution', () => { it('Should resolve $ref in response schema', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users': { get: { responses: { '200': { description: 'OK', content: { 'application/json': { schema: { $ref: '#/components/schemas/User' } }, }, }, }, }, }, }, components: { schemas: { User: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' } }, }, }, }, }; expectTypeOf().toHaveProperty('id'); expectTypeOf().toHaveProperty('name'); }); it('Should resolve $ref in request body schema', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/users': { post: { requestBody: { content: { 'application/json': { schema: { $ref: '#/components/schemas/CreateUser' } }, }, }, responses: { '201': { description: 'Created' } }, }, }, }, components: { schemas: { CreateUser: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'], }, }, }, }; expectTypeOf().toHaveProperty('name'); }); }); describe('Schema composition', () => { it('Should handle oneOf as union type', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/shape': { get: { responses: { '200': { description: 'OK', content: { 'application/json': { schema: { oneOf: [ { type: 'object', properties: { radius: { type: 'number' } } }, { type: 'object', properties: { width: { type: 'number' } } }, ], }, }, }, }, }, }, }, }, }; expectTypeOf().toExtend(); expectTypeOf().toExtend(); }); it('Should handle allOf as intersection type', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/item': { get: { responses: { '200': { description: 'OK', content: { 'application/json': { schema: { allOf: [ { type: 'object', properties: { id: { type: 'string' } } }, { type: 'object', properties: { name: { type: 'string' } } }, ], }, }, }, }, }, }, }, }, }; expectTypeOf().toHaveProperty('id'); expectTypeOf().toHaveProperty('name'); }); it('Should handle const values', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/status': { get: { responses: { '200': { description: 'OK', content: { 'application/json': { schema: { const: 'active' } }, }, }, }, }, }, }, }; expectTypeOf().toEqualTypeOf(); }); it('Should handle nullable types (3.1 tuple style)', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/item': { get: { responses: { '200': { description: 'OK', content: { 'application/json': { schema: { type: ['string', 'null'] }, }, }, }, }, }, }, }, }; expectTypeOf().toEqualTypeOf(); }); }); describe('Metadata extraction', () => { it('Should extract tags at type level', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { get: { tags: ['store'], responses: { '200': { description: 'OK' } }, }, }, }, }; expectTypeOf().toHaveProperty('tags'); }); it('Should extract deprecated flag at type level', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/old': { get: { deprecated: true, responses: { '200': { description: 'OK' } }, }, }, }, }; expectTypeOf().toHaveProperty('deprecated'); }); it('Should extract summary and description at type level', () => { const doc = { openapi: '3.1.0', info: { title: 'Test', version: '1.0.0' }, paths: { '/items': { get: { summary: 'List items', description: 'Returns all items', responses: { '200': { description: 'OK' } }, }, }, }, }; expectTypeOf().toHaveProperty('summary'); expectTypeOf().toHaveProperty('description'); }); }); }); //# sourceMappingURL=openapi-to-rest-api.spec.js.map