From ee715a6dc6449b3d3df576134d1033add2eb56b2 Mon Sep 17 00:00:00 2001 From: lohit Date: Sun, 15 Dec 2024 15:40:49 +0530 Subject: [PATCH] chore: headers/vars/script merge fns refactor (#3654) * chore: cli code refactoring * chore: code refactoring --- .../bruno-cli/src/runner/prepare-request.js | 204 +---------------- packages/bruno-cli/src/utils/collection.js | 208 +++++++++++++++++ .../bruno-electron/src/ipc/network/index.js | 29 +-- .../src/ipc/network/prepare-request.js | 215 +----------------- .../bruno-electron/src/utils/collection.js | 170 +++++++++++++- packages/bruno-electron/src/utils/common.js | 21 +- .../bruno-electron/src/utils/form-data.js | 52 +++++ .../tests/network/prepare-request.spec.js | 2 +- 8 files changed, 443 insertions(+), 458 deletions(-) create mode 100644 packages/bruno-cli/src/utils/collection.js create mode 100644 packages/bruno-electron/src/utils/form-data.js diff --git a/packages/bruno-cli/src/runner/prepare-request.js b/packages/bruno-cli/src/runner/prepare-request.js index 8c9daa43..1d18d529 100644 --- a/packages/bruno-cli/src/runner/prepare-request.js +++ b/packages/bruno-cli/src/runner/prepare-request.js @@ -1,208 +1,8 @@ -const { get, each, filter, find, compact } = require('lodash'); -const fs = require('fs'); -const os = require('os'); +const { get, each, filter } = require('lodash'); var JSONbig = require('json-bigint'); const decomment = require('decomment'); const crypto = require('node:crypto'); - -const mergeHeaders = (collection, request, requestTreePath) => { - let headers = new Map(); - - let collectionHeaders = get(collection, 'root.request.headers', []); - collectionHeaders.forEach((header) => { - if (header.enabled) { - headers.set(header.name, header.value); - } - }); - - for (let i of requestTreePath) { - if (i.type === 'folder') { - let _headers = get(i, 'root.request.headers', []); - _headers.forEach((header) => { - if (header.enabled) { - headers.set(header.name, header.value); - } - }); - } else { - const _headers = i?.draft ? get(i, 'draft.request.headers', []) : get(i, 'request.headers', []); - _headers.forEach((header) => { - if (header.enabled) { - headers.set(header.name, header.value); - } - }); - } - } - - request.headers = Array.from(headers, ([name, value]) => ({ name, value, enabled: true })); -}; - -const mergeVars = (collection, request, requestTreePath) => { - let reqVars = new Map(); - let collectionRequestVars = get(collection, 'root.request.vars.req', []); - let collectionVariables = {}; - collectionRequestVars.forEach((_var) => { - if (_var.enabled) { - reqVars.set(_var.name, _var.value); - collectionVariables[_var.name] = _var.value; - } - }); - let folderVariables = {}; - let requestVariables = {}; - for (let i of requestTreePath) { - if (i.type === 'folder') { - let vars = get(i, 'root.request.vars.req', []); - vars.forEach((_var) => { - if (_var.enabled) { - reqVars.set(_var.name, _var.value); - folderVariables[_var.name] = _var.value; - } - }); - } else { - const vars = i?.draft ? get(i, 'draft.request.vars.req', []) : get(i, 'request.vars.req', []); - vars.forEach((_var) => { - if (_var.enabled) { - reqVars.set(_var.name, _var.value); - requestVariables[_var.name] = _var.value; - } - }); - } - } - - request.collectionVariables = collectionVariables; - request.folderVariables = folderVariables; - request.requestVariables = requestVariables; - - if(request?.vars) { - request.vars.req = Array.from(reqVars, ([name, value]) => ({ - name, - value, - enabled: true, - type: 'request' - })); - } - - let resVars = new Map(); - let collectionResponseVars = get(collection, 'root.request.vars.res', []); - collectionResponseVars.forEach((_var) => { - if (_var.enabled) { - resVars.set(_var.name, _var.value); - } - }); - for (let i of requestTreePath) { - if (i.type === 'folder') { - let vars = get(i, 'root.request.vars.res', []); - vars.forEach((_var) => { - if (_var.enabled) { - resVars.set(_var.name, _var.value); - } - }); - } else { - const vars = i?.draft ? get(i, 'draft.request.vars.res', []) : get(i, 'request.vars.res', []); - vars.forEach((_var) => { - if (_var.enabled) { - resVars.set(_var.name, _var.value); - } - }); - } - } - - if(request?.vars) { - request.vars.res = Array.from(resVars, ([name, value]) => ({ - name, - value, - enabled: true, - type: 'response' - })); - } -}; - -const mergeScripts = (collection, request, requestTreePath, scriptFlow) => { - let collectionPreReqScript = get(collection, 'root.request.script.req', ''); - let collectionPostResScript = get(collection, 'root.request.script.res', ''); - let collectionTests = get(collection, 'root.request.tests', ''); - - let combinedPreReqScript = []; - let combinedPostResScript = []; - let combinedTests = []; - for (let i of requestTreePath) { - if (i.type === 'folder') { - let preReqScript = get(i, 'root.request.script.req', ''); - if (preReqScript && preReqScript.trim() !== '') { - combinedPreReqScript.push(preReqScript); - } - - let postResScript = get(i, 'root.request.script.res', ''); - if (postResScript && postResScript.trim() !== '') { - combinedPostResScript.push(postResScript); - } - - let tests = get(i, 'root.request.tests', ''); - if (tests && tests?.trim?.() !== '') { - combinedTests.push(tests); - } - } - } - - request.script.req = compact([collectionPreReqScript, ...combinedPreReqScript, request?.script?.req || '']).join(os.EOL); - - if (scriptFlow === 'sequential') { - request.script.res = compact([collectionPostResScript, ...combinedPostResScript, request?.script?.res || '']).join(os.EOL); - } else { - request.script.res = compact([request?.script?.res || '', ...combinedPostResScript.reverse(), collectionPostResScript]).join(os.EOL); - } - - if (scriptFlow === 'sequential') { - request.tests = compact([collectionTests, ...combinedTests, request?.tests || '']).join(os.EOL); - } else { - request.tests = compact([request?.tests || '', ...combinedTests.reverse(), collectionTests]).join(os.EOL); - } -}; - -const findItem = (items = [], pathname) => { - return find(items, (i) => i.pathname === pathname); -}; - -const findItemInCollection = (collection, pathname) => { - let flattenedItems = flattenItems(collection.items); - - return findItem(flattenedItems, pathname); -}; - -const findParentItemInCollection = (collection, pathname) => { - let flattenedItems = flattenItems(collection.items); - - return find(flattenedItems, (item) => { - return item.items && find(item.items, (i) => i.pathname === pathname); - }); -}; - -const flattenItems = (items = []) => { - const flattenedItems = []; - - const flatten = (itms, flattened) => { - each(itms, (i) => { - flattened.push(i); - - if (i.items && i.items.length) { - flatten(i.items, flattened); - } - }); - }; - - flatten(items, flattenedItems); - - return flattenedItems; -}; - -const getTreePathFromCollectionToItem = (collection, _item) => { - let path = []; - let item = findItemInCollection(collection, _item.pathname); - while (item) { - path.unshift(item); - item = findParentItemInCollection(collection, item.pathname); - } - return path; -}; +const { mergeHeaders, mergeScripts, mergeVars, getTreePathFromCollectionToItem } = require('../utils/collection'); const prepareRequest = (item = {}, collection = {}) => { const request = item?.request; diff --git a/packages/bruno-cli/src/utils/collection.js b/packages/bruno-cli/src/utils/collection.js new file mode 100644 index 00000000..365732c4 --- /dev/null +++ b/packages/bruno-cli/src/utils/collection.js @@ -0,0 +1,208 @@ +const { get, each, find, compact } = require('lodash'); +const os = require('os'); + +const mergeHeaders = (collection, request, requestTreePath) => { + let headers = new Map(); + + let collectionHeaders = get(collection, 'root.request.headers', []); + collectionHeaders.forEach((header) => { + if (header.enabled) { + headers.set(header.name, header.value); + } + }); + + for (let i of requestTreePath) { + if (i.type === 'folder') { + let _headers = get(i, 'root.request.headers', []); + _headers.forEach((header) => { + if (header.enabled) { + headers.set(header.name, header.value); + } + }); + } else { + const _headers = i?.draft ? get(i, 'draft.request.headers', []) : get(i, 'request.headers', []); + _headers.forEach((header) => { + if (header.enabled) { + headers.set(header.name, header.value); + } + }); + } + } + + request.headers = Array.from(headers, ([name, value]) => ({ name, value, enabled: true })); +}; + +const mergeVars = (collection, request, requestTreePath) => { + let reqVars = new Map(); + let collectionRequestVars = get(collection, 'root.request.vars.req', []); + let collectionVariables = {}; + collectionRequestVars.forEach((_var) => { + if (_var.enabled) { + reqVars.set(_var.name, _var.value); + collectionVariables[_var.name] = _var.value; + } + }); + let folderVariables = {}; + let requestVariables = {}; + for (let i of requestTreePath) { + if (i.type === 'folder') { + let vars = get(i, 'root.request.vars.req', []); + vars.forEach((_var) => { + if (_var.enabled) { + reqVars.set(_var.name, _var.value); + folderVariables[_var.name] = _var.value; + } + }); + } else { + const vars = i?.draft ? get(i, 'draft.request.vars.req', []) : get(i, 'request.vars.req', []); + vars.forEach((_var) => { + if (_var.enabled) { + reqVars.set(_var.name, _var.value); + requestVariables[_var.name] = _var.value; + } + }); + } + } + + request.collectionVariables = collectionVariables; + request.folderVariables = folderVariables; + request.requestVariables = requestVariables; + + if(request?.vars) { + request.vars.req = Array.from(reqVars, ([name, value]) => ({ + name, + value, + enabled: true, + type: 'request' + })); + } + + let resVars = new Map(); + let collectionResponseVars = get(collection, 'root.request.vars.res', []); + collectionResponseVars.forEach((_var) => { + if (_var.enabled) { + resVars.set(_var.name, _var.value); + } + }); + for (let i of requestTreePath) { + if (i.type === 'folder') { + let vars = get(i, 'root.request.vars.res', []); + vars.forEach((_var) => { + if (_var.enabled) { + resVars.set(_var.name, _var.value); + } + }); + } else { + const vars = i?.draft ? get(i, 'draft.request.vars.res', []) : get(i, 'request.vars.res', []); + vars.forEach((_var) => { + if (_var.enabled) { + resVars.set(_var.name, _var.value); + } + }); + } + } + + if(request?.vars) { + request.vars.res = Array.from(resVars, ([name, value]) => ({ + name, + value, + enabled: true, + type: 'response' + })); + } +}; + +const mergeScripts = (collection, request, requestTreePath, scriptFlow) => { + let collectionPreReqScript = get(collection, 'root.request.script.req', ''); + let collectionPostResScript = get(collection, 'root.request.script.res', ''); + let collectionTests = get(collection, 'root.request.tests', ''); + + let combinedPreReqScript = []; + let combinedPostResScript = []; + let combinedTests = []; + for (let i of requestTreePath) { + if (i.type === 'folder') { + let preReqScript = get(i, 'root.request.script.req', ''); + if (preReqScript && preReqScript.trim() !== '') { + combinedPreReqScript.push(preReqScript); + } + + let postResScript = get(i, 'root.request.script.res', ''); + if (postResScript && postResScript.trim() !== '') { + combinedPostResScript.push(postResScript); + } + + let tests = get(i, 'root.request.tests', ''); + if (tests && tests?.trim?.() !== '') { + combinedTests.push(tests); + } + } + } + + request.script.req = compact([collectionPreReqScript, ...combinedPreReqScript, request?.script?.req || '']).join(os.EOL); + + if (scriptFlow === 'sequential') { + request.script.res = compact([collectionPostResScript, ...combinedPostResScript, request?.script?.res || '']).join(os.EOL); + } else { + request.script.res = compact([request?.script?.res || '', ...combinedPostResScript.reverse(), collectionPostResScript]).join(os.EOL); + } + + if (scriptFlow === 'sequential') { + request.tests = compact([collectionTests, ...combinedTests, request?.tests || '']).join(os.EOL); + } else { + request.tests = compact([request?.tests || '', ...combinedTests.reverse(), collectionTests]).join(os.EOL); + } +}; + +const findItem = (items = [], pathname) => { + return find(items, (i) => i.pathname === pathname); +}; + +const findItemInCollection = (collection, pathname) => { + let flattenedItems = flattenItems(collection.items); + + return findItem(flattenedItems, pathname); +}; + +const findParentItemInCollection = (collection, pathname) => { + let flattenedItems = flattenItems(collection.items); + + return find(flattenedItems, (item) => { + return item.items && find(item.items, (i) => i.pathname === pathname); + }); +}; + +const flattenItems = (items = []) => { + const flattenedItems = []; + + const flatten = (itms, flattened) => { + each(itms, (i) => { + flattened.push(i); + + if (i.items && i.items.length) { + flatten(i.items, flattened); + } + }); + }; + + flatten(items, flattenedItems); + + return flattenedItems; +}; + +const getTreePathFromCollectionToItem = (collection, _item) => { + let path = []; + let item = findItemInCollection(collection, _item.pathname); + while (item) { + path.unshift(item); + item = findParentItemInCollection(collection, item.pathname); + } + return path; +}; + +module.exports = { + mergeHeaders, + mergeVars, + mergeScripts, + getTreePathFromCollectionToItem +} \ No newline at end of file diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index ded75010..9e37c828 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -38,7 +38,7 @@ const { const Oauth2Store = require('../../store/oauth2'); const iconv = require('iconv-lite'); const FormData = require('form-data'); -const { createFormData } = prepareRequest; +const { createFormData } = require('../../utils/form-data'); const safeStringifyJSON = (data) => { try { @@ -397,7 +397,7 @@ const registerNetworkIpc = (mainWindow) => { ) => { // run pre-request script let scriptResult; - const requestScript = compact([get(collectionRoot, 'request.script.req'), get(request, 'script.req')]).join(os.EOL); + const requestScript = get(request, 'script.req'); if (requestScript?.length) { const scriptRuntime = new ScriptRuntime({ runtime: scriptingConfig?.runtime }); scriptResult = await scriptRuntime.runRequestScript( @@ -493,12 +493,7 @@ const registerNetworkIpc = (mainWindow) => { } // run post-response script - const responseScript = compact(scriptingConfig.flow === 'sequential' ? [ - get(collectionRoot, 'request.script.res'), get(request, 'script.res') - ] : [ - get(request, 'script.res'), get(collectionRoot, 'request.script.res') - ]).join(os.EOL); - + const responseScript = get(request, 'script.res'); let scriptResult; if (responseScript?.length) { const scriptRuntime = new ScriptRuntime({ runtime: scriptingConfig?.runtime }); @@ -675,14 +670,7 @@ const registerNetworkIpc = (mainWindow) => { }); } - // run tests - const testScript = item.draft ? get(item.draft, 'request.tests') : get(item, 'request.tests'); - const testFile = compact(scriptingConfig.flow === 'sequential' ? [ - get(collectionRoot, 'request.tests'), testScript, - ] : [ - testScript, get(collectionRoot, 'request.tests') - ]).join(os.EOL); - + const testFile = get(request, 'tests'); if (typeof testFile === 'string') { const testRuntime = new TestRuntime({ runtime: scriptingConfig?.runtime }); const testResults = await testRuntime.runTests( @@ -1147,14 +1135,7 @@ const registerNetworkIpc = (mainWindow) => { }); } - // run tests - const testScript = item.draft ? get(item.draft, 'request.tests') : get(item, 'request.tests'); - const testFile = compact(scriptingConfig.flow === 'sequential' ? [ - get(collectionRoot, 'request.tests'), testScript - ] : [ - testScript, get(collectionRoot, 'request.tests') - ]).join(os.EOL); - + const testFile = get(request, 'tests'); if (typeof testFile === 'string') { const testRuntime = new TestRuntime({ runtime: scriptingConfig?.runtime }); const testResults = await testRuntime.runTests( diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index c8b36bb8..a544c970 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -1,194 +1,8 @@ -const os = require('os'); -const { get, each, filter, compact, forOwn } = require('lodash'); +const { get, each, filter } = require('lodash'); const decomment = require('decomment'); -const FormData = require('form-data'); -const fs = require('fs'); -const path = require('path'); const crypto = require('node:crypto'); -const { getTreePathFromCollectionToItem } = require('../../utils/collection'); -const { buildFormUrlEncodedPayload } = require('../../utils/common'); - -const mergeFolderLevelHeaders = (request, requestTreePath) => { - let folderHeaders = new Map(); - - for (let i of requestTreePath) { - if (i.type === 'folder') { - let headers = get(i, 'root.request.headers', []); - headers.forEach((header) => { - if (header.enabled) { - folderHeaders.set(header.name, header.value); - } - }); - } else if (i.uid === request.uid) { - const headers = i?.draft ? get(i, 'draft.request.headers', []) : get(i, 'request.headers', []); - headers.forEach((header) => { - if (header.enabled) { - folderHeaders.set(header.name, header.value); - } - }); - } - } - - let mergedFolderHeaders = Array.from(folderHeaders, ([name, value]) => ({ name, value, enabled: true })); - let requestHeaders = request.headers || []; - let requestHeadersMap = new Map(); - - for (let header of requestHeaders) { - if (header.enabled) { - requestHeadersMap.set(header.name, header.value); - } - } - - mergedFolderHeaders.forEach((header) => { - requestHeadersMap.set(header.name, header.value); - }); - - request.headers = Array.from(requestHeadersMap, ([name, value]) => ({ name, value, enabled: true })); -}; - -const mergeVars = (collection, request, requestTreePath) => { - let reqVars = new Map(); - let collectionRequestVars = get(collection, 'root.request.vars.req', []); - let collectionVariables = {}; - collectionRequestVars.forEach((_var) => { - if (_var.enabled) { - reqVars.set(_var.name, _var.value); - collectionVariables[_var.name] = _var.value; - } - }); - let folderVariables = {}; - let requestVariables = {}; - for (let i of requestTreePath) { - if (i.type === 'folder') { - let vars = get(i, 'root.request.vars.req', []); - vars.forEach((_var) => { - if (_var.enabled) { - reqVars.set(_var.name, _var.value); - folderVariables[_var.name] = _var.value; - } - }); - } else { - const vars = i?.draft ? get(i, 'draft.request.vars.req', []) : get(i, 'request.vars.req', []); - vars.forEach((_var) => { - if (_var.enabled) { - reqVars.set(_var.name, _var.value); - requestVariables[_var.name] = _var.value; - } - }); - } - } - - request.collectionVariables = collectionVariables; - request.folderVariables = folderVariables; - request.requestVariables = requestVariables; - - request.vars.req = Array.from(reqVars, ([name, value]) => ({ - name, - value, - enabled: true, - type: 'request' - })); - - let resVars = new Map(); - let collectionResponseVars = get(collection, 'root.request.vars.res', []); - collectionResponseVars.forEach((_var) => { - if (_var.enabled) { - resVars.set(_var.name, _var.value); - } - }); - for (let i of requestTreePath) { - if (i.type === 'folder') { - let vars = get(i, 'root.request.vars.res', []); - vars.forEach((_var) => { - if (_var.enabled) { - resVars.set(_var.name, _var.value); - } - }); - } else { - const vars = i?.draft ? get(i, 'draft.request.vars.res', []) : get(i, 'request.vars.res', []); - vars.forEach((_var) => { - if (_var.enabled) { - resVars.set(_var.name, _var.value); - } - }); - } - } - - request.vars.res = Array.from(resVars, ([name, value]) => ({ - name, - value, - enabled: true, - type: 'response' - })); -}; - -const mergeFolderLevelScripts = (request, requestTreePath, scriptFlow) => { - let folderCombinedPreReqScript = []; - let folderCombinedPostResScript = []; - let folderCombinedTests = []; - for (let i of requestTreePath) { - if (i.type === 'folder') { - let preReqScript = get(i, 'root.request.script.req', ''); - if (preReqScript && preReqScript.trim() !== '') { - folderCombinedPreReqScript.push(preReqScript); - } - - let postResScript = get(i, 'root.request.script.res', ''); - if (postResScript && postResScript.trim() !== '') { - folderCombinedPostResScript.push(postResScript); - } - - let tests = get(i, 'root.request.tests', ''); - if (tests && tests?.trim?.() !== '') { - folderCombinedTests.push(tests); - } - } - } - - if (folderCombinedPreReqScript.length) { - request.script.req = compact([...folderCombinedPreReqScript, request?.script?.req || '']).join(os.EOL); - } - - if (folderCombinedPostResScript.length) { - if (scriptFlow === 'sequential') { - request.script.res = compact([...folderCombinedPostResScript, request?.script?.res || '']).join(os.EOL); - } else { - request.script.res = compact([request?.script?.res || '', ...folderCombinedPostResScript.reverse()]).join(os.EOL); - } - } - - if (folderCombinedTests.length) { - if (scriptFlow === 'sequential') { - request.tests = compact([...folderCombinedTests, request?.tests || '']).join(os.EOL); - } else { - request.tests = compact([request?.tests || '', ...folderCombinedTests.reverse()]).join(os.EOL); - } - } -}; - -const createFormData = (datas, collectionPath) => { - // make axios work in node using form data - // reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427 - const form = new FormData(); - forOwn(datas, (value, key) => { - if (typeof value == 'string') { - form.append(key, value); - return; - } - - const filePaths = value || []; - filePaths?.forEach?.((filePath) => { - let trimmedFilePath = filePath.trim(); - - if (!path.isAbsolute(trimmedFilePath)) { - trimmedFilePath = path.join(collectionPath, trimmedFilePath); - } - - form.append(key, fs.createReadStream(trimmedFilePath), path.basename(trimmedFilePath)); - }); - }); - return form; -}; +const { getTreePathFromCollectionToItem, mergeHeaders, mergeScripts, mergeVars } = require('../../utils/collection'); +const { buildFormUrlEncodedPayload } = require('../../utils/form-data'); const setAuthHeaders = (axiosRequest, request, collectionRoot) => { const collectionAuth = get(collectionRoot, 'request.auth'); @@ -352,29 +166,25 @@ const prepareRequest = (item, collection) => { const headers = {}; let contentTypeDefined = false; let url = request.url; - - // Collection level headers + each(get(collectionRoot, 'request.headers', []), (h) => { - if (h.enabled && h.name.length > 0) { - headers[h.name] = h.value; - if (h.name.toLowerCase() === 'content-type') { - contentTypeDefined = true; - } + if (h.enabled && h.name?.toLowerCase() === 'content-type') { + contentTypeDefined = true; + return false; } }); - - // scriptFlow is either "sandwich" or "sequential" + const scriptFlow = collection.brunoConfig?.scripts?.flow ?? 'sandwich'; const requestTreePath = getTreePathFromCollectionToItem(collection, item); if (requestTreePath && requestTreePath.length > 0) { - mergeFolderLevelHeaders(request, requestTreePath); - mergeFolderLevelScripts(request, requestTreePath, scriptFlow); + mergeHeaders(collection, request, requestTreePath); + mergeScripts(collection, request, requestTreePath, scriptFlow); mergeVars(collection, request, requestTreePath); request.globalEnvironmentVariables = collection?.globalEnvironmentVariables; } - // Request level headers - each(request.headers, (h) => { + + each(get(request, 'headers', []), (h) => { if (h.enabled && h.name.length > 0) { headers[h.name] = h.value; if (h.name.toLowerCase() === 'content-type') { @@ -470,4 +280,3 @@ const prepareRequest = (item, collection) => { module.exports = prepareRequest; module.exports.setAuthHeaders = setAuthHeaders; -module.exports.createFormData = createFormData; diff --git a/packages/bruno-electron/src/utils/collection.js b/packages/bruno-electron/src/utils/collection.js index 5ec40a68..5b9c3452 100644 --- a/packages/bruno-electron/src/utils/collection.js +++ b/packages/bruno-electron/src/utils/collection.js @@ -1,5 +1,161 @@ -const each = require('lodash/each'); -const find = require('lodash/find'); +const { get, each, find, compact } = require('lodash'); +const os = require('os'); + +const mergeHeaders = (collection, request, requestTreePath) => { + let headers = new Map(); + + let collectionHeaders = get(collection, 'root.request.headers', []); + collectionHeaders.forEach((header) => { + if (header.enabled) { + headers.set(header.name, header.value); + if (header?.name?.toLowerCase() === 'content-type') { + contentTypeDefined = true; + } + } + }); + + for (let i of requestTreePath) { + if (i.type === 'folder') { + let _headers = get(i, 'root.request.headers', []); + _headers.forEach((header) => { + if (header.enabled) { + headers.set(header.name, header.value); + } + }); + } else { + const _headers = i?.draft ? get(i, 'draft.request.headers', []) : get(i, 'request.headers', []); + _headers.forEach((header) => { + if (header.enabled) { + headers.set(header.name, header.value); + } + }); + } + } + + request.headers = Array.from(headers, ([name, value]) => ({ name, value, enabled: true })); +}; + +const mergeVars = (collection, request, requestTreePath) => { + let reqVars = new Map(); + let collectionRequestVars = get(collection, 'root.request.vars.req', []); + let collectionVariables = {}; + collectionRequestVars.forEach((_var) => { + if (_var.enabled) { + reqVars.set(_var.name, _var.value); + collectionVariables[_var.name] = _var.value; + } + }); + let folderVariables = {}; + let requestVariables = {}; + for (let i of requestTreePath) { + if (i.type === 'folder') { + let vars = get(i, 'root.request.vars.req', []); + vars.forEach((_var) => { + if (_var.enabled) { + reqVars.set(_var.name, _var.value); + folderVariables[_var.name] = _var.value; + } + }); + } else { + const vars = i?.draft ? get(i, 'draft.request.vars.req', []) : get(i, 'request.vars.req', []); + vars.forEach((_var) => { + if (_var.enabled) { + reqVars.set(_var.name, _var.value); + requestVariables[_var.name] = _var.value; + } + }); + } + } + + request.collectionVariables = collectionVariables; + request.folderVariables = folderVariables; + request.requestVariables = requestVariables; + + if(request?.vars) { + request.vars.req = Array.from(reqVars, ([name, value]) => ({ + name, + value, + enabled: true, + type: 'request' + })); + } + + let resVars = new Map(); + let collectionResponseVars = get(collection, 'root.request.vars.res', []); + collectionResponseVars.forEach((_var) => { + if (_var.enabled) { + resVars.set(_var.name, _var.value); + } + }); + for (let i of requestTreePath) { + if (i.type === 'folder') { + let vars = get(i, 'root.request.vars.res', []); + vars.forEach((_var) => { + if (_var.enabled) { + resVars.set(_var.name, _var.value); + } + }); + } else { + const vars = i?.draft ? get(i, 'draft.request.vars.res', []) : get(i, 'request.vars.res', []); + vars.forEach((_var) => { + if (_var.enabled) { + resVars.set(_var.name, _var.value); + } + }); + } + } + + if(request?.vars) { + request.vars.res = Array.from(resVars, ([name, value]) => ({ + name, + value, + enabled: true, + type: 'response' + })); + } +}; + +const mergeScripts = (collection, request, requestTreePath, scriptFlow) => { + let collectionPreReqScript = get(collection, 'root.request.script.req', ''); + let collectionPostResScript = get(collection, 'root.request.script.res', ''); + let collectionTests = get(collection, 'root.request.tests', ''); + + let combinedPreReqScript = []; + let combinedPostResScript = []; + let combinedTests = []; + for (let i of requestTreePath) { + if (i.type === 'folder') { + let preReqScript = get(i, 'root.request.script.req', ''); + if (preReqScript && preReqScript.trim() !== '') { + combinedPreReqScript.push(preReqScript); + } + + let postResScript = get(i, 'root.request.script.res', ''); + if (postResScript && postResScript.trim() !== '') { + combinedPostResScript.push(postResScript); + } + + let tests = get(i, 'root.request.tests', ''); + if (tests && tests?.trim?.() !== '') { + combinedTests.push(tests); + } + } + } + + request.script.req = compact([collectionPreReqScript, ...combinedPreReqScript, request?.script?.req || '']).join(os.EOL); + + if (scriptFlow === 'sequential') { + request.script.res = compact([collectionPostResScript, ...combinedPostResScript, request?.script?.res || '']).join(os.EOL); + } else { + request.script.res = compact([request?.script?.res || '', ...combinedPostResScript.reverse(), collectionPostResScript]).join(os.EOL); + } + + if (scriptFlow === 'sequential') { + request.tests = compact([collectionTests, ...combinedTests, request?.tests || '']).join(os.EOL); + } else { + request.tests = compact([request?.tests || '', ...combinedTests.reverse(), collectionTests]).join(os.EOL); + } +}; const flattenItems = (items = []) => { const flattenedItems = []; @@ -44,14 +200,12 @@ const getTreePathFromCollectionToItem = (collection, _item) => { path.unshift(item); item = findParentItemInCollection(collection, item.uid); } - return path; }; module.exports = { - flattenItems, - findItem, - findItemInCollection, - findParentItemInCollection, + mergeHeaders, + mergeVars, + mergeScripts, getTreePathFromCollectionToItem -}; +} \ No newline at end of file diff --git a/packages/bruno-electron/src/utils/common.js b/packages/bruno-electron/src/utils/common.js index 1962ac26..50b17bb3 100644 --- a/packages/bruno-electron/src/utils/common.js +++ b/packages/bruno-electron/src/utils/common.js @@ -85,24 +85,6 @@ const flattenDataForDotNotation = (data) => { return result; }; -/** - * @param {Array.} params The request body Array - * @returns {object} Returns an obj with repeating key as a array of values - * {item: 2, item: 3, item1: 4} becomes {item: [2,3], item1: 4} - */ -const buildFormUrlEncodedPayload = (params) => { - return params.reduce((acc, p) => { - if (!acc[p.name]) { - acc[p.name] = p.value; - } else if (Array.isArray(acc[p.name])) { - acc[p.name].push(p.value); - } else { - acc[p.name] = [acc[p.name], p.value]; - } - return acc; - }, {}); -}; - module.exports = { uuid, stringifyJson, @@ -111,6 +93,5 @@ module.exports = { safeParseJSON, simpleHash, generateUidBasedOnHash, - flattenDataForDotNotation, - buildFormUrlEncodedPayload + flattenDataForDotNotation }; diff --git a/packages/bruno-electron/src/utils/form-data.js b/packages/bruno-electron/src/utils/form-data.js new file mode 100644 index 00000000..22bf1d3c --- /dev/null +++ b/packages/bruno-electron/src/utils/form-data.js @@ -0,0 +1,52 @@ +const { forOwn } = require('lodash'); +const FormData = require('form-data'); +const fs = require('fs'); +const path = require('path'); + +/** + * @param {Array.} params The request body Array + * @returns {object} Returns an obj with repeating key as a array of values + * {item: 2, item: 3, item1: 4} becomes {item: [2,3], item1: 4} + */ +const buildFormUrlEncodedPayload = (params) => { + return params.reduce((acc, p) => { + if (!acc[p.name]) { + acc[p.name] = p.value; + } else if (Array.isArray(acc[p.name])) { + acc[p.name].push(p.value); + } else { + acc[p.name] = [acc[p.name], p.value]; + } + return acc; + }, {}); +}; + + +const createFormData = (datas, collectionPath) => { + // make axios work in node using form data + // reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427 + const form = new FormData(); + forOwn(datas, (value, key) => { + if (typeof value == 'string') { + form.append(key, value); + return; + } + + const filePaths = value || []; + filePaths?.forEach?.((filePath) => { + let trimmedFilePath = filePath.trim(); + + if (!path.isAbsolute(trimmedFilePath)) { + trimmedFilePath = path.join(collectionPath, trimmedFilePath); + } + + form.append(key, fs.createReadStream(trimmedFilePath), path.basename(trimmedFilePath)); + }); + }); + return form; +}; + +module.exports = { + buildFormUrlEncodedPayload, + createFormData +}; diff --git a/packages/bruno-electron/tests/network/prepare-request.spec.js b/packages/bruno-electron/tests/network/prepare-request.spec.js index b61d42c5..a624d3ea 100644 --- a/packages/bruno-electron/tests/network/prepare-request.spec.js +++ b/packages/bruno-electron/tests/network/prepare-request.spec.js @@ -1,7 +1,7 @@ const { describe, it, expect } = require('@jest/globals'); const prepareRequest = require('../../src/ipc/network/prepare-request'); -const { buildFormUrlEncodedPayload } = require('../../src/utils/common'); +const { buildFormUrlEncodedPayload } = require('../../src/utils/form-data'); describe('prepare-request: prepareRequest', () => { describe('Decomments request body', () => {