From 705b8b5c68ebaa80ca456c5739dba010ce84c3cf Mon Sep 17 00:00:00 2001 From: sanish-bruno Date: Wed, 12 Feb 2025 17:45:53 +0530 Subject: [PATCH] feat: add getSize method to BrunoResponse and update related shims and translations --- package-lock.json | 13 +- .../src/components/CodeEditor/index.js | 3 +- .../translators/postman_translation.js | 5 +- .../src/runner/run-single-request.js | 38 ++-- .../bruno-cli/src/utils/axios-instance.js | 15 +- .../src/ipc/network/axios-instance.js | 19 +- .../bruno-electron/src/ipc/network/index.js | 185 ++++++++++-------- packages/bruno-js/src/bruno-response.js | 4 + .../bruno-js/src/runtime/script-runtime.js | 28 ++- .../sandbox/quickjs/shims/bruno-response.js | 6 + 10 files changed, 189 insertions(+), 127 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42cf6a3436..a3af1292fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -787,7 +786,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -818,7 +816,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -836,7 +833,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/@babel/generator": { @@ -1116,7 +1112,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", @@ -7083,7 +7078,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true, "license": "MIT" }, "node_modules/@types/lodash": { @@ -7096,7 +7090,6 @@ "version": "12.2.3", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/linkify-it": "*", @@ -7107,7 +7100,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true, "license": "MIT" }, "node_modules/@types/ms": { @@ -10337,7 +10329,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -11939,7 +11930,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -12973,7 +12963,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -23545,7 +23534,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index 2f9ca9cdd3..53aead4c67 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -35,6 +35,7 @@ if (!SERVER_RENDERED) { 'res.getHeaders()', 'res.getBody()', 'res.getResponseTime()', + 'res.getSize()', 'req', 'req.url', 'req.method', @@ -83,7 +84,7 @@ if (!SERVER_RENDERED) { 'bru.runner', 'bru.runner.setNextRequest(requestName)', 'bru.runner.skipRequest()', - 'bru.runner.stopExecution()', + 'bru.runner.stopExecution()' ]; CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => { const cursor = editor.getCursor(); diff --git a/packages/bruno-app/src/utils/importers/translators/postman_translation.js b/packages/bruno-app/src/utils/importers/translators/postman_translation.js index 5d6573c162..e62f90a1e3 100644 --- a/packages/bruno-app/src/utils/importers/translators/postman_translation.js +++ b/packages/bruno-app/src/utils/importers/translators/postman_translation.js @@ -19,6 +19,9 @@ const replacements = { 'pm\\.expect\\.fail\\(': 'expect.fail(', 'pm\\.response\\.responseTime': 'res.getResponseTime()', 'pm\\.environment\\.name': 'bru.getEnvName()', + 'pm\\.response\\.status': 'res.statusText()', + 'pm\\.response\\.headers': 'res.headers', + 'pm\\.response\\.size': 'res.getSize()', "tests\\['([^']+)'\\]\\s*=\\s*([^;]+);": 'test("$1", function() { expect(Boolean($2)).to.be.true; });', // deprecated translations 'postman\\.setEnvironmentVariable\\(': 'bru.setEnvVar(', @@ -27,7 +30,7 @@ const replacements = { 'pm\\.execution\\.skipRequest\\(\\)': 'bru.runner.skipRequest()', 'pm\\.execution\\.skipRequest': 'bru.runner.skipRequest', 'pm\\.execution\\.setNextRequest\\(null\\)': 'bru.runner.stopExecution()', - 'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runner.stopExecution()', + "pm\\.execution\\.setNextRequest\\('null'\\)": 'bru.runner.stopExecution()' }; const extendedReplacements = Object.keys(replacements).reduce((acc, key) => { diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index c8e137b7b8..9d6a8451aa 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -25,7 +25,6 @@ const { createFormData } = require('../utils/form-data'); const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; const { NtlmClient } = require('axios-ntlm'); - const onConsoleLog = (type, args) => { console[type](...args); }; @@ -50,7 +49,7 @@ const runSingleRequest = async function ( let item = { pathname: path.join(collectionPath, filename), ...bruJson - } + }; request = prepareRequest(item, collection); request.__bruno__executionMode = 'cli'; @@ -265,29 +264,28 @@ const runSingleRequest = async function ( if (!options.disableCookies) { const cookieString = getCookieStringForUrl(request.url); if (cookieString && typeof cookieString === 'string' && cookieString.length) { - const existingCookieHeaderName = Object.keys(request.headers).find( - name => name.toLowerCase() === 'cookie' - ); + const existingCookieHeaderName = Object.keys(request.headers).find((name) => name.toLowerCase() === 'cookie'); const existingCookieString = existingCookieHeaderName ? request.headers[existingCookieHeaderName] : ''; - + // Helper function to parse cookies into an object - const parseCookies = (str) => str.split(';').reduce((cookies, cookie) => { + const parseCookies = (str) => + str.split(';').reduce((cookies, cookie) => { const [name, ...rest] = cookie.split('='); if (name && name.trim()) { - cookies[name.trim()] = rest.join('=').trim(); + cookies[name.trim()] = rest.join('=').trim(); } return cookies; - }, {}); - + }, {}); + const mergedCookies = { - ...parseCookies(existingCookieString), - ...parseCookies(cookieString), + ...parseCookies(existingCookieString), + ...parseCookies(cookieString) }; - + const combinedCookieString = Object.entries(mergedCookies) - .map(([name, value]) => `${name}=${value}`) - .join('; '); - + .map(([name, value]) => `${name}=${value}`) + .join('; '); + request.headers[existingCookieHeaderName || 'Cookie'] = combinedCookieString; } } @@ -307,13 +305,11 @@ const runSingleRequest = async function ( let response, responseTime; try { - let axiosInstance = makeAxiosInstance(); if (request.ntlmConfig) { - axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance.defaults) + axiosInstance = NtlmClient(request.ntlmConfig, axiosInstance.defaults); delete request.ntlmConfig; } - if (request.awsv4config) { // todo: make this happen in prepare-request.js @@ -375,7 +371,7 @@ const runSingleRequest = async function ( data: null, responseTime: 0 }, - error: err?.message || err?.errors?.map(e => e?.message)?.at(0) || err?.code || 'Request Failed!', + error: err?.message || err?.errors?.map((e) => e?.message)?.at(0) || err?.code || 'Request Failed!', assertionResults: [], testResults: [], nextRequestName: nextRequestName, @@ -388,7 +384,7 @@ const runSingleRequest = async function ( console.log( chalk.green(stripExtension(filename)) + - chalk.dim(` (${response.status} ${response.statusText}) - ${responseTime} ms`) + chalk.dim(` (${response.status} ${response.statusText}) - ${responseTime} ms`) ); // run post-response vars diff --git a/packages/bruno-cli/src/utils/axios-instance.js b/packages/bruno-cli/src/utils/axios-instance.js index 834cda2a89..02609eb355 100644 --- a/packages/bruno-cli/src/utils/axios-instance.js +++ b/packages/bruno-cli/src/utils/axios-instance.js @@ -12,7 +12,7 @@ function makeAxiosInstance() { const instance = axios.create({ proxy: false, headers: { - "User-Agent": `bruno-runtime/${CLI_VERSION}` + 'User-Agent': `bruno-runtime/${CLI_VERSION}` } }); @@ -26,6 +26,11 @@ function makeAxiosInstance() { const end = Date.now(); const start = response.config.headers['request-start-time']; response.headers['request-duration'] = end - start; + // response size is the sum of the response data and the headers, should it include anything else? + const responseSize = + Buffer.byteLength(response.data) + + Object.keys(response.headers).reduce((total, key) => total + Buffer.byteLength(key + response.headers[key]), 0); + response.headers['response-size'] = responseSize; return response; }, (error) => { @@ -33,6 +38,14 @@ function makeAxiosInstance() { const end = Date.now(); const start = error.config.headers['request-start-time']; error.response.headers['request-duration'] = end - start; + // response size is the sum of the response data and the headers, should it include anything else? + const responseSize = + Buffer.byteLength(error.response.data) + + Object.keys(error.response.headers).reduce( + (total, key) => total + Buffer.byteLength(key + error.response.headers[key]), + 0 + ); + error.response.headers['response-size'] = responseSize; } return Promise.reject(error); } diff --git a/packages/bruno-electron/src/ipc/network/axios-instance.js b/packages/bruno-electron/src/ipc/network/axios-instance.js index 4f7f9f8f6a..79ca363396 100644 --- a/packages/bruno-electron/src/ipc/network/axios-instance.js +++ b/packages/bruno-electron/src/ipc/network/axios-instance.js @@ -2,12 +2,12 @@ const URL = require('url'); const Socket = require('net').Socket; const axios = require('axios'); const connectionCache = new Map(); // Cache to store checkConnection() results -const electronApp = require("electron"); +const electronApp = require('electron'); const LOCAL_IPV6 = '::1'; const LOCAL_IPV4 = '127.0.0.1'; const LOCALHOST = 'localhost'; -const version = electronApp?.app?.getVersion()?.substring(1) ?? ""; +const version = electronApp?.app?.getVersion()?.substring(1) ?? ''; const getTld = (hostname) => { if (!hostname) { @@ -69,7 +69,7 @@ function makeAxiosInstance() { }, proxy: false, headers: { - "User-Agent": `bruno-runtime/${version}` + 'User-Agent': `bruno-runtime/${version}` } }); @@ -99,6 +99,11 @@ function makeAxiosInstance() { const end = Date.now(); const start = response.config.headers['request-start-time']; response.headers['request-duration'] = end - start; + // response size is the sum of the response data and the headers, should it include anything else? + const responseSize = + Buffer.byteLength(response.data) + + Object.keys(response.headers).reduce((total, key) => total + Buffer.byteLength(key + response.headers[key]), 0); + response.headers['response-size'] = responseSize; return response; }, (error) => { @@ -106,6 +111,14 @@ function makeAxiosInstance() { const end = Date.now(); const start = error.config.headers['request-start-time']; error.response.headers['request-duration'] = end - start; + // response size is the sum of the response data and the headers, should it include anything else? + const responseSize = + Buffer.byteLength(error.response.data) + + Object.keys(error.response.headers).reduce( + (total, key) => total + Buffer.byteLength(key + error.response.headers[key]), + 0 + ); + error.response.headers['response-size'] = responseSize; } return Promise.reject(error); } diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 2271a3d331..7bdc1a60e1 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -90,9 +90,7 @@ const saveCookies = (url, headers) => { if (preferencesUtil.shouldStoreCookies()) { let setCookieHeaders = []; if (headers['set-cookie']) { - setCookieHeaders = Array.isArray(headers['set-cookie']) - ? headers['set-cookie'] - : [headers['set-cookie']]; + setCookieHeaders = Array.isArray(headers['set-cookie']) ? headers['set-cookie'] : [headers['set-cookie']]; for (let setCookieHeader of setCookieHeaders) { if (typeof setCookieHeader === 'string' && setCookieHeader.length) { addCookieToJar(setCookieHeader, url); @@ -100,16 +98,9 @@ const saveCookies = (url, headers) => { } } } -} - -const configureRequest = async ( - collectionUid, - request, - envVars, - runtimeVariables, - processEnvVars, - collectionPath -) => { +}; + +const configureRequest = async (collectionUid, request, envVars, runtimeVariables, processEnvVars, collectionPath) => { if (!protocolRegex.test(request.url)) { request.url = `http://${request.url}`; } @@ -181,14 +172,14 @@ const configureRequest = async ( /** * Proxy configuration - * + * * Preferences proxyMode has three possible values: on, off, system * Collection proxyMode has three possible values: true, false, global - * + * * When collection proxyMode is true, it overrides the app-level proxy settings * When collection proxyMode is false, it ignores the app-level proxy settings * When collection proxyMode is global, it uses the app-level proxy settings - * + * * Below logic calculates the proxyMode and proxyConfig to be used for the request */ let proxyMode = 'off'; @@ -275,13 +266,12 @@ const configureRequest = async ( } let axiosInstance = makeAxiosInstance(); - + if (request.ntlmConfig) { - axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance.defaults) + axiosInstance = NtlmClient(request.ntlmConfig, axiosInstance.defaults); delete request.ntlmConfig; } - if (request.oauth2) { let requestCopy = cloneDeep(request); switch (request?.oauth2?.grantType) { @@ -332,29 +322,28 @@ const configureRequest = async ( if (preferencesUtil.shouldSendCookies()) { const cookieString = getCookieStringForUrl(request.url); if (cookieString && typeof cookieString === 'string' && cookieString.length) { - const existingCookieHeaderName = Object.keys(request.headers).find( - name => name.toLowerCase() === 'cookie' - ); + const existingCookieHeaderName = Object.keys(request.headers).find((name) => name.toLowerCase() === 'cookie'); const existingCookieString = existingCookieHeaderName ? request.headers[existingCookieHeaderName] : ''; - + // Helper function to parse cookies into an object - const parseCookies = (str) => str.split(';').reduce((cookies, cookie) => { + const parseCookies = (str) => + str.split(';').reduce((cookies, cookie) => { const [name, ...rest] = cookie.split('='); if (name && name.trim()) { - cookies[name.trim()] = rest.join('=').trim(); + cookies[name.trim()] = rest.join('=').trim(); } return cookies; - }, {}); - + }, {}); + const mergedCookies = { - ...parseCookies(existingCookieString), - ...parseCookies(cookieString), + ...parseCookies(existingCookieString), + ...parseCookies(cookieString) }; - + const combinedCookieString = Object.entries(mergedCookies) - .map(([name, value]) => `${name}=${value}`) - .join('; '); - + .map(([name, value]) => `${name}=${value}`) + .join('; '); + request.headers[existingCookieHeaderName || 'Cookie'] = combinedCookieString; } } @@ -400,12 +389,12 @@ const parseDataFromResponse = (response, disableParsingResponseJson = false) => data = data.replace(/^\uFEFF/, ''); // If the response is a string and starts and ends with double quotes, it's a stringified JSON and should not be parsed - if ( !disableParsingResponseJson && ! (typeof data === 'string' && data.startsWith("\"") && data.endsWith("\""))) { + if (!disableParsingResponseJson && !(typeof data === 'string' && data.startsWith('"') && data.endsWith('"'))) { data = JSON.parse(data); } - } catch { + } catch { console.log('Failed to parse response data as JSON'); - } + } return { data, dataBuffer }; }; @@ -569,7 +558,14 @@ const registerNetworkIpc = (mainWindow) => { return scriptResult; }; - const runRequest = async ({ item, collection, envVars, processEnvVars, runtimeVariables, runInBackground = false }) => { + const runRequest = async ({ + item, + collection, + envVars, + processEnvVars, + runtimeVariables, + runInBackground = false + }) => { const collectionUid = collection.uid; const collectionPath = collection.pathname; const cancelTokenUid = uuid(); @@ -582,21 +578,29 @@ const registerNetworkIpc = (mainWindow) => { itemPathname = `${itemPathname}.bru`; } const _item = cloneDeep(findItemInCollectionByPathname(collection, itemPathname)); - if(_item) { - const res = await runRequest({ item: _item, collection, envVars, processEnvVars, runtimeVariables, runInBackground: true }); + if (_item) { + const res = await runRequest({ + item: _item, + collection, + envVars, + processEnvVars, + runtimeVariables, + runInBackground: true + }); resolve(res); } reject(`bru.runRequest: invalid request path - ${itemPathname}`); }); - } + }; - !runInBackground && mainWindow.webContents.send('main:run-request-event', { - type: 'request-queued', - requestUid, - collectionUid, - itemUid: item.uid, - cancelTokenUid - }); + !runInBackground && + mainWindow.webContents.send('main:run-request-event', { + type: 'request-queued', + requestUid, + collectionUid, + itemUid: item.uid, + cancelTokenUid + }); const abortController = new AbortController(); const request = await prepareRequest(item, collection, abortController); @@ -631,22 +635,23 @@ const registerNetworkIpc = (mainWindow) => { collectionPath ); - !runInBackground && mainWindow.webContents.send('main:run-request-event', { - type: 'request-sent', - requestSent: { - url: request.url, - method: request.method, - headers: request.headers, - data: request.mode == 'file'? "": safeParseJSON(safeStringifyJSON(request.data)) , - timestamp: Date.now() - }, - collectionUid, - itemUid: item.uid, - requestUid, - cancelTokenUid - }); + !runInBackground && + mainWindow.webContents.send('main:run-request-event', { + type: 'request-sent', + requestSent: { + url: request.url, + method: request.method, + headers: request.headers, + data: request.mode == 'file' ? '' : safeParseJSON(safeStringifyJSON(request.data)), + timestamp: Date.now() + }, + collectionUid, + itemUid: item.uid, + requestUid, + cancelTokenUid + }); - let response, responseTime; + let response, responseTime, responseSize; try { /** @type {import('axios').AxiosResponse} */ response = await axiosInstance(request); @@ -654,6 +659,8 @@ const registerNetworkIpc = (mainWindow) => { // Prevents the duration on leaking to the actual result responseTime = response.headers.get('request-duration'); response.headers.delete('request-duration'); + responseSize = response.headers.get('response-size'); + response.headers.delete('response-size'); } catch (error) { deleteCancelToken(cancelTokenUid); @@ -670,6 +677,8 @@ const registerNetworkIpc = (mainWindow) => { // Prevents the duration on leaking to the actual result responseTime = response.headers.get('request-duration'); response.headers.delete('request-duration'); + responseSize = response.headers.get('response-size'); + response.headers.delete('response-size'); } else { // if it's not a network error, don't continue return Promise.reject(error); @@ -682,6 +691,7 @@ const registerNetworkIpc = (mainWindow) => { response.data = data; response.responseTime = responseTime; + response.responseSize = responseSize; // save cookies if (preferencesUtil.shouldStoreCookies()) { @@ -720,13 +730,14 @@ const registerNetworkIpc = (mainWindow) => { processEnvVars ); - !runInBackground && mainWindow.webContents.send('main:run-request-event', { - type: 'assertion-results', - results: results, - itemUid: item.uid, - requestUid, - collectionUid - }); + !runInBackground && + mainWindow.webContents.send('main:run-request-event', { + type: 'assertion-results', + results: results, + itemUid: item.uid, + requestUid, + collectionUid + }); } const testFile = get(request, 'tests'); @@ -745,13 +756,14 @@ const registerNetworkIpc = (mainWindow) => { runRequestByItemPathname ); - !runInBackground && mainWindow.webContents.send('main:run-request-event', { - type: 'test-results', - results: testResults.results, - itemUid: item.uid, - requestUid, - collectionUid - }); + !runInBackground && + mainWindow.webContents.send('main:run-request-event', { + type: 'test-results', + results: testResults.results, + itemUid: item.uid, + requestUid, + collectionUid + }); mainWindow.webContents.send('main:script-environment-update', { envVariables: testResults.envVariables, @@ -779,7 +791,7 @@ const registerNetworkIpc = (mainWindow) => { return Promise.reject(error); } - } + }; // handler for sending http request ipcMain.handle('send-http-request', async (event, item, collection, environment, runtimeVariables) => { @@ -991,13 +1003,20 @@ const registerNetworkIpc = (mainWindow) => { itemPathname = `${itemPathname}.bru`; } const _item = cloneDeep(findItemInCollectionByPathname(collection, itemPathname)); - if(_item) { - const res = await runRequest({ item: _item, collection, envVars, processEnvVars, runtimeVariables, runInBackground: true }); + if (_item) { + const res = await runRequest({ + item: _item, + collection, + envVars, + processEnvVars, + runtimeVariables, + runInBackground: true + }); resolve(res); } reject(`bru.runRequest: invalid request path - ${itemPathname}`); }); - } + }; if (!folder) { folder = collection; @@ -1061,7 +1080,7 @@ const registerNetworkIpc = (mainWindow) => { const request = await prepareRequest(item, collection, abortController); request.__bruno__executionMode = 'runner'; - + const requestUid = uuid(); try { @@ -1358,7 +1377,7 @@ const registerNetworkIpc = (mainWindow) => { try { const disposition = contentDispositionParser.parse(contentDisposition); return disposition && disposition.parameters['filename']; - } catch (error) { } + } catch (error) {} }; const getFileNameFromUrlPath = () => { @@ -1390,7 +1409,7 @@ const registerNetworkIpc = (mainWindow) => { const filePath = await chooseFileToSave(mainWindow, fileName); if (filePath) { const encoding = getEncodingFormat(); - const data = Buffer.from(response.dataBuffer, 'base64') + const data = Buffer.from(response.dataBuffer, 'base64'); if (encoding === 'utf-8') { await writeFile(filePath, data); } else { diff --git a/packages/bruno-js/src/bruno-response.js b/packages/bruno-js/src/bruno-response.js index faa3152356..6c085f2584 100644 --- a/packages/bruno-js/src/bruno-response.js +++ b/packages/bruno-js/src/bruno-response.js @@ -37,6 +37,10 @@ class BrunoResponse { return this.res ? this.res.responseTime : null; } + getSize() { + return this.res ? this.res.responseSize : null; + } + setBody(data) { if (!this.res) { return; diff --git a/packages/bruno-js/src/runtime/script-runtime.js b/packages/bruno-js/src/runtime/script-runtime.js index 758b574e8e..541d8255d0 100644 --- a/packages/bruno-js/src/runtime/script-runtime.js +++ b/packages/bruno-js/src/runtime/script-runtime.js @@ -54,7 +54,16 @@ class ScriptRuntime { const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; - const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables); + const bru = new Bru( + envVariables, + runtimeVariables, + processEnvVars, + collectionPath, + collectionVariables, + folderVariables, + requestVariables, + globalEnvironmentVariables + ); const req = new BrunoRequest(request); const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false); const moduleWhitelist = get(scriptingConfig, 'moduleWhitelist', []); @@ -95,7 +104,7 @@ class ScriptRuntime { }; } - if(runRequestByItemPathname) { + if (runRequestByItemPathname) { context.bru.runRequest = runRequestByItemPathname; } @@ -147,7 +156,7 @@ class ScriptRuntime { chai, 'node-fetch': fetch, 'crypto-js': CryptoJS, - 'xml2js': xml2js, + xml2js: xml2js, cheerio, ...whitelistedModules, fs: allowScriptFilesystemAccess ? fs : undefined, @@ -185,7 +194,16 @@ class ScriptRuntime { const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; - const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables); + const bru = new Bru( + envVariables, + runtimeVariables, + processEnvVars, + collectionPath, + collectionVariables, + folderVariables, + requestVariables, + globalEnvironmentVariables + ); const req = new BrunoRequest(request); const res = new BrunoResponse(response); const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false); @@ -223,7 +241,7 @@ class ScriptRuntime { }; } - if(runRequestByItemPathname) { + if (runRequestByItemPathname) { context.bru.runRequest = runRequestByItemPathname; } diff --git a/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js b/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js index fb2ae6888a..2303896a38 100644 --- a/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js +++ b/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js @@ -56,6 +56,12 @@ const addBrunoResponseShimToContext = (vm, res) => { vm.setProp(resFn, 'setBody', setBody); setBody.dispose(); + let getSize = vm.newFunction('getSize', function () { + return marshallToVm(res.getSize(), vm); + }); + vm.setProp(resFn, 'getSize', getSize); + getSize.dispose(); + vm.setProp(vm.global, 'res', resFn); resFn.dispose(); };