From f3afb4bf841f75e1c986c04efdceed0e136cdd59 Mon Sep 17 00:00:00 2001 From: Abhishek S Lal Date: Thu, 30 Oct 2025 19:54:07 +0530 Subject: [PATCH] Fix/export folder and collection level scripts (#5942) * fix: bruno to postman export - export pre and post request scripts on folder/collection level * refactor: removed redundant code. * fix: lint error - file should end with a new line --------- Co-authored-by: Jakub Sadowski Co-authored-by: Bijin A B --- .../src/postman/bruno-to-postman.js | 59 ++++++---- .../tests/postman/bruno-to-postman.spec.js | 101 ++++++++++++++++++ 2 files changed, 137 insertions(+), 23 deletions(-) diff --git a/packages/bruno-converters/src/postman/bruno-to-postman.js b/packages/bruno-converters/src/postman/bruno-to-postman.js index e4748c229..d3238ade2 100644 --- a/packages/bruno-converters/src/postman/bruno-to-postman.js +++ b/packages/bruno-converters/src/postman/bruno-to-postman.js @@ -69,7 +69,7 @@ export const transformUrl = (url, params) => { postmanUrl.query = params .filter((param) => param.type === 'query') .map(({ name, value, description }) => ({ key: name, value, description })); - + // Construct path params. postmanUrl.variable = params .filter((param) => param.type === 'path') @@ -80,10 +80,10 @@ export const transformUrl = (url, params) => { /** * Collapses multiple consecutive slashes (`//`) into a single slash, while skipping the protocol (e.g., `http://` or `https://`). - * + * * @param {String} url - A URL string * @returns {String} The sanitized URL - * + * */ const collapseDuplicateSlashes = (url) => { return url.replace(/(? { /** * Replaces all `\\` (backslashes) with `//` (forward slashes) and collapses multiple slashes into one. - * + * * @param {string} url - The URL to sanitize. * @returns {string} The sanitized URL. * @@ -146,24 +146,30 @@ export const brunoToPostman = (collection) => { type: 'default' })); }; - const generateEventSection = (item) => { const eventArray = []; - if (item?.request?.tests?.length) { - eventArray.push({ - listen: 'test', - script: { - exec: item.request.tests.split('\n') - // type: 'text/javascript' - } - }); - } - if (item?.request?.script?.req) { + // Request: item.script, Folder: item.root.request.script, Collection: item.request.script + const scriptBlock = item?.script || item?.root?.request?.script || item?.request?.script; + + if (scriptBlock?.req) { eventArray.push({ listen: 'prerequest', script: { - exec: item.request.script.req.split('\n') - // type: 'text/javascript' + type: 'text/javascript', + packages: {}, + requests: {}, + exec: scriptBlock.req.split('\n') + } + }); + } + if (scriptBlock?.res) { + eventArray.push({ + listen: 'test', + script: { + type: 'text/javascript', + packages: {}, + requests: {}, + exec: scriptBlock.res.split('\n') } }); } @@ -317,7 +323,7 @@ export const brunoToPostman = (collection) => { if (!itemRequest) { return {}; } - + const requestObject = { method: itemRequest.method || 'GET', header: generateHeaders(itemRequest.headers), @@ -337,7 +343,7 @@ export const brunoToPostman = (collection) => { if (!itemsArray || !Array.isArray(itemsArray)) { return []; } - + return map(itemsArray, (item) => { if (!item) { return null; @@ -346,17 +352,20 @@ export const brunoToPostman = (collection) => { if (item.type === 'grpc-request') { return null; } - + if (item.type === 'folder') { + const folderEvents = generateEventSection(item); return { name: item.name || 'Untitled Folder', - item: item.items && item.items.length ? generateItemSection(item.items) : [] + item: generateItemSection(item.items), + ...(folderEvents.length ? { event: folderEvents } : {}) }; } else { + const requestEvents = generateEventSection(item.request); return { name: item.name || 'Untitled Request', - event: generateEventSection(item), - request: generateRequestSection(item.request) + request: generateRequestSection(item.request), + ...(requestEvents.length ? { event: requestEvents } : {}) }; } }); @@ -365,6 +374,10 @@ export const brunoToPostman = (collection) => { collectionToExport.info = generateInfoSection(); collectionToExport.item = generateItemSection(collection.items); collectionToExport.variable = generateCollectionVars(collection); + const collectionEvents = generateEventSection(collection.root); + if (collectionEvents.length) { + collectionToExport.event = collectionEvents; + } return collectionToExport; }; diff --git a/packages/bruno-converters/tests/postman/bruno-to-postman.spec.js b/packages/bruno-converters/tests/postman/bruno-to-postman.spec.js index 7d5018997..417c527b2 100644 --- a/packages/bruno-converters/tests/postman/bruno-to-postman.spec.js +++ b/packages/bruno-converters/tests/postman/bruno-to-postman.spec.js @@ -492,3 +492,104 @@ describe('brunoToPostman null checks and fallbacks', () => { }); }); }); + +describe('brunoToPostman event handling', () => { + it('should generate events for request scripts (req/res)', () => { + const simpleCollection = { + items: [ + { + name: 'Test Request', + type: 'http-request', + request: { + method: 'GET', + url: 'https://example.com', + script: { + req: 'console.log("pre");', + res: 'console.log("post");' + } + } + } + ] + }; + + const result = brunoToPostman(simpleCollection); + const events = result.item[0].event; + + expect(events).toHaveLength(2); + expect(events[0]).toMatchObject({ listen: 'prerequest', script: { exec: ['console.log("pre");'] } }); + expect(events[1]).toMatchObject({ listen: 'test', script: { exec: ['console.log("post");'] } }); + }); + + it('should generate events for folder scripts', () => { + const simpleCollection = { + items: [ + { + type: 'folder', + name: 'Test Folder', + script: { + req: 'console.log("folder pre");', + res: 'console.log("folder post");' + }, + items: [] + } + ] + }; + + const result = brunoToPostman(simpleCollection); + const folder = result.item[0]; + + expect(folder.name).toBe('Test Folder'); + expect(folder.event).toHaveLength(2); + expect(folder.event[0].listen).toBe('prerequest'); + expect(folder.event[1].listen).toBe('test'); + }); + + it('should generate collection-level events from root', () => { + const simpleCollection = { + root: { + script: { + req: 'console.log("collection pre");', + res: 'console.log("collection post");' + } + }, + items: [] + }; + + const result = brunoToPostman(simpleCollection); + expect(result.event).toHaveLength(2); + expect(result.event[0].listen).toBe('prerequest'); + expect(result.event[1].listen).toBe('test'); + }); + + it('should handle nested folders and requests with scripts', () => { + const simpleCollection = { + items: [ + { + type: 'folder', + name: 'Parent Folder', + items: [ + { + type: 'http-request', + name: 'Nested Request', + request: { + method: 'GET', + url: 'https://example.com', + script: { req: 'console.log("nested pre");' } + } + } + ] + } + ] + }; + + const result = brunoToPostman(simpleCollection); + const folder = result.item[0]; + const nestedRequest = folder.item[0]; + + expect(folder.name).toBe('Parent Folder'); + expect(nestedRequest.name).toBe('Nested Request'); + expect(nestedRequest.event).toHaveLength(1); + expect(nestedRequest.event[0].listen).toBe('prerequest'); + expect(nestedRequest.event[0].script.exec).toEqual(['console.log("nested pre");']); + }); +});