mirror of
https://github.com/LukeHagar/prettier-plugin-openapi.git
synced 2025-12-06 04:21:03 +00:00
Add ESLint and Prettier configuration files, update .gitignore and .npmignore, and enhance CI/CD workflows with testing and release automation
This commit is contained in:
519
test/integration.test.ts
Normal file
519
test/integration.test.ts
Normal file
@@ -0,0 +1,519 @@
|
||||
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 jsonPrinter = plugin.printers?.['openapi-json-ast'];
|
||||
expect(jsonPrinter).toBeDefined();
|
||||
|
||||
const testData = {
|
||||
content: openApiContent
|
||||
};
|
||||
|
||||
// @ts-ignore We are mocking things here
|
||||
const result = jsonPrinter?.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 jsonPrinter = plugin.printers?.['openapi-json-ast'];
|
||||
expect(jsonPrinter).toBeDefined();
|
||||
|
||||
const testData = {
|
||||
content: swaggerContent
|
||||
};
|
||||
|
||||
// @ts-ignore We are mocking things here
|
||||
const result = jsonPrinter?.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 yamlPrinter = plugin.printers?.['openapi-yaml-ast'];
|
||||
expect(yamlPrinter).toBeDefined();
|
||||
|
||||
const testData = {
|
||||
content: yamlContent
|
||||
};
|
||||
|
||||
// @ts-ignore We are mocking things here
|
||||
const result = yamlPrinter?.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 jsonParser = plugin.parsers?.['openapi-json-parser'];
|
||||
expect(jsonParser).toBeDefined();
|
||||
|
||||
const malformedJson = '{"openapi": "3.0.0", "info": {';
|
||||
|
||||
// @ts-ignore We are mocking things here
|
||||
expect(() => jsonParser?.parse(malformedJson, {})).toThrow();
|
||||
});
|
||||
|
||||
it('should handle malformed YAML gracefully', () => {
|
||||
const yamlParser = plugin.parsers?.['openapi-yaml-parser'];
|
||||
expect(yamlParser).toBeDefined();
|
||||
|
||||
const malformedYaml = 'openapi: 3.0.0\ninfo:\n title: Test\n version: 1.0.0\n invalid: [';
|
||||
|
||||
// @ts-ignore We are mocking things here
|
||||
expect(() => yamlParser?.parse(malformedYaml, {})).toThrow();
|
||||
});
|
||||
|
||||
it('should reject non-OpenAPI content', () => {
|
||||
const jsonParser = plugin.parsers?.['openapi-json-parser'];
|
||||
expect(jsonParser).toBeDefined();
|
||||
|
||||
const nonOpenAPI = '{"name": "John", "age": 30}';
|
||||
|
||||
// @ts-ignore We are mocking things here
|
||||
expect(() => jsonParser?.parse(nonOpenAPI, {})).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 jsonPrinter = plugin.printers?.['openapi-json-ast'];
|
||||
expect(jsonPrinter).toBeDefined();
|
||||
|
||||
const testData = {
|
||||
content: largeOpenAPI
|
||||
};
|
||||
|
||||
const startTime = Date.now();
|
||||
|
||||
// @ts-ignore We are mocking things here
|
||||
const result = jsonPrinter?.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
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user