From 60a0a32743e3e5ffe55fbb260b7a64c253dd5e84 Mon Sep 17 00:00:00 2001 From: Tim Nikischin <49103409+nikischin@users.noreply.github.com> Date: Wed, 30 Jul 2025 16:05:17 +0200 Subject: [PATCH] Implement Response URL variable (#2983) --- .../src/runner/run-single-request.js | 3 +++ .../bruno-electron/src/ipc/network/index.js | 2 ++ packages/bruno-js/src/bruno-response.js | 5 ++++ .../sandbox/quickjs/shims/bruno-response.js | 9 ++++++++ packages/bruno-js/src/utils.js | 1 + .../collection/scripting/api/res/getUrl.bru | 23 +++++++++++++++++++ 6 files changed, 43 insertions(+) create mode 100644 packages/bruno-tests/collection/scripting/api/res/getUrl.bru diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index 55397c7c4..ed1e554e0 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -463,6 +463,7 @@ const runSingleRequest = async function ( statusText: null, headers: null, data: null, + url: null, responseTime: 0 }, error: err?.message || err?.errors?.map(e => e?.message)?.at(0) || err?.code || 'Request Failed!', @@ -602,6 +603,7 @@ const runSingleRequest = async function ( statusText: response.statusText, headers: response.headers, data: response.data, + url: response.request ? response.request.protocol + '//' + response.request.host + response.request.path : null, responseTime }, error: null, @@ -630,6 +632,7 @@ const runSingleRequest = async function ( statusText: null, headers: null, data: null, + url: null, responseTime: 0 }, status: 'error', diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 078cc20c4..8e39e0d5c 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -901,6 +901,7 @@ const registerNetworkIpc = (mainWindow) => { dataBuffer: response.dataBuffer.toString('base64'), size: Buffer.byteLength(response.dataBuffer), duration: responseTime ?? 0, + url: response.request ? response.request.protocol + '//' + response.request.host + response.request.path : null, timeline: response.timeline }; } catch (error) { @@ -1208,6 +1209,7 @@ const registerNetworkIpc = (mainWindow) => { data: response.data, responseTime: response.responseTime, timeline: response.timeline, + url: response.request ? response.request.protocol + '//' + response.request.host + response.request.path : null }, ...eventData }); diff --git a/packages/bruno-js/src/bruno-response.js b/packages/bruno-js/src/bruno-response.js index 1705d606f..2a482c5e7 100644 --- a/packages/bruno-js/src/bruno-response.js +++ b/packages/bruno-js/src/bruno-response.js @@ -9,6 +9,7 @@ class BrunoResponse { this.headers = res ? res.headers : null; this.body = res ? res.data : null; this.responseTime = res ? res.responseTime : null; + this.url = res?.request ? res.request.protocol + '//' + res.request.host + res.request.path : null; // Make the instance callable const callable = (...args) => get(this.body, ...args); @@ -42,6 +43,10 @@ class BrunoResponse { return this.res ? this.res.responseTime : null; } + getUrl() { + return this.res ? this.url : null; + } + setBody(data) { if (!this.res) { return; 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 50aca92ac..df0fabe60 100644 --- a/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js +++ b/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js @@ -10,17 +10,20 @@ const addBrunoResponseShimToContext = (vm, res) => { const headers = marshallToVm(res?.headers, vm); const body = marshallToVm(res?.body, vm); const responseTime = marshallToVm(res?.responseTime, vm); + const url = marshallToVm(res?.url, vm); vm.setProp(resFn, 'status', status); vm.setProp(resFn, 'statusText', statusText); vm.setProp(resFn, 'headers', headers); vm.setProp(resFn, 'body', body); vm.setProp(resFn, 'responseTime', responseTime); + vm.setProp(resFn, 'url', url); status.dispose(); headers.dispose(); body.dispose(); responseTime.dispose(); + url.dispose(); statusText.dispose(); let getStatusText = vm.newFunction('getStatusText', function () { @@ -59,6 +62,12 @@ const addBrunoResponseShimToContext = (vm, res) => { vm.setProp(resFn, 'getResponseTime', getResponseTime); getResponseTime.dispose(); + let getUrl = vm.newFunction('getUrl', function () { + return marshallToVm(res.getUrl(), vm); + }); + vm.setProp(resFn, 'getUrl', getUrl); + getUrl.dispose(); + let setBody = vm.newFunction('setBody', function (data) { res.setBody(vm.dump(data)); }); diff --git a/packages/bruno-js/src/utils.js b/packages/bruno-js/src/utils.js index 7ebfa795a..ca26d6f4d 100644 --- a/packages/bruno-js/src/utils.js +++ b/packages/bruno-js/src/utils.js @@ -117,6 +117,7 @@ const createResponseParser = (response = {}) => { res.headers = response.headers; res.body = response.data; res.responseTime = response.responseTime; + res.url = response.request ? response.request.protocol + '//' + response.request.host + response.request.path : null; res.jq = (expr) => { const output = jsonQuery(expr, { data: response.data }); diff --git a/packages/bruno-tests/collection/scripting/api/res/getUrl.bru b/packages/bruno-tests/collection/scripting/api/res/getUrl.bru new file mode 100644 index 000000000..fc85436c5 --- /dev/null +++ b/packages/bruno-tests/collection/scripting/api/res/getUrl.bru @@ -0,0 +1,23 @@ +meta { + name: getUrl + type: http + seq: 1 +} + +get { + url: {{host}}/ping + body: none + auth: none +} + +assert { + res.status: eq 200 + res.body: eq pong +} + +tests { + test("res.getUrl()", function() { + const url = res.getUrl(); + expect(url).to.equal("https://testbench-sanity.usebruno.com/ping"); + }); +}