mirror of
https://github.com/LukeHagar/prettier-plugin-openapi.git
synced 2025-12-06 04:21:03 +00:00
532 lines
15 KiB
TypeScript
532 lines
15 KiB
TypeScript
import { describe, expect, it } from 'bun:test';
|
|
import plugin from '../src/index';
|
|
|
|
describe('Integration Tests', () => {
|
|
describe('Real OpenAPI file processing', () => {
|
|
it('should process a complete OpenAPI 3.0 file', () => {
|
|
const openApiContent = {
|
|
openapi: '3.0.0',
|
|
info: {
|
|
title: 'Test API',
|
|
version: '1.0.0',
|
|
description: 'A test API',
|
|
contact: {
|
|
name: 'API Support',
|
|
email: 'support@example.com'
|
|
},
|
|
license: {
|
|
name: 'MIT',
|
|
url: 'https://opensource.org/licenses/MIT'
|
|
}
|
|
},
|
|
servers: [
|
|
{
|
|
url: 'https://api.example.com/v1',
|
|
description: 'Production server'
|
|
}
|
|
],
|
|
paths: {
|
|
'/users': {
|
|
get: {
|
|
summary: 'Get users',
|
|
description: 'Retrieve all users',
|
|
operationId: 'getUsers',
|
|
tags: ['users'],
|
|
parameters: [
|
|
{
|
|
name: 'limit',
|
|
in: 'query',
|
|
description: 'Number of users to return',
|
|
required: false,
|
|
schema: {
|
|
type: 'integer',
|
|
minimum: 1,
|
|
maximum: 100,
|
|
default: 10
|
|
}
|
|
}
|
|
],
|
|
responses: {
|
|
'200': {
|
|
description: 'Successful response',
|
|
content: {
|
|
'application/json': {
|
|
schema: {
|
|
type: 'array',
|
|
items: {
|
|
$ref: '#/components/schemas/User'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'400': {
|
|
description: 'Bad request',
|
|
content: {
|
|
'application/json': {
|
|
schema: {
|
|
$ref: '#/components/schemas/Error'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
post: {
|
|
summary: 'Create user',
|
|
description: 'Create a new user',
|
|
operationId: 'createUser',
|
|
tags: ['users'],
|
|
requestBody: {
|
|
required: true,
|
|
content: {
|
|
'application/json': {
|
|
schema: {
|
|
$ref: '#/components/schemas/UserCreate'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
responses: {
|
|
'201': {
|
|
description: 'User created',
|
|
content: {
|
|
'application/json': {
|
|
schema: {
|
|
$ref: '#/components/schemas/User'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'/users/{id}': {
|
|
get: {
|
|
summary: 'Get user by ID',
|
|
operationId: 'getUserById',
|
|
tags: ['users'],
|
|
parameters: [
|
|
{
|
|
name: 'id',
|
|
in: 'path',
|
|
required: true,
|
|
description: 'User ID',
|
|
schema: {
|
|
type: 'integer',
|
|
format: 'int64'
|
|
}
|
|
}
|
|
],
|
|
responses: {
|
|
'200': {
|
|
description: 'User found',
|
|
content: {
|
|
'application/json': {
|
|
schema: {
|
|
$ref: '#/components/schemas/User'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'404': {
|
|
description: 'User not found',
|
|
content: {
|
|
'application/json': {
|
|
schema: {
|
|
$ref: '#/components/schemas/Error'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
components: {
|
|
schemas: {
|
|
User: {
|
|
type: 'object',
|
|
required: ['id', 'name', 'email'],
|
|
properties: {
|
|
id: {
|
|
type: 'integer',
|
|
format: 'int64',
|
|
description: 'User ID'
|
|
},
|
|
name: {
|
|
type: 'string',
|
|
description: 'User name',
|
|
minLength: 1,
|
|
maxLength: 100
|
|
},
|
|
email: {
|
|
type: 'string',
|
|
format: 'email',
|
|
description: 'User email'
|
|
},
|
|
createdAt: {
|
|
type: 'string',
|
|
format: 'date-time',
|
|
description: 'Creation timestamp'
|
|
}
|
|
}
|
|
},
|
|
UserCreate: {
|
|
type: 'object',
|
|
required: ['name', 'email'],
|
|
properties: {
|
|
name: {
|
|
type: 'string',
|
|
description: 'User name',
|
|
minLength: 1,
|
|
maxLength: 100
|
|
},
|
|
email: {
|
|
type: 'string',
|
|
format: 'email',
|
|
description: 'User email'
|
|
}
|
|
}
|
|
},
|
|
Error: {
|
|
type: 'object',
|
|
required: ['code', 'message'],
|
|
properties: {
|
|
code: {
|
|
type: 'string',
|
|
description: 'Error code'
|
|
},
|
|
message: {
|
|
type: 'string',
|
|
description: 'Error message'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
tags: [
|
|
{
|
|
name: 'users',
|
|
description: 'User management operations'
|
|
}
|
|
]
|
|
};
|
|
|
|
const printer = plugin.printers?.['openapi-ast'];
|
|
expect(printer).toBeDefined();
|
|
|
|
const testData = {
|
|
type: 'openapi',
|
|
content: openApiContent,
|
|
originalText: '',
|
|
format: 'json'
|
|
};
|
|
|
|
// @ts-expect-error We are mocking things here
|
|
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
|
|
expect(result).toBeDefined();
|
|
|
|
if (result && typeof result === 'string') {
|
|
const formatted = JSON.parse(result);
|
|
|
|
// Verify key ordering
|
|
const keys = Object.keys(formatted);
|
|
expect(keys[0]).toBe('openapi');
|
|
expect(keys[1]).toBe('info');
|
|
expect(keys[2]).toBe('servers');
|
|
expect(keys[3]).toBe('tags');
|
|
expect(keys[4]).toBe('paths');
|
|
expect(keys[5]).toBe('components');
|
|
|
|
// Verify nested key ordering
|
|
const infoKeys = Object.keys(formatted.info);
|
|
expect(infoKeys[0]).toBe('title');
|
|
expect(infoKeys[1]).toBe('version');
|
|
expect(infoKeys[2]).toBe('description');
|
|
expect(infoKeys[3]).toBe('contact');
|
|
expect(infoKeys[4]).toBe('license');
|
|
|
|
// Verify components key ordering
|
|
const componentKeys = Object.keys(formatted.components);
|
|
expect(componentKeys[0]).toBe('schemas');
|
|
|
|
// Verify schema key ordering (alphabetical)
|
|
const schemaKeys = Object.keys(formatted.components.schemas);
|
|
expect(schemaKeys[0]).toBe('Error');
|
|
expect(schemaKeys[1]).toBe('User');
|
|
expect(schemaKeys[2]).toBe('UserCreate');
|
|
}
|
|
});
|
|
|
|
it('should process a Swagger 2.0 file', () => {
|
|
const swaggerContent = {
|
|
swagger: '2.0',
|
|
info: {
|
|
title: 'Test API',
|
|
version: '1.0.0',
|
|
description: 'A test API',
|
|
contact: {
|
|
name: 'API Support',
|
|
email: 'support@example.com'
|
|
},
|
|
license: {
|
|
name: 'MIT',
|
|
url: 'https://opensource.org/licenses/MIT'
|
|
}
|
|
},
|
|
host: 'api.example.com',
|
|
basePath: '/v1',
|
|
schemes: ['https'],
|
|
consumes: ['application/json'],
|
|
produces: ['application/json'],
|
|
paths: {
|
|
'/users': {
|
|
get: {
|
|
summary: 'Get users',
|
|
description: 'Retrieve all users',
|
|
operationId: 'getUsers',
|
|
tags: ['users'],
|
|
parameters: [
|
|
{
|
|
name: 'limit',
|
|
in: 'query',
|
|
description: 'Number of users to return',
|
|
required: false,
|
|
type: 'integer',
|
|
minimum: 1,
|
|
maximum: 100,
|
|
default: 10
|
|
}
|
|
],
|
|
responses: {
|
|
'200': {
|
|
description: 'Successful response',
|
|
schema: {
|
|
type: 'array',
|
|
items: {
|
|
$ref: '#/definitions/User'
|
|
}
|
|
}
|
|
},
|
|
'400': {
|
|
description: 'Bad request',
|
|
schema: {
|
|
$ref: '#/definitions/Error'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
definitions: {
|
|
User: {
|
|
type: 'object',
|
|
required: ['id', 'name', 'email'],
|
|
properties: {
|
|
id: {
|
|
type: 'integer',
|
|
format: 'int64',
|
|
description: 'User ID'
|
|
},
|
|
name: {
|
|
type: 'string',
|
|
description: 'User name',
|
|
minLength: 1,
|
|
maxLength: 100
|
|
},
|
|
email: {
|
|
type: 'string',
|
|
format: 'email',
|
|
description: 'User email'
|
|
}
|
|
}
|
|
},
|
|
Error: {
|
|
type: 'object',
|
|
required: ['code', 'message'],
|
|
properties: {
|
|
code: {
|
|
type: 'string',
|
|
description: 'Error code'
|
|
},
|
|
message: {
|
|
type: 'string',
|
|
description: 'Error message'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
tags: [
|
|
{
|
|
name: 'users',
|
|
description: 'User management operations'
|
|
}
|
|
]
|
|
};
|
|
|
|
const printer = plugin.printers?.['openapi-ast'];
|
|
expect(printer).toBeDefined();
|
|
|
|
const testData = {
|
|
type: 'openapi',
|
|
content: swaggerContent,
|
|
originalText: '',
|
|
format: 'json'
|
|
};
|
|
|
|
// @ts-expect-error We are mocking things here
|
|
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
|
|
expect(result).toBeDefined();
|
|
|
|
if (result && typeof result === 'string') {
|
|
const formatted = JSON.parse(result);
|
|
|
|
// Verify Swagger 2.0 key ordering
|
|
const keys = Object.keys(formatted);
|
|
expect(keys[0]).toBe('swagger');
|
|
expect(keys[1]).toBe('info');
|
|
expect(keys[2]).toBe('schemes');
|
|
expect(keys[3]).toBe('host');
|
|
expect(keys[4]).toBe('basePath');
|
|
expect(keys[5]).toBe('consumes');
|
|
expect(keys[6]).toBe('produces');
|
|
expect(keys[7]).toBe('tags');
|
|
expect(keys[8]).toBe('paths');
|
|
expect(keys[9]).toBe('definitions');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('YAML formatting', () => {
|
|
it('should format YAML with proper structure', () => {
|
|
const yamlContent = {
|
|
openapi: '3.0.0',
|
|
info: {
|
|
title: 'Test API',
|
|
version: '1.0.0'
|
|
},
|
|
paths: {
|
|
'/test': {
|
|
get: {
|
|
responses: {
|
|
'200': {
|
|
description: 'Success'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
const printer = plugin.printers?.['openapi-ast'];
|
|
expect(printer).toBeDefined();
|
|
|
|
const testData = {
|
|
type: 'openapi',
|
|
content: yamlContent,
|
|
originalText: '',
|
|
format: 'yaml'
|
|
};
|
|
|
|
// @ts-expect-error We are mocking things here
|
|
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
|
|
expect(result).toBeDefined();
|
|
|
|
if (result) {
|
|
// Verify YAML structure
|
|
expect(result).toContain('openapi:');
|
|
expect(result).toContain('info:');
|
|
expect(result).toContain('paths:');
|
|
expect(result).toContain('title:');
|
|
expect(result).toContain('version:');
|
|
expect(result).toContain('get:');
|
|
expect(result).toContain('responses:');
|
|
expect(result).toContain('"200":');
|
|
expect(result).toContain('description:');
|
|
expect(result).toContain('Success');
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('Error handling', () => {
|
|
it('should handle malformed JSON gracefully', () => {
|
|
const parser = plugin.parsers?.['openapi-parser'];
|
|
expect(parser).toBeDefined();
|
|
|
|
const malformedJson = '{"openapi": "3.0.0", "info": {';
|
|
|
|
// @ts-expect-error We are mocking things here
|
|
expect(() => parser?.parse(malformedJson, { filepath: 'test.json' })).toThrow();
|
|
});
|
|
|
|
it('should handle malformed YAML gracefully', () => {
|
|
const parser = plugin.parsers?.['openapi-parser'];
|
|
expect(parser).toBeDefined();
|
|
|
|
const malformedYaml = 'openapi: 3.0.0\ninfo:\n title: Test\n version: 1.0.0\n invalid: [';
|
|
|
|
// @ts-expect-error We are mocking things here
|
|
expect(() => parser?.parse(malformedYaml, { filepath: 'test.yaml' })).toThrow();
|
|
});
|
|
|
|
it('should reject non-OpenAPI content', () => {
|
|
const parser = plugin.parsers?.['openapi-parser'];
|
|
expect(parser).toBeDefined();
|
|
|
|
const nonOpenAPI = '{"name": "John", "age": 30}';
|
|
|
|
// @ts-expect-error We are mocking things here
|
|
expect(() => parser?.parse(nonOpenAPI, { filepath: 'test.json' })).toThrow('Not an OpenAPI file');
|
|
});
|
|
});
|
|
|
|
describe('Performance tests', () => {
|
|
it('should handle large OpenAPI files efficiently', () => {
|
|
const largeOpenAPI = {
|
|
openapi: '3.0.0',
|
|
info: {
|
|
title: 'Large API',
|
|
version: '1.0.0'
|
|
},
|
|
paths: {}
|
|
};
|
|
|
|
// Create a large paths object
|
|
for (let i = 0; i < 100; i++) {
|
|
largeOpenAPI.paths[`/path${i}`] = {
|
|
get: {
|
|
summary: `Get path ${i}`,
|
|
responses: {
|
|
'200': {
|
|
description: 'Success'
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
const printer = plugin.printers?.['openapi-ast'];
|
|
expect(printer).toBeDefined();
|
|
|
|
const testData = {
|
|
type: 'openapi',
|
|
content: largeOpenAPI,
|
|
originalText: '',
|
|
format: 'json'
|
|
};
|
|
|
|
const startTime = Date.now();
|
|
|
|
// @ts-expect-error We are mocking things here
|
|
const result = printer?.print({ getValue: () => testData }, { tabWidth: 2 }, () => '');
|
|
|
|
const endTime = Date.now();
|
|
const duration = endTime - startTime;
|
|
|
|
expect(result).toBeDefined();
|
|
expect(duration).toBeLessThan(1000); // Should complete within 1 second
|
|
});
|
|
});
|
|
});
|