fix: Add null checks and fallbacks to Bruno-to-Postman converter to… (#4525)

This commit is contained in:
pooja-bruno 2025-04-22 16:40:15 +05:30 committed by GitHub
parent 220da6b58e
commit 317ccccfc6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 466 additions and 26 deletions

View File

@ -171,10 +171,13 @@ export const brunoToPostman = (collection) => {
};
const generateHeaders = (headersArray) => {
if (!headersArray || !Array.isArray(headersArray)) {
return [];
}
return map(headersArray, (item) => {
return {
key: item.name,
value: item.value,
key: item.name || '',
value: item.value || '',
disabled: !item.enabled,
type: 'default'
};
@ -182,14 +185,21 @@ export const brunoToPostman = (collection) => {
};
const generateBody = (body) => {
if (!body || !body.mode) {
return {
mode: 'raw',
raw: ''
};
}
switch (body.mode) {
case 'formUrlEncoded':
return {
mode: 'urlencoded',
urlencoded: map(body.formUrlEncoded, (bodyItem) => {
urlencoded: map(body.formUrlEncoded || [], (bodyItem) => {
return {
key: bodyItem.name,
value: bodyItem.value,
key: bodyItem.name || '',
value: bodyItem.value || '',
disabled: !bodyItem.enabled,
type: 'default'
};
@ -198,10 +208,10 @@ export const brunoToPostman = (collection) => {
case 'multipartForm':
return {
mode: 'formdata',
formdata: map(body.multipartForm, (bodyItem) => {
formdata: map(body.multipartForm || [], (bodyItem) => {
return {
key: bodyItem.name,
value: bodyItem.value,
key: bodyItem.name || '',
value: bodyItem.value || '',
disabled: !bodyItem.enabled,
type: 'default'
};
@ -210,7 +220,7 @@ export const brunoToPostman = (collection) => {
case 'json':
return {
mode: 'raw',
raw: body.json,
raw: body.json || '',
options: {
raw: {
language: 'json'
@ -220,7 +230,7 @@ export const brunoToPostman = (collection) => {
case 'xml':
return {
mode: 'raw',
raw: body.xml,
raw: body.xml || '',
options: {
raw: {
language: 'xml'
@ -230,7 +240,7 @@ export const brunoToPostman = (collection) => {
case 'text':
return {
mode: 'raw',
raw: body.text,
raw: body.text || '',
options: {
raw: {
language: 'text'
@ -240,7 +250,12 @@ export const brunoToPostman = (collection) => {
case 'graphql':
return {
mode: 'graphql',
graphql: body.graphql
graphql: body.graphql || {}
};
default:
return {
mode: 'raw',
raw: ''
};
}
};
@ -252,7 +267,7 @@ export const brunoToPostman = (collection) => {
type: 'bearer',
bearer: {
key: 'token',
value: itemAuth.bearer.token,
value: itemAuth.bearer?.token || '',
type: 'string'
}
};
@ -262,12 +277,12 @@ export const brunoToPostman = (collection) => {
basic: [
{
key: 'password',
value: itemAuth.basic.password,
value: itemAuth.basic?.password || '',
type: 'string'
},
{
key: 'username',
value: itemAuth.basic.username,
value: itemAuth.basic?.username || '',
type: 'string'
}
]
@ -279,12 +294,12 @@ export const brunoToPostman = (collection) => {
apikey: [
{
key: 'key',
value: itemAuth.apikey.key,
value: itemAuth.apikey?.key || '',
type: 'string'
},
{
key: 'value',
value: itemAuth.apikey.value,
value: itemAuth.apikey?.value || '',
type: 'string'
}
]
@ -299,31 +314,43 @@ export const brunoToPostman = (collection) => {
};
const generateRequestSection = (itemRequest) => {
if (!itemRequest) {
return {};
}
const requestObject = {
method: itemRequest.method,
method: itemRequest.method || 'GET',
header: generateHeaders(itemRequest.headers),
auth: generateAuth(itemRequest.auth),
description: itemRequest.docs,
description: itemRequest.docs || '',
// We sanitize the URL to make sure it's in the right format before passing it to the transformUrl func. This means changing backslashes to forward slashes and reducing multiple slashes to a single one, except in the protocol part.
url: transformUrl(sanitizeUrl(itemRequest.url), itemRequest.params)
url: transformUrl(sanitizeUrl(itemRequest.url || ''), itemRequest.params || [])
};
if (itemRequest.body.mode !== 'none') {
if (itemRequest.body && itemRequest.body.mode !== 'none') {
requestObject.body = generateBody(itemRequest.body);
}
return requestObject;
};
const generateItemSection = (itemsArray) => {
if (!itemsArray || !Array.isArray(itemsArray)) {
return [];
}
return map(itemsArray, (item) => {
if (!item) {
return null;
}
if (item.type === 'folder') {
return {
name: item.name,
item: item.items.length ? generateItemSection(item.items) : []
name: item.name || 'Untitled Folder',
item: item.items && item.items.length ? generateItemSection(item.items) : []
};
} else {
return {
name: item.name,
name: item.name || 'Untitled Request',
event: generateEventSection(item),
request: generateRequestSection(item.request)
};

View File

@ -1,4 +1,4 @@
import { sanitizeUrl, transformUrl } from "../../src/postman/bruno-to-postman";
import { sanitizeUrl, transformUrl, brunoToPostman } from "../../src/postman/bruno-to-postman";
describe('transformUrl', () => {
it('should handle basic URL with path variables', () => {
@ -78,4 +78,417 @@ describe('sanitizeUrl', () => {
const expected = 'http://example.com/path/to/file';
expect(sanitizeUrl(input)).toBe(expected);
});
})
});
describe('brunoToPostman null checks and fallbacks', () => {
it('should handle null or undefined headers', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
headers: null
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.header).toEqual([]);
});
it('should handle null or undefined items in headers', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
headers: [
{ name: null, value: 'test-value', enabled: true },
{ name: 'Content-Type', value: null, enabled: true }
]
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.header).toEqual([
{ key: '', value: 'test-value', disabled: false, type: 'default' },
{ key: 'Content-Type', value: '', disabled: false, type: 'default' }
]);
});
it('should handle null or undefined body', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
body: null
}
}
]
};
const result = brunoToPostman(simpleCollection);
// Should not have body property since we're checking for body before adding it
expect(result.item[0].request.body).toBeUndefined();
});
it('should handle null or undefined body mode', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
body: {}
}
}
]
};
const result = brunoToPostman(simpleCollection);
// Should use default raw mode for undefined body mode
expect(result.item[0].request.body).toEqual({
mode: 'raw',
raw: ''
});
});
it('should handle null or undefined formUrlEncoded array', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'POST',
url: 'https://example.com',
body: {
mode: 'formUrlEncoded',
formUrlEncoded: null
}
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.body).toEqual({
mode: 'urlencoded',
urlencoded: []
});
});
it('should handle null or undefined multipartForm array', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'POST',
url: 'https://example.com',
body: {
mode: 'multipartForm',
multipartForm: null
}
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.body).toEqual({
mode: 'formdata',
formdata: []
});
});
it('should handle null or undefined items in form data', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'POST',
url: 'https://example.com',
body: {
mode: 'formUrlEncoded',
formUrlEncoded: [
{ name: null, value: 'test-value', enabled: true },
{ name: 'field', value: null, enabled: true }
]
}
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.body.urlencoded).toEqual([
{ key: '', value: 'test-value', disabled: false, type: 'default' },
{ key: 'field', value: '', disabled: false, type: 'default' }
]);
});
it('should handle null or undefined method', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
url: 'https://example.com',
method: null
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.method).toBe('GET');
});
it('should handle null or undefined url', () => {
// Mock console.error to prevent it from logging during test
const originalConsoleError = console.error;
console.error = jest.fn();
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: null
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.url.raw).toBe('');
});
it('should handle null or undefined params', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
params: null
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.url.variable).toEqual([]);
});
it('should handle null or undefined docs', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
docs: null
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.description).toBe('');
});
it('should handle null or undefined folder name', () => {
const simpleCollection = {
items: [
{
type: 'folder',
name: null,
items: []
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].name).toBe('Untitled Folder');
});
it('should handle null or undefined request name', () => {
const simpleCollection = {
items: [
{
type: 'http-request',
name: null,
request: {
method: 'GET',
url: 'https://example.com'
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].name).toBe('Untitled Request');
});
it('should handle null or undefined folder items', () => {
const simpleCollection = {
items: [
{
type: 'folder',
name: 'Test Folder',
items: null
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].item).toEqual([]);
});
it('should handle null or undefined auth object', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
auth: null
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.auth).toEqual({ type: 'noauth' });
});
it('should handle missing token in bearer auth', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
auth: {
mode: 'bearer',
bearer: { token: null }
}
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.auth).toEqual({
type: 'bearer',
bearer: {
key: 'token',
value: '',
type: 'string'
}
});
});
it('should handle missing username/password in basic auth', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
auth: {
mode: 'basic',
basic: { username: null, password: undefined }
}
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.auth).toEqual({
type: 'basic',
basic: [
{
key: 'password',
value: '',
type: 'string'
},
{
key: 'username',
value: '',
type: 'string'
}
]
});
});
it('should handle missing key/value in apikey auth', () => {
const simpleCollection = {
items: [
{
name: 'Test Request',
type: 'http-request',
request: {
method: 'GET',
url: 'https://example.com',
auth: {
mode: 'apikey',
apikey: { key: null, value: undefined }
}
}
}
]
};
const result = brunoToPostman(simpleCollection);
expect(result.item[0].request.auth).toEqual({
type: 'apikey',
apikey: [
{
key: 'key',
value: '',
type: 'string'
},
{
key: 'value',
value: '',
type: 'string'
}
]
});
});
});