mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-02 17:08:32 +00:00
fix: tags validation error for openapi import for BRU and YAML compatibility (#7294)
* fix: tags schema updatd to array of string * tests: added test cases for sanitizing tags, openapi-tags * fix: enhance tag sanitization to support object input and UTF characters --------- Co-authored-by: shubh-bruno <shubh-bruno@shubh-bruno.local>
This commit is contained in:
@@ -42,6 +42,68 @@ export const uuid = () => {
|
||||
return customNanoId();
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes a tag name for BRU format compatibility.
|
||||
* BRU format only supports tag names containing alphanumeric characters,
|
||||
* hyphens (-), and underscores (_). Spaces are replaced with underscores.
|
||||
*
|
||||
* @param {string} tag - The tag to sanitize
|
||||
* @param {Object} options - Sanitization options
|
||||
* @param {string} options.collectionFormat - The collection format ('yml' for OpenCollection YAML)
|
||||
* @returns {string|null} - The sanitized tag, or null if the result is empty
|
||||
*/
|
||||
export const sanitizeTag = (tag, options = {}) => {
|
||||
const typeofTag = typeof tag;
|
||||
if (!tag || !['string', 'object'].includes(typeofTag)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let usableTagString = typeof tag == 'string' ? tag : 'name' in tag ? tag.name : '';
|
||||
|
||||
let sanitized = usableTagString.trim();
|
||||
|
||||
// BRU format only supports alphanumeric, hyphens, and underscores in tags
|
||||
// The BRU grammar defines listitem as: (alnum | "_" | "-")+
|
||||
// Spaces are NOT allowed, so we replace them with underscores
|
||||
|
||||
// Replace spaces with underscores first
|
||||
sanitized = sanitized.replace(/\s+/g, '_');
|
||||
|
||||
// Replace any character that's NOT alphanumeric, hyphen, or underscore with underscore
|
||||
sanitized = sanitized.replace(/[^\p{L}\p{N}\-_]/gu, '_');
|
||||
|
||||
// Collapse multiple consecutive underscores into one
|
||||
sanitized = sanitized.replace(/_+/g, '_');
|
||||
|
||||
// Remove leading characters that aren't alphanumeric
|
||||
sanitized = sanitized.replace(/^[^\p{L}\p{N}]+/gu, '');
|
||||
|
||||
// Remove trailing characters that aren't alphanumeric
|
||||
sanitized = sanitized.replace(/[^\p{L}\p{N}]+$/gu, '');
|
||||
|
||||
// Return null if the result is empty
|
||||
return sanitized || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sanitizes an array of tags, removing duplicates and null values.
|
||||
*
|
||||
* @param {string[]} tags - Array of tags to sanitize
|
||||
* @param {Object} options - Sanitization options
|
||||
* @returns {string[]} - Array of unique sanitized tags
|
||||
*/
|
||||
export const sanitizeTags = (tags, options = {}) => {
|
||||
if (!Array.isArray(tags)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [...new Set(
|
||||
tags
|
||||
.map((tag) => sanitizeTag(tag, options))
|
||||
.filter((tag) => tag !== null)
|
||||
)];
|
||||
};
|
||||
|
||||
export const validateSchema = (collection = {}) => {
|
||||
try {
|
||||
collectionSchema.validateSync(collection);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
import jsyaml from 'js-yaml';
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid } from '../common';
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid, sanitizeTag, sanitizeTags } from '../common';
|
||||
|
||||
// Content type patterns for matching MIME type variants
|
||||
// These patterns handle structured types with many variants (e.g., application/ld+json, application/vnd.api+json)
|
||||
@@ -533,15 +533,7 @@ const transformOpenapiRequestItem = (request, usedNames = new Set(), options = {
|
||||
uid: uuid(),
|
||||
name: operationName,
|
||||
type: 'http-request',
|
||||
tags: [...new Set(
|
||||
(request.operationObject.tags || []).map((tag) => {
|
||||
let sanitized = tag.trim();
|
||||
if (options.collectionFormat !== 'yml') {
|
||||
sanitized = sanitized.replace(/\s+/g, '_');
|
||||
}
|
||||
return sanitized;
|
||||
}).filter((tag) => tag.trim())
|
||||
)],
|
||||
tags: sanitizeTags(request.operationObject.tags || [], options),
|
||||
request: {
|
||||
docs: _operationObject.description,
|
||||
url: ensureUrl(request.global.server + path),
|
||||
@@ -1032,13 +1024,13 @@ const resolveRefs = (spec, components = spec?.components, cache = new Map()) =>
|
||||
return resolved;
|
||||
};
|
||||
|
||||
const groupRequestsByTags = (requests) => {
|
||||
const groupRequestsByTags = (requests, options = {}) => {
|
||||
let _groups = {};
|
||||
let ungrouped = [];
|
||||
each(requests, (request) => {
|
||||
let tags = request.operationObject.tags || [];
|
||||
if (tags.length > 0) {
|
||||
let tag = tags[0].trim(); // take first tag and trim whitespace
|
||||
let tag = sanitizeTag(tags[0].trim()); // take first tag, trim whitespace, and sanitize
|
||||
|
||||
if (tag) {
|
||||
if (!_groups[tag]) {
|
||||
@@ -1274,7 +1266,7 @@ export const parseOpenApiCollection = (data, options = {}) => {
|
||||
brunoCollection.items = groupRequestsByPath(allRequests, options);
|
||||
} else {
|
||||
// Default tag-based grouping
|
||||
let [groups, ungroupedRequests] = groupRequestsByTags(allRequests);
|
||||
let [groups, ungroupedRequests] = groupRequestsByTags(allRequests, options);
|
||||
let brunoFolders = groups.map((group) => {
|
||||
return {
|
||||
uid: uuid(),
|
||||
|
||||
181
packages/bruno-converters/tests/common/sanitizeTag.spec.js
Normal file
181
packages/bruno-converters/tests/common/sanitizeTag.spec.js
Normal file
@@ -0,0 +1,181 @@
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import { sanitizeTag, sanitizeTags } from '../../src/common/index.js';
|
||||
|
||||
describe('sanitizeTag', () => {
|
||||
describe('basic functionality', () => {
|
||||
it('should return null for null input', () => {
|
||||
expect(sanitizeTag(null)).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null for undefined input', () => {
|
||||
expect(sanitizeTag(undefined)).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null for non-string input', () => {
|
||||
expect(sanitizeTag(123)).toBeNull();
|
||||
expect(sanitizeTag({})).toBeNull();
|
||||
expect(sanitizeTag([])).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null for empty string', () => {
|
||||
expect(sanitizeTag('')).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null for whitespace-only string', () => {
|
||||
expect(sanitizeTag(' ')).toBeNull();
|
||||
expect(sanitizeTag('\t\n')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('valid tags', () => {
|
||||
it('should preserve alphanumeric tags', () => {
|
||||
expect(sanitizeTag('valid')).toBe('valid');
|
||||
expect(sanitizeTag('ValidTag')).toBe('ValidTag');
|
||||
expect(sanitizeTag('tag123')).toBe('tag123');
|
||||
});
|
||||
|
||||
it('should preserve tags with hyphens', () => {
|
||||
expect(sanitizeTag('valid-tag')).toBe('valid-tag');
|
||||
expect(sanitizeTag('my-api-endpoint')).toBe('my-api-endpoint');
|
||||
});
|
||||
|
||||
it('should preserve tags with underscores', () => {
|
||||
expect(sanitizeTag('valid_tag')).toBe('valid_tag');
|
||||
expect(sanitizeTag('my_api_endpoint')).toBe('my_api_endpoint');
|
||||
});
|
||||
|
||||
it('should replace spaces with underscores', () => {
|
||||
expect(sanitizeTag('User Management')).toBe('User_Management');
|
||||
expect(sanitizeTag('API v1')).toBe('API_v1');
|
||||
});
|
||||
|
||||
it('should preserve tags with mixed valid characters (spaces become underscores)', () => {
|
||||
expect(sanitizeTag('valid-tag_name')).toBe('valid-tag_name');
|
||||
expect(sanitizeTag('API v1-endpoint')).toBe('API_v1-endpoint');
|
||||
expect(sanitizeTag('User Management API')).toBe('User_Management_API');
|
||||
});
|
||||
});
|
||||
|
||||
describe('space handling', () => {
|
||||
it('should replace spaces with underscores in the middle of tags', () => {
|
||||
expect(sanitizeTag('User Management')).toBe('User_Management');
|
||||
expect(sanitizeTag('API v1')).toBe('API_v1');
|
||||
});
|
||||
|
||||
it('should collapse multiple spaces into a single underscore', () => {
|
||||
expect(sanitizeTag('User Management')).toBe('User_Management');
|
||||
expect(sanitizeTag('API v1')).toBe('API_v1');
|
||||
});
|
||||
|
||||
it('should trim leading and trailing spaces', () => {
|
||||
expect(sanitizeTag(' tag ')).toBe('tag');
|
||||
expect(sanitizeTag('\ttag\n')).toBe('tag');
|
||||
});
|
||||
|
||||
it('should remove leading/trailing spaces and replace internal spaces with underscores', () => {
|
||||
expect(sanitizeTag(' User Management ')).toBe('User_Management');
|
||||
});
|
||||
});
|
||||
|
||||
describe('special character handling', () => {
|
||||
it('should replace dots with underscores', () => {
|
||||
expect(sanitizeTag('api.v1')).toBe('api_v1');
|
||||
expect(sanitizeTag('api.v1.0')).toBe('api_v1_0');
|
||||
});
|
||||
|
||||
it('should replace colons with underscores', () => {
|
||||
expect(sanitizeTag('api:v1')).toBe('api_v1');
|
||||
});
|
||||
|
||||
it('should replace slashes with underscores', () => {
|
||||
expect(sanitizeTag('api/v1')).toBe('api_v1');
|
||||
expect(sanitizeTag('api/v1/users')).toBe('api_v1_users');
|
||||
});
|
||||
|
||||
it('should replace parentheses with underscores', () => {
|
||||
// 'API (v1)' has space before parenthesis, both become underscores
|
||||
expect(sanitizeTag('API (v1)')).toBe('API_v1');
|
||||
// 'API(v1)' has no space, so it becomes 'API_v1'
|
||||
expect(sanitizeTag('API(v1)')).toBe('API_v1');
|
||||
});
|
||||
|
||||
it('should replace multiple special characters', () => {
|
||||
// 'API v1.0 (beta)' - spaces, dots, parentheses all become underscores
|
||||
// Result: 'API_v1_0_beta' (collapsed to single underscores)
|
||||
expect(sanitizeTag('API v1.0 (beta)')).toBe('API_v1_0_beta');
|
||||
expect(sanitizeTag('api.v1:beta')).toBe('api_v1_beta');
|
||||
});
|
||||
|
||||
it('should handle special characters at start and end', () => {
|
||||
expect(sanitizeTag('.api')).toBe('api');
|
||||
expect(sanitizeTag('api.')).toBe('api');
|
||||
expect(sanitizeTag('-api')).toBe('api');
|
||||
expect(sanitizeTag('api-')).toBe('api');
|
||||
expect(sanitizeTag('_api')).toBe('api');
|
||||
expect(sanitizeTag('api_')).toBe('api');
|
||||
expect(sanitizeTag(' api')).toBe('api');
|
||||
expect(sanitizeTag('api ')).toBe('api');
|
||||
});
|
||||
|
||||
it('should return null when result is only special characters', () => {
|
||||
expect(sanitizeTag('...')).toBeNull();
|
||||
expect(sanitizeTag('---')).toBeNull();
|
||||
expect(sanitizeTag('___')).toBeNull();
|
||||
expect(sanitizeTag('.-_')).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('options handling', () => {
|
||||
it('should ignore collectionFormat option and always sanitize', () => {
|
||||
// The collectionFormat option is no longer used - always sanitize
|
||||
// Spaces are replaced with underscores for BRU format compatibility
|
||||
expect(sanitizeTag('User Management', { collectionFormat: 'yml' })).toBe('User_Management');
|
||||
expect(sanitizeTag('api.v1', { collectionFormat: 'yml' })).toBe('api_v1');
|
||||
// 'API (v1)' becomes 'API_v1' (space and parentheses become underscores)
|
||||
expect(sanitizeTag('API (v1)', { collectionFormat: 'yml' })).toBe('API_v1');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('sanitizeTags', () => {
|
||||
it('should return empty array for null input', () => {
|
||||
expect(sanitizeTags(null)).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return empty array for undefined input', () => {
|
||||
expect(sanitizeTags(undefined)).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return empty array for non-array input', () => {
|
||||
expect(sanitizeTags('string')).toEqual([]);
|
||||
expect(sanitizeTags(123)).toEqual([]);
|
||||
expect(sanitizeTags({})).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return empty array for empty array input', () => {
|
||||
expect(sanitizeTags([])).toEqual([]);
|
||||
});
|
||||
|
||||
it('should sanitize all tags in array', () => {
|
||||
// Spaces are replaced with underscores
|
||||
expect(sanitizeTags(['User Management', 'API v1'])).toEqual(['User_Management', 'API_v1']);
|
||||
});
|
||||
|
||||
it('should remove null values from result', () => {
|
||||
expect(sanitizeTags(['valid', '...', 'also-valid'])).toEqual(['valid', 'also-valid']);
|
||||
});
|
||||
|
||||
it('should remove duplicates from result', () => {
|
||||
expect(sanitizeTags(['User Management', 'User Management'])).toEqual(['User_Management']);
|
||||
expect(sanitizeTags(['api.v1', 'api_v1'])).toEqual(['api_v1']);
|
||||
});
|
||||
|
||||
it('should preserve order of first occurrence', () => {
|
||||
expect(sanitizeTags(['tag1', 'tag2', 'tag1'])).toEqual(['tag1', 'tag2']);
|
||||
});
|
||||
|
||||
it('should handle mixed valid and invalid tags', () => {
|
||||
// Spaces are replaced with underscores
|
||||
expect(sanitizeTags(['valid-tag', 'invalid.tag', 'another valid'])).toEqual(['valid-tag', 'invalid_tag', 'another_valid']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,395 @@
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import openApiToBruno from '../../../src/openapi/openapi-to-bruno';
|
||||
|
||||
/**
|
||||
* Helper function to find a request by name in the collection.
|
||||
* Searches recursively through folders since requests with tags
|
||||
* are grouped into folders.
|
||||
*/
|
||||
const findRequestByName = (items, name) => {
|
||||
for (const item of items) {
|
||||
if (item.type === 'http-request' && item.name === name) {
|
||||
return item;
|
||||
}
|
||||
if (item.type === 'folder' && item.items) {
|
||||
const found = findRequestByName(item.items, name);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function to find a folder by name in the collection.
|
||||
*/
|
||||
const findFolderByName = (items, name) => {
|
||||
for (const item of items) {
|
||||
if (item.type === 'folder' && item.name === name) {
|
||||
return item;
|
||||
}
|
||||
if (item.type === 'folder' && item.items) {
|
||||
const found = findFolderByName(item.items, name);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
describe('OpenAPI Import - Tag Sanitization', () => {
|
||||
it('should replace spaces with underscores in tags', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['User Management'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
// Spaces are replaced with underscores for BRU format compatibility
|
||||
expect(request.tags).toEqual(['User_Management']);
|
||||
});
|
||||
|
||||
it('should sanitize tags with dots', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['api.v1', 'user.service'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
// Dots should be replaced with underscores
|
||||
expect(request.tags).toEqual(['api_v1', 'user_service']);
|
||||
});
|
||||
|
||||
it('should sanitize tags with special characters', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['API (v1)', 'user-service:v2'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
// Parentheses, colons, and spaces should be replaced with underscores
|
||||
// 'API (v1)' becomes 'API_v1' (space and parentheses become underscores, collapsed)
|
||||
expect(request.tags).toEqual(['API_v1', 'user-service_v2']);
|
||||
});
|
||||
|
||||
it('should preserve valid tags', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['users', 'api-v1', 'user_service'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
expect(request.tags).toEqual(['users', 'api-v1', 'user_service']);
|
||||
});
|
||||
|
||||
it('should handle empty tags array', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: [],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
expect(request.tags).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle missing tags property', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
expect(request.tags).toEqual([]);
|
||||
});
|
||||
|
||||
it('should remove duplicate tags after sanitization', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['User Management', 'User Management', 'user-management'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
// 'User Management' becomes 'User_Management', which is different from 'user-management'
|
||||
expect(request.tags).toEqual(['User_Management', 'user-management']);
|
||||
});
|
||||
|
||||
it('should filter out tags that become empty after sanitization', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['...', 'valid-tag', '---'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const request = findRequestByName(result.items, 'Get users');
|
||||
expect(request).toBeDefined();
|
||||
expect(request.tags).toEqual(['valid-tag']);
|
||||
});
|
||||
|
||||
it('should use sanitized tag names for folder grouping', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['User Management'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/posts': {
|
||||
get: {
|
||||
operationId: 'getPosts',
|
||||
summary: 'Get posts',
|
||||
tags: ['User Management'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
// Find the folder created from the tag - spaces replaced with underscores
|
||||
const folder = findFolderByName(result.items, 'User_Management');
|
||||
expect(folder).toBeDefined();
|
||||
expect(folder.name).toBe('User_Management');
|
||||
expect(folder.items).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should sanitize folder names from tags with dots', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.0',
|
||||
info: {
|
||||
title: 'Test API',
|
||||
version: '1.0.0'
|
||||
},
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['api.v1'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
// Find the folder created from the tag - dots should be replaced
|
||||
const folder = findFolderByName(result.items, 'api_v1');
|
||||
expect(folder).toBeDefined();
|
||||
expect(folder.name).toBe('api_v1');
|
||||
});
|
||||
|
||||
it('should handle utf characters as well', () => {
|
||||
const openApiSpec = {
|
||||
openapi: '3.0.1',
|
||||
info: {
|
||||
title: 'CBC-MODEL3D-API',
|
||||
description: 'POWER BY WARE4U',
|
||||
termsOfService: 'http://swagger.io/terms/',
|
||||
contact: {
|
||||
name: '陈洪',
|
||||
email: 'sendreams@hotmail.com'
|
||||
},
|
||||
license: {
|
||||
name: 'Apache 2.0',
|
||||
url: 'http://springdoc.org'
|
||||
},
|
||||
version: '1.0.0'
|
||||
},
|
||||
tags: [
|
||||
{
|
||||
name: '模型管理',
|
||||
description: '发布和管理3d模型'
|
||||
},
|
||||
{
|
||||
name: '模型集市',
|
||||
description: '模型查询、评价、下单等'
|
||||
}
|
||||
],
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
operationId: 'getUsers',
|
||||
summary: 'Get users',
|
||||
tags: ['模型管理'],
|
||||
responses: {
|
||||
200: {
|
||||
description: 'Success'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const result = openApiToBruno(JSON.stringify(openApiSpec));
|
||||
const folder = findFolderByName(result.items, '模型管理');
|
||||
expect(folder).toBeDefined();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user