@furystack/rest
Version:
Generic REST package
665 lines • 25.7 kB
JavaScript
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