mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
fix: Postman import compatibility for multipart form-data file params (#7325)
* fix: multipart form-data file param export/import for Postman * fix: Postman import compatibility for multipart form-data file params This commit fixes two issues that caused Postman to fail importing Bruno-exported collections with multipart form-data file parameters: 1. Changed `src` field format to match Postman's export format: - Single file: export as string (e.g., "/path/to/file") - Multiple files: export as array (e.g., ["/path/a", "/path/b"]) - Empty/null: export as null Previously, Bruno always exported `src` as an array, but Postman's importer expects a string for single files and fails to recognize the file type and path when given an array. 2. Added `protocolProfileBehavior.disableBodyPruning` for GET/HEAD/OPTIONS requests that have a body: By default, Postman discards request bodies for HTTP methods that typically don't have bodies (GET, HEAD, OPTIONS). Without this flag, importing a GET request with a form-data body would result in the body being silently dropped, making Postman unable to identify that the request has a formdata body at all. Both changes align Bruno's Postman export format with Postman's own export format, ensuring full import compatibility. --------- Co-authored-by: Chirag Chandrashekhar <cchirag85@gmail.com>
This commit is contained in:
committed by
GitHub
parent
5e75bc5fcb
commit
a9709fb82a
@@ -268,13 +268,21 @@ export const brunoToPostman = (collection) => {
|
||||
mode: 'formdata',
|
||||
formdata: map(body.multipartForm || [], (bodyItem) => {
|
||||
const isFile = bodyItem.type === 'file';
|
||||
|
||||
const getSrc = () => {
|
||||
if (!bodyItem.value) return null;
|
||||
if (Array.isArray(bodyItem.value)) {
|
||||
if (bodyItem.value.length === 0) return null;
|
||||
if (bodyItem.value.length === 1) return bodyItem.value[0];
|
||||
return bodyItem.value;
|
||||
}
|
||||
return bodyItem.value;
|
||||
};
|
||||
return {
|
||||
key: bodyItem.name || '',
|
||||
disabled: !bodyItem.enabled,
|
||||
type: isFile ? 'file' : 'text',
|
||||
...(isFile
|
||||
? { src: Array.isArray(bodyItem.value) ? bodyItem.value : bodyItem.value ? [bodyItem.value] : [] }
|
||||
: { value: bodyItem.value || '' }),
|
||||
...(isFile ? { src: getSrc() } : { value: bodyItem.value || '' }),
|
||||
...(bodyItem.contentType && { contentType: bodyItem.contentType })
|
||||
};
|
||||
})
|
||||
@@ -507,8 +515,15 @@ export const brunoToPostman = (collection) => {
|
||||
};
|
||||
} else if (isItemARequest(item)) {
|
||||
const requestEvents = generateEventSection(item.request);
|
||||
const method = (item.request?.method || 'GET').toUpperCase();
|
||||
const hasBody = item.request?.body && item.request.body.mode !== 'none';
|
||||
|
||||
const methodsWithoutBody = ['GET', 'HEAD', 'OPTIONS'];
|
||||
const needsBodyPruningDisabled = hasBody && methodsWithoutBody.includes(method);
|
||||
|
||||
const postmanItem = {
|
||||
name: item.name || 'Untitled Request',
|
||||
...(needsBodyPruningDisabled ? { protocolProfileBehavior: { disableBodyPruning: true } } : {}),
|
||||
request: generateRequestSection(item.request),
|
||||
...(requestEvents.length ? { event: requestEvents } : {})
|
||||
};
|
||||
|
||||
@@ -604,7 +604,7 @@ describe('brunoToPostman multipartForm handling', () => {
|
||||
formdata: [
|
||||
{
|
||||
key: 'myFile',
|
||||
src: ['/path/to/file.json'],
|
||||
src: '/path/to/file.json',
|
||||
disabled: false,
|
||||
type: 'file',
|
||||
contentType: 'application/json'
|
||||
@@ -656,7 +656,7 @@ describe('brunoToPostman multipartForm handling', () => {
|
||||
},
|
||||
{
|
||||
key: 'fileField',
|
||||
src: ['/path/to/file.txt'],
|
||||
src: '/path/to/file.txt',
|
||||
disabled: true,
|
||||
type: 'file'
|
||||
}
|
||||
@@ -692,7 +692,7 @@ describe('brunoToPostman multipartForm handling', () => {
|
||||
const result = brunoToPostman(simpleCollection);
|
||||
expect(result.item[0].request.body.formdata[0]).toEqual({
|
||||
key: 'myFile',
|
||||
src: ['/single/file/path.txt'],
|
||||
src: '/single/file/path.txt',
|
||||
disabled: false,
|
||||
type: 'file'
|
||||
});
|
||||
@@ -726,13 +726,117 @@ describe('brunoToPostman multipartForm handling', () => {
|
||||
const result = brunoToPostman(simpleCollection);
|
||||
expect(result.item[0].request.body.formdata[0]).toEqual({
|
||||
key: 'myFile',
|
||||
src: [],
|
||||
src: null,
|
||||
disabled: false,
|
||||
type: 'file'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('brunoToPostman protocolProfileBehavior handling', () => {
|
||||
it('should add disableBodyPruning for GET requests with body', () => {
|
||||
const simpleCollection = {
|
||||
items: [
|
||||
{
|
||||
name: 'GET with body',
|
||||
type: 'http-request',
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: 'https://example.com',
|
||||
body: {
|
||||
mode: 'multipartForm',
|
||||
multipartForm: [
|
||||
{
|
||||
name: 'file',
|
||||
value: '/path/to/file.txt',
|
||||
type: 'file',
|
||||
enabled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const result = brunoToPostman(simpleCollection);
|
||||
expect(result.item[0].protocolProfileBehavior).toEqual({
|
||||
disableBodyPruning: true
|
||||
});
|
||||
});
|
||||
|
||||
it('should not add protocolProfileBehavior for POST requests with body', () => {
|
||||
const simpleCollection = {
|
||||
items: [
|
||||
{
|
||||
name: 'POST with body',
|
||||
type: 'http-request',
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: 'https://example.com',
|
||||
body: {
|
||||
mode: 'multipartForm',
|
||||
multipartForm: [
|
||||
{
|
||||
name: 'file',
|
||||
value: '/path/to/file.txt',
|
||||
type: 'file',
|
||||
enabled: true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const result = brunoToPostman(simpleCollection);
|
||||
expect(result.item[0].protocolProfileBehavior).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should not add protocolProfileBehavior for GET requests without body', () => {
|
||||
const simpleCollection = {
|
||||
items: [
|
||||
{
|
||||
name: 'GET without body',
|
||||
type: 'http-request',
|
||||
request: {
|
||||
method: 'GET',
|
||||
url: 'https://example.com'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const result = brunoToPostman(simpleCollection);
|
||||
expect(result.item[0].protocolProfileBehavior).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should add disableBodyPruning for HEAD requests with body', () => {
|
||||
const simpleCollection = {
|
||||
items: [
|
||||
{
|
||||
name: 'HEAD with body',
|
||||
type: 'http-request',
|
||||
request: {
|
||||
method: 'HEAD',
|
||||
url: 'https://example.com',
|
||||
body: {
|
||||
mode: 'json',
|
||||
json: '{"test": true}'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const result = brunoToPostman(simpleCollection);
|
||||
expect(result.item[0].protocolProfileBehavior).toEqual({
|
||||
disableBodyPruning: true
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('brunoToPostman event handling', () => {
|
||||
it('should generate events for request scripts (req/res)', () => {
|
||||
const simpleCollection = {
|
||||
|
||||
Reference in New Issue
Block a user