mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-24 21:25:45 +00:00
fix: skip null query parameters in Postman to Bruno conversion (#7193)
* fix: skip null query parameters in Postman to Bruno conversion Updated the importPostmanV2CollectionItem function to skip query parameters where both key and value are null. Added a test case to ensure that such parameters are not included in the converted Bruno collection, while preserving other valid parameters. * fix: skip null parameters in Postman to Bruno conversion Updated the importPostmanV2CollectionItem function to skip headers, URL-encoded parameters, and form data where both key and value are null. Added corresponding test cases to ensure proper handling of these scenarios in the conversion process.
This commit is contained in:
@@ -465,15 +465,16 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
brunoRequestItem.request.body.mode = 'multipartForm';
|
||||
|
||||
each(i.request.body.formdata, (param) => {
|
||||
if (param.key == null && param.value == null) return;
|
||||
const isFile = param.type === 'file' || (param.type === 'default' && param.src);
|
||||
const value = isFile
|
||||
? (Array.isArray(param.src) ? param.src : param.src ? [param.src] : [])
|
||||
: (Array.isArray(param.value) ? param.value.join('') : param.value);
|
||||
: (Array.isArray(param.value) ? param.value.join('') : param.value ?? '');
|
||||
|
||||
brunoRequestItem.request.body.multipartForm.push({
|
||||
uid: uuid(),
|
||||
type: isFile ? 'file' : 'text',
|
||||
name: param.key,
|
||||
name: param.key ?? '',
|
||||
value,
|
||||
description: transformDescription(param.description),
|
||||
enabled: !param.disabled,
|
||||
@@ -485,10 +486,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
if (bodyMode === 'urlencoded') {
|
||||
brunoRequestItem.request.body.mode = 'formUrlEncoded';
|
||||
each(i.request.body.urlencoded, (param) => {
|
||||
if (param.key == null && param.value == null) return;
|
||||
brunoRequestItem.request.body.formUrlEncoded.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
value: param.value,
|
||||
name: param.key ?? '',
|
||||
value: param.value ?? '',
|
||||
description: transformDescription(param.description),
|
||||
enabled: !param.disabled
|
||||
});
|
||||
@@ -520,10 +522,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
}
|
||||
|
||||
each(i.request.header, (header) => {
|
||||
if (header.key == null && header.value == null) return;
|
||||
brunoRequestItem.request.headers.push({
|
||||
uid: uuid(),
|
||||
name: header.key,
|
||||
value: header.value,
|
||||
name: header.key ?? '',
|
||||
value: header.value ?? '',
|
||||
description: transformDescription(header.description),
|
||||
enabled: !header.disabled
|
||||
});
|
||||
@@ -533,10 +536,13 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
processAuth(i.request.auth, brunoRequestItem.request);
|
||||
|
||||
each(get(i, 'request.url.query'), (param) => {
|
||||
if (param.key == null && param.value == null) {
|
||||
return;
|
||||
}
|
||||
brunoRequestItem.request.params.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
value: param.value,
|
||||
name: param.key ?? '',
|
||||
value: param.value ?? '',
|
||||
description: transformDescription(param.description),
|
||||
type: 'query',
|
||||
enabled: !param.disabled
|
||||
@@ -606,10 +612,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
// Convert original request headers
|
||||
if (originalRequest.header && Array.isArray(originalRequest.header)) {
|
||||
originalRequest.header.forEach((header) => {
|
||||
if (header.key == null && header.value == null) return;
|
||||
example.request.headers.push({
|
||||
uid: uuid(),
|
||||
name: header.key,
|
||||
value: header.value,
|
||||
name: header.key ?? '',
|
||||
value: header.value ?? '',
|
||||
description: transformDescription(header.description),
|
||||
enabled: !header.disabled
|
||||
});
|
||||
@@ -619,10 +626,13 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
// Convert original request query parameters
|
||||
if (originalRequest.url && originalRequest.url.query && Array.isArray(originalRequest.url.query)) {
|
||||
originalRequest.url.query.forEach((param) => {
|
||||
if (param.key == null && param.value == null) {
|
||||
return;
|
||||
}
|
||||
example.request.params.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
value: param.value,
|
||||
name: param.key ?? '',
|
||||
value: param.value ?? '',
|
||||
description: transformDescription(param.description),
|
||||
type: 'query',
|
||||
enabled: !param.disabled
|
||||
@@ -632,6 +642,7 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
|
||||
if (originalRequest.url && originalRequest.url.variable && Array.isArray(originalRequest.url.variable)) {
|
||||
originalRequest.url.variable.forEach((param) => {
|
||||
if (!param.key) return;
|
||||
example.request.params.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
@@ -650,15 +661,16 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
example.request.body.mode = 'multipartForm';
|
||||
if (originalRequest.body.formdata && Array.isArray(originalRequest.body.formdata)) {
|
||||
originalRequest.body.formdata.forEach((param) => {
|
||||
if (param.key == null && param.value == null) return;
|
||||
const isFile = param.type === 'file' || (param.type === 'default' && param.src);
|
||||
const value = isFile
|
||||
? (Array.isArray(param.src) ? param.src : param.src ? [param.src] : [])
|
||||
: (Array.isArray(param.value) ? param.value.join('') : param.value);
|
||||
: (Array.isArray(param.value) ? param.value.join('') : param.value ?? '');
|
||||
|
||||
example.request.body.multipartForm.push({
|
||||
uid: uuid(),
|
||||
type: isFile ? 'file' : 'text',
|
||||
name: param.key,
|
||||
name: param.key ?? '',
|
||||
value,
|
||||
description: transformDescription(param.description),
|
||||
enabled: !param.disabled,
|
||||
@@ -670,10 +682,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
example.request.body.mode = 'formUrlEncoded';
|
||||
if (originalRequest.body.urlencoded && Array.isArray(originalRequest.body.urlencoded)) {
|
||||
originalRequest.body.urlencoded.forEach((param) => {
|
||||
if (param.key == null && param.value == null) return;
|
||||
example.request.body.formUrlEncoded.push({
|
||||
uid: uuid(),
|
||||
name: param.key,
|
||||
value: param.value,
|
||||
name: param.key ?? '',
|
||||
value: param.value ?? '',
|
||||
description: transformDescription(param.description),
|
||||
enabled: !param.disabled
|
||||
});
|
||||
@@ -700,10 +713,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, { useWorkers = false }
|
||||
// Convert response headers
|
||||
if (response.header && Array.isArray(response.header)) {
|
||||
response.header.forEach((header) => {
|
||||
if (header.key == null && header.value == null) return;
|
||||
example.response.headers.push({
|
||||
uid: uuid(),
|
||||
name: header.key,
|
||||
value: header.value,
|
||||
name: header.key ?? '',
|
||||
value: header.value ?? '',
|
||||
description: transformDescription(header.description),
|
||||
enabled: true
|
||||
});
|
||||
|
||||
@@ -604,6 +604,171 @@ describe('postman-collection', () => {
|
||||
digest: null
|
||||
});
|
||||
});
|
||||
|
||||
it('should skip headers where both key and value are null, and coalesce partial nulls', async () => {
|
||||
const collectionWithNullHeaders = {
|
||||
info: {
|
||||
_postman_id: 'test-null-headers',
|
||||
name: 'collection with null headers',
|
||||
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
||||
},
|
||||
item: [
|
||||
{
|
||||
name: 'request with null headers',
|
||||
request: {
|
||||
method: 'GET',
|
||||
header: [
|
||||
{ key: 'Content-Type', value: 'application/json' },
|
||||
{ key: null, value: null },
|
||||
{ key: null, value: 'somevalue' },
|
||||
{ key: 'X-Custom', value: null }
|
||||
],
|
||||
url: { raw: 'https://example.com/api' }
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const brunoCollection = await postmanToBruno(collectionWithNullHeaders);
|
||||
const headers = brunoCollection.items[0].request.headers;
|
||||
|
||||
expect(headers).toHaveLength(3);
|
||||
expect(headers[0].name).toBe('Content-Type');
|
||||
expect(headers[0].value).toBe('application/json');
|
||||
expect(headers[1].name).toBe('');
|
||||
expect(headers[1].value).toBe('somevalue');
|
||||
expect(headers[2].name).toBe('X-Custom');
|
||||
expect(headers[2].value).toBe('');
|
||||
});
|
||||
|
||||
it('should skip urlencoded params where both key and value are null', async () => {
|
||||
const collectionWithNullUrlencoded = {
|
||||
info: {
|
||||
_postman_id: 'test-null-urlencoded',
|
||||
name: 'collection with null urlencoded',
|
||||
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
||||
},
|
||||
item: [
|
||||
{
|
||||
name: 'request with null urlencoded',
|
||||
request: {
|
||||
method: 'POST',
|
||||
header: [],
|
||||
url: { raw: 'https://example.com/api' },
|
||||
body: {
|
||||
mode: 'urlencoded',
|
||||
urlencoded: [
|
||||
{ key: 'field1', value: 'value1' },
|
||||
{ key: null, value: null },
|
||||
{ key: null, value: 'partialvalue' },
|
||||
{ key: 'field2', value: null }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const brunoCollection = await postmanToBruno(collectionWithNullUrlencoded);
|
||||
const formUrlEncoded = brunoCollection.items[0].request.body.formUrlEncoded;
|
||||
|
||||
expect(formUrlEncoded).toHaveLength(3);
|
||||
expect(formUrlEncoded[0].name).toBe('field1');
|
||||
expect(formUrlEncoded[0].value).toBe('value1');
|
||||
expect(formUrlEncoded[1].name).toBe('');
|
||||
expect(formUrlEncoded[1].value).toBe('partialvalue');
|
||||
expect(formUrlEncoded[2].name).toBe('field2');
|
||||
expect(formUrlEncoded[2].value).toBe('');
|
||||
});
|
||||
|
||||
it('should skip formdata params where both key and value are null', async () => {
|
||||
const collectionWithNullFormdata = {
|
||||
info: {
|
||||
_postman_id: 'test-null-formdata',
|
||||
name: 'collection with null formdata',
|
||||
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
||||
},
|
||||
item: [
|
||||
{
|
||||
name: 'request with null formdata',
|
||||
request: {
|
||||
method: 'POST',
|
||||
header: [],
|
||||
url: { raw: 'https://example.com/api' },
|
||||
body: {
|
||||
mode: 'formdata',
|
||||
formdata: [
|
||||
{ key: 'field1', value: 'value1', type: 'text' },
|
||||
{ key: null, value: null, type: 'text' },
|
||||
{ key: 'field2', value: null, type: 'text' }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const brunoCollection = await postmanToBruno(collectionWithNullFormdata);
|
||||
const multipartForm = brunoCollection.items[0].request.body.multipartForm;
|
||||
|
||||
expect(multipartForm).toHaveLength(2);
|
||||
expect(multipartForm[0].name).toBe('field1');
|
||||
expect(multipartForm[0].value).toBe('value1');
|
||||
expect(multipartForm[1].name).toBe('field2');
|
||||
expect(multipartForm[1].value).toBe('');
|
||||
});
|
||||
|
||||
it('should skip query params where both key and value are null', async () => {
|
||||
const collectionWithNullQueryParams = {
|
||||
info: {
|
||||
_postman_id: 'test-null-query-params',
|
||||
name: 'collection with null query params',
|
||||
schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
|
||||
},
|
||||
item: [
|
||||
{
|
||||
name: 'request with null query params',
|
||||
request: {
|
||||
method: 'GET',
|
||||
header: [],
|
||||
url: {
|
||||
raw: 'https://example.com/api?search=test',
|
||||
protocol: 'https',
|
||||
host: ['example', 'com'],
|
||||
path: ['api'],
|
||||
query: [
|
||||
{ key: 'search', value: 'test' },
|
||||
{ key: null, value: null },
|
||||
{ key: null, value: 'somevalue' },
|
||||
{ key: 'emptyval', value: null }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const brunoCollection = await postmanToBruno(collectionWithNullQueryParams);
|
||||
const params = brunoCollection.items[0].request.params;
|
||||
|
||||
// Fully-null entry should be skipped
|
||||
expect(params).toHaveLength(3);
|
||||
|
||||
// Normal param preserved as-is
|
||||
expect(params[0].name).toBe('search');
|
||||
expect(params[0].value).toBe('test');
|
||||
expect(params[0].type).toBe('query');
|
||||
|
||||
// Null key normalized to empty string, value preserved
|
||||
expect(params[1].name).toBe('');
|
||||
expect(params[1].value).toBe('somevalue');
|
||||
expect(params[1].type).toBe('query');
|
||||
|
||||
// Key preserved, null value normalized to empty string
|
||||
expect(params[2].name).toBe('emptyval');
|
||||
expect(params[2].value).toBe('');
|
||||
expect(params[2].type).toBe('query');
|
||||
});
|
||||
});
|
||||
|
||||
// Simple Collection (postman)
|
||||
|
||||
Reference in New Issue
Block a user