From a4b1941817179af5eeffae053fb8f1b85ef2c55a Mon Sep 17 00:00:00 2001 From: lohit Date: Fri, 17 Oct 2025 18:22:43 +0530 Subject: [PATCH] fix(bru-2035): form-urlencoded logic updates (#5820) --- .../src/runner/run-single-request.js | 12 +- packages/bruno-cli/src/utils/form-data.js | 19 --- .../bruno-common/src/utils/form-data.spec.ts | 112 ++++++++++++++++++ packages/bruno-common/src/utils/form-data.ts | 33 ++++++ packages/bruno-common/src/utils/index.ts | 6 +- .../bruno-electron/src/ipc/network/index.js | 18 ++- .../src/ipc/network/prepare-request.js | 1 - .../bruno-electron/src/utils/form-data.js | 19 --- .../tests/network/prepare-request.spec.js | 60 ---------- .../collection/echo/echo form-url-encoded.bru | 23 +++- .../setBody/form-urlencoded/array body.bru | 66 +++++++++++ .../content-type via setHeader.bru | 41 +++++++ .../req/setBody/form-urlencoded/folder.bru | 8 ++ .../setBody/form-urlencoded/object body.bru | 37 ++++++ .../setBody/form-urlencoded/string body.bru | 32 +++++ 15 files changed, 375 insertions(+), 112 deletions(-) create mode 100644 packages/bruno-common/src/utils/form-data.spec.ts create mode 100644 packages/bruno-common/src/utils/form-data.ts create mode 100644 packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/array body.bru create mode 100644 packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/content-type via setHeader.bru create mode 100644 packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/folder.bru create mode 100644 packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/object body.bru create mode 100644 packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/string body.bru diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index a196cf8a7..171a1a659 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -19,13 +19,13 @@ const { shouldUseProxy, PatchedHttpsProxyAgent, getSystemProxyEnvVariables } = r const path = require('path'); const { parseDataFromResponse } = require('../utils/common'); const { getCookieStringForUrl, saveCookies } = require('../utils/cookies'); -const { createFormData, buildFormUrlEncodedPayload } = require('../utils/form-data'); +const { createFormData } = require('../utils/form-data'); const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; const { NtlmClient } = require('axios-ntlm'); const { addDigestInterceptor } = require('@usebruno/requests'); const { getCACertificates } = require('@usebruno/requests'); const { getOAuth2Token } = require('../utils/oauth2'); -const { encodeUrl } = require('@usebruno/common').utils; +const { encodeUrl, buildFormUrlEncodedPayload } = require('@usebruno/common').utils; const onConsoleLog = (type, args) => { console[type](...args); @@ -332,8 +332,14 @@ const runSingleRequest = async function ( const contentTypeHeader = Object.keys(request.headers).find( name => name.toLowerCase() === 'content-type' ); + if (contentTypeHeader && request.headers[contentTypeHeader] === 'application/x-www-form-urlencoded') { - request.data = buildFormUrlEncodedPayload(request.data); + if (Array.isArray(request.data)) { + request.data = buildFormUrlEncodedPayload(request.data); + } else if (typeof request.data !== 'string') { + request.data = qs.stringify(request.data, { arrayFormat: 'repeat' }); + } + // if `data` is of string type - return as-is (assumes already encoded) } if (contentTypeHeader && request.headers[contentTypeHeader] === 'multipart/form-data') { diff --git a/packages/bruno-cli/src/utils/form-data.js b/packages/bruno-cli/src/utils/form-data.js index 5741d794e..eab5d5824 100644 --- a/packages/bruno-cli/src/utils/form-data.js +++ b/packages/bruno-cli/src/utils/form-data.js @@ -3,24 +3,6 @@ const FormData = require('form-data'); const fs = require('fs'); const path = require('path'); -/** - * @param {Array.} params The request body Array - * @returns {string} Returns a order respecting standard compliant string of form encoded values - */ -const buildFormUrlEncodedPayload = (params) => { - if (typeof params !== 'object') return ''; - if (!Array.isArray(params)) return ''; - const resultParams = new URLSearchParams(); - for (const param of params) { - // Invalid items are ignored - if (typeof param !== 'object') continue; - if (!('name' in param)) continue; - resultParams.append(param.name, param.value ?? ''); - } - return resultParams.toString(); -}; - - const createFormData = (data, collectionPath) => { // make axios work in node using form data // reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427 @@ -56,6 +38,5 @@ const createFormData = (data, collectionPath) => { }; module.exports = { - buildFormUrlEncodedPayload, createFormData } \ No newline at end of file diff --git a/packages/bruno-common/src/utils/form-data.spec.ts b/packages/bruno-common/src/utils/form-data.spec.ts new file mode 100644 index 000000000..060cc4bf5 --- /dev/null +++ b/packages/bruno-common/src/utils/form-data.spec.ts @@ -0,0 +1,112 @@ +import { describe, it, expect } from '@jest/globals'; +import { buildFormUrlEncodedPayload } from './form-data'; + +describe('buildFormUrlEncodedPayload', () => { + it('should handle single key-value pair', () => { + const requestObj = [{ name: 'item', value: 2 }]; + const expected = 'item=2'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should handle multiple key-value pairs with unique keys', () => { + const requestObj = [ + { name: 'item1', value: 2 }, + { name: 'item2', value: 3 } + ]; + const expected = 'item1=2&item2=3'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should handle multiple key-value pairs with the same key', () => { + const requestObj = [ + { name: 'item', value: 2 }, + { name: 'item', value: 3 } + ]; + const expected = 'item=2&item=3'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should handle mixed key-value pairs with unique and duplicate keys', () => { + const requestObj = [ + { name: 'item1', value: 2 }, + { name: 'item2', value: 3 }, + { name: 'item1', value: 4 } + ]; + const expected = 'item1=2&item2=3&item1=4'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should handle empty array', () => { + const result = buildFormUrlEncodedPayload([]); + expect(result).toEqual(''); + }); + + it('should handle array with undefined and null values', () => { + const requestObj = [ + { name: 'item1', value: undefined }, + { name: 'item2', value: null as any }, + { name: 'item3', value: '' }, + { name: 'item4', value: 0 } + ]; + const expected = 'item1=&item2=&item3=&item4=0'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should handle array with special characters in names and values', () => { + const requestObj = [ + { name: 'item with spaces', value: 'value with spaces' }, + { name: 'item&special', value: 'value&special' }, + { name: 'item=equals', value: 'value=equals' }, + { name: 'item%percent', value: 'value%percent' } + ]; + const expected = 'item+with+spaces=value+with+spaces&item%26special=value%26special&item%3Dequals=value%3Dequals&item%25percent=value%25percent'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should handle array with numeric and boolean values', () => { + const requestObj = [ + { name: 'number', value: 42 }, + { name: 'float', value: 3.14 }, + { name: 'boolean_true', value: true }, + { name: 'boolean_false', value: false } + ]; + const expected = 'number=42&float=3.14&boolean_true=true&boolean_false=false'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should preserve parameter order in array format', () => { + const requestObj = [ + { name: 'z', value: '1' }, + { name: 'a', value: '2' }, + { name: 'm', value: '3' } + ]; + const expected = 'z=1&a=2&m=3'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); + + it('should ignore invalid items inside params array', () => { + const requestObj: any[] = [ + { name: 'item1', value: 'a' }, + 'not-an-object', + { value: 'missingName' }, + 42, + { name: 'item2', value: 'b' }, + { name: 'item3' }, // missing value should default to empty string + null, + undefined, + { name: '', value: 'empty_name' }, // empty name should still work + { name: 'valid', value: 'c' } + ]; + const expected = 'item1=a&item2=b&item3=&=empty_name&valid=c'; + const result = buildFormUrlEncodedPayload(requestObj); + expect(result).toEqual(expected); + }); +}); diff --git a/packages/bruno-common/src/utils/form-data.ts b/packages/bruno-common/src/utils/form-data.ts new file mode 100644 index 000000000..91516a52f --- /dev/null +++ b/packages/bruno-common/src/utils/form-data.ts @@ -0,0 +1,33 @@ +/** + * Builds a URL-encoded payload from various data formats + * + * This function handles multiple input formats: + * - Array of objects with 'name' and 'value' properties (preserves order) + * + * @param data The request body data + * @returns URL-encoded string suitable for application/x-www-form-urlencoded content type + * + * @example + * // Array format (preserves order) + * buildFormUrlEncodedPayload([{name: 'a', value: '1'}, {name: 'b', value: '2'}]) + * // Returns: 'a=1&b=2' + */ +export const buildFormUrlEncodedPayload = (params: Array<{ name: string; value: string | number | boolean | undefined }>): string => { + // Ensure params is iterable (array) + if (!Array.isArray(params)) { + return ''; + } + + const resultParams = new URLSearchParams(); + + for (const param of params) { + // Invalid items are ignored + if (typeof param !== 'object' || param === null) continue; + if (!('name' in param)) continue; + + // Append parameter with value (default to empty string if undefined/null) + resultParams.append(param.name, String(param.value ?? '')); + } + + return resultParams.toString(); +}; diff --git a/packages/bruno-common/src/utils/index.ts b/packages/bruno-common/src/utils/index.ts index eee1e5d9b..f20eab9a4 100644 --- a/packages/bruno-common/src/utils/index.ts +++ b/packages/bruno-common/src/utils/index.ts @@ -2,4 +2,8 @@ export { encodeUrl, parseQueryParams, buildQueryString, -} from './url'; \ No newline at end of file +} from './url'; + +export { + buildFormUrlEncodedPayload +} from './form-data'; diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index a8f736b08..e075c56b9 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -1,7 +1,7 @@ -const qs = require('qs'); const https = require('https'); const axios = require('axios'); const path = require('path'); +const qs = require('qs'); const decomment = require('decomment'); const contentDispositionParser = require('content-disposition'); const mime = require('mime-types'); @@ -23,7 +23,7 @@ const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../util const { uuid, safeStringifyJSON, safeParseJSON, parseDataFromResponse, parseDataFromRequest } = require('../../utils/common'); const { chooseFileToSave, writeBinaryFile, writeFile } = require('../../utils/filesystem'); const { addCookieToJar, getDomainsWithCookies, getCookieStringForUrl } = require('../../utils/cookies'); -const { createFormData, buildFormUrlEncodedPayload } = require('../../utils/form-data'); +const { createFormData } = require('../../utils/form-data'); const { findItemInCollectionByPathname, sortFolder, getAllRequestsInFolderRecursively, getEnvVars, getTreePathFromCollectionToItem, mergeVars, sortByNameThenSequence } = require('../../utils/collection'); const { getOAuth2TokenUsingAuthorizationCode, getOAuth2TokenUsingClientCredentials, getOAuth2TokenUsingPasswordCredentials, getOAuth2TokenUsingImplicitGrant, updateCollectionOauth2Credentials } = require('../../utils/oauth2'); const { preferencesUtil } = require('../../store/preferences'); @@ -35,6 +35,7 @@ const { cookiesStore } = require('../../store/cookies'); const registerGrpcEventHandlers = require('./grpc-event-handlers'); const { registerWsEventHandlers } = require('./ws-event-handlers'); const { getCertsAndProxyConfig } = require('./cert-utils'); +const { buildFormUrlEncodedPayload } = require('@usebruno/common').utils; const ERROR_OCCURRED_WHILE_EXECUTING_REQUEST = 'Error occurred while executing the request!'; @@ -423,11 +424,18 @@ const registerNetworkIpc = (mainWindow) => { } // stringify the request url encoded params - if (request.headers['content-type'] === 'application/x-www-form-urlencoded') { - request.data = buildFormUrlEncodedPayload(request.data); + const contentTypeHeader = Object.keys(request.headers).find((name) => name.toLowerCase() === 'content-type'); + + if (contentTypeHeader && request.headers[contentTypeHeader] === 'application/x-www-form-urlencoded') { + if (Array.isArray(request.data)) { + request.data = buildFormUrlEncodedPayload(request.data); + } else if (typeof request.data !== 'string') { + request.data = qs.stringify(request.data, { arrayFormat: 'repeat' }); + } + // if `data` is of string type - return as-is (assumes already encoded) } - if (request.headers['content-type'] === 'multipart/form-data') { + if (contentTypeHeader && request.headers[contentTypeHeader] === 'multipart/form-data') { if (!(request.data instanceof FormData)) { request._originalMultipartData = request.data; request.collectionPath = collectionPath; diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 01c11a27e..514c7b92e 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -3,7 +3,6 @@ const decomment = require('decomment'); const crypto = require('node:crypto'); const fs = require('node:fs'); const { getTreePathFromCollectionToItem, mergeHeaders, mergeScripts, mergeVars, getFormattedCollectionOauth2Credentials, mergeAuth } = require('../../utils/collection'); -const { buildFormUrlEncodedPayload } = require('../../utils/form-data'); const path = require('node:path'); const { isLargeFile } = require('../../utils/filesystem'); diff --git a/packages/bruno-electron/src/utils/form-data.js b/packages/bruno-electron/src/utils/form-data.js index fe53c31cc..9bff10442 100644 --- a/packages/bruno-electron/src/utils/form-data.js +++ b/packages/bruno-electron/src/utils/form-data.js @@ -3,24 +3,6 @@ const FormData = require('form-data'); const fs = require('fs'); const path = require('path'); -/** - * @param {Array.} params The request body Array - * @returns {string} Returns a order respecting standard compliant string of form encoded values - */ -const buildFormUrlEncodedPayload = (params) => { - if (typeof params !== 'object') return ''; - if (!Array.isArray(params)) return ''; - const resultParams = new URLSearchParams(); - for (const param of params) { - // Invalid items are ignored - if (typeof param !== 'object') continue; - if (!('name' in param)) continue; - resultParams.append(param.name, param.value ?? ''); - } - return resultParams.toString(); -}; - - const createFormData = (data, collectionPath) => { // make axios work in node using form data // reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427 @@ -56,6 +38,5 @@ const createFormData = (data, collectionPath) => { }; 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 96af32f3c..ec14ad3c0 100644 --- a/packages/bruno-electron/tests/network/prepare-request.spec.js +++ b/packages/bruno-electron/tests/network/prepare-request.spec.js @@ -1,7 +1,6 @@ const { describe, it, expect } = require('@jest/globals'); const { prepareRequest } = require('../../src/ipc/network/prepare-request'); -const { buildFormUrlEncodedPayload } = require('../../src/utils/form-data'); describe('prepare-request: prepareRequest', () => { describe('Decomments request body', () => { @@ -20,65 +19,6 @@ describe('prepare-request: prepareRequest', () => { const result = await prepareRequest({ request: { body }, collection: { pathname: '' } }); expect(result.data).toEqual(expected); }); - - it('should handle single key-value pair', () => { - const requestObj = [{ name: 'item', value: 2 }]; - const expected = 'item=2'; - const result = buildFormUrlEncodedPayload(requestObj); - expect(result).toEqual(expected); - }); - - it('should handle multiple key-value pairs with unique keys', () => { - const requestObj = [ - { name: 'item1', value: 2 }, - { name: 'item2', value: 3 } - ]; - const expected = 'item1=2&item2=3'; - const result = buildFormUrlEncodedPayload(requestObj); - expect(result).toEqual(expected); - }); - - it('should handle multiple key-value pairs with the same key', () => { - const requestObj = [ - { name: 'item', value: 2 }, - { name: 'item', value: 3 } - ]; - const expected = 'item=2&item=3'; - const result = buildFormUrlEncodedPayload(requestObj); - expect(result).toEqual(expected); - }); - - it('should handle mixed key-value pairs with unique and duplicate keys', () => { - const requestObj = [ - { name: 'item1', value: 2 }, - { name: 'item2', value: 3 }, - { name: 'item1', value: 4 } - ]; - const expected = 'item1=2&item2=3&item1=4'; - const result = buildFormUrlEncodedPayload(requestObj); - expect(result).toEqual(expected); - }); - - it('returns empty string when params is not an object', () => { - expect(buildFormUrlEncodedPayload(null)).toEqual(''); - expect(buildFormUrlEncodedPayload('string')).toEqual(''); - expect(buildFormUrlEncodedPayload(123)).toEqual(''); - expect(buildFormUrlEncodedPayload(undefined)).toEqual(''); - }); - - it('ignores invalid items inside params array', () => { - const requestObj = [ - { name: 'item1', value: 'a' }, - 'not-an-object', - { value: 'missingName' }, - 42, - { name: 'item2', value: 'b' }, - { name: 'item3' } - ]; - const expected = 'item1=a&item2=b&item3='; - const result = buildFormUrlEncodedPayload(requestObj); - expect(result).toEqual(expected); - }); }); describe.each(['POST', 'PUT', 'PATCH'])('POST request with no body', (method) => { diff --git a/packages/bruno-tests/collection/echo/echo form-url-encoded.bru b/packages/bruno-tests/collection/echo/echo form-url-encoded.bru index 7c0ce77eb..566d7134c 100644 --- a/packages/bruno-tests/collection/echo/echo form-url-encoded.bru +++ b/packages/bruno-tests/collection/echo/echo form-url-encoded.bru @@ -13,10 +13,10 @@ post { body:form-urlencoded { form-data-key: {{form-data-key}} form-data-stringified-object: {{form-data-stringified-object}} -} - -assert { - res.body: eq form-data-key=form-data-value&form-data-stringified-object=%7B%22foo%22%3A123%7D + key_1: value_1 + key_2: value_2 + key_1: value_3 + key_2: value_4 } script:pre-request { @@ -24,3 +24,18 @@ script:pre-request { bru.setVar('form-data-key', 'form-data-value'); bru.setVar('form-data-stringified-object', obj); } + +tests { + test("form-urlencoded body with variables and duplicate keys", function() { + const expected = [ + "form-data-key=form-data-value", + "form-data-stringified-object=%7B%22foo%22%3A123%7D", // {"foo":123} URL encoded + "key_1=value_1", + "key_2=value_2", + "key_1=value_3", // duplicate key with different value + "key_2=value_4" // duplicate key with different value + ].join("&"); + + expect(res.getBody()).to.eql(expected); + }); +} \ No newline at end of file diff --git a/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/array body.bru b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/array body.bru new file mode 100644 index 000000000..79b6c4257 --- /dev/null +++ b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/array body.bru @@ -0,0 +1,66 @@ +meta { + name: array body + type: http + seq: 8 +} + +post { + url: {{echo-host}} + body: formUrlEncoded + auth: inherit +} + +script:pre-request { + req.setBody([ + {name: "empty", value: ""}, + {name: "null", value: null}, + {name: "undefined", value: undefined}, + {name: "zero", value: 0}, + {name: "false", value: false}, + {name: "", value: "empty_key"}, + {name: "key", value: "value1"}, + {name: "name", value: "bruno"}, + {name: "key", value: "value2"}, + ]); +} + +tests { + test("req.setBody() with edge cases - request body", function() { + const data = req.getBody(); + const expected = [ + "empty=", + "null=", + "undefined=", + "zero=0", + "false=false", + "=empty_key", + "key=value1", + "name=bruno", + "key=value2" + ].join("&"); + + expect(data).to.eql(expected); + }); + + test("req.setBody() with edge cases - response body", function() { + const data = res.getBody(); + const expected = [ + "empty=", + "null=", + "undefined=", + "zero=0", + "false=false", + "=empty_key", + "key=value1", + "name=bruno", + "key=value2" + ].join("&"); + + expect(data).to.eql(expected); + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/content-type via setHeader.bru b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/content-type via setHeader.bru new file mode 100644 index 000000000..e0d532497 --- /dev/null +++ b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/content-type via setHeader.bru @@ -0,0 +1,41 @@ +meta { + name: content-type via setHeader + type: http + seq: 7 +} + +post { + url: {{echo-host}} + body: none + auth: inherit +} + +script:pre-request { + req.setHeader('content-type', 'application/x-www-form-urlencoded'); + req.setBody([ + {name: "key", value: "value"}, + {name: "name", value: "bruno"} + ]); +} + +tests { + test("req.setBody() - request body", function() { + const data = req.getBody(); + expect(data).to.eql("key=value&name=bruno"); + }); + + test("req.setBody() - response body", function() { + const data = res.getBody(); + expect(data).to.eql("key=value&name=bruno"); + }); + + test("Content-Type header is set correctly", function() { + const contentType = req.getHeader('content-type'); + expect(contentType).to.eql('application/x-www-form-urlencoded'); + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/folder.bru b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/folder.bru new file mode 100644 index 000000000..df646c541 --- /dev/null +++ b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/folder.bru @@ -0,0 +1,8 @@ +meta { + name: form-urlencoded + seq: 1 +} + +auth { + mode: inherit +} diff --git a/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/object body.bru b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/object body.bru new file mode 100644 index 000000000..87125ff7f --- /dev/null +++ b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/object body.bru @@ -0,0 +1,37 @@ +meta { + name: object body + type: http + seq: 1 +} + +post { + url: {{echo-host}} + body: formUrlEncoded + auth: inherit +} + +script:pre-request { + req.setBody({ + "key": "value with spaces", + "name": "bruno", + "array": ["test", "value"], + }); +} + +tests { + // https://github.com/usebruno/bruno/issues/5813 + test("req.setBody() with object - request body", function() { + const data = req.getBody(); + expect(data).to.eql("key=value%20with%20spaces&name=bruno&array=test&array=value"); + }); + + test("req.setBody() with object - response body", function() { + const data = res.getBody(); + expect(data).to.eql("key=value%20with%20spaces&name=bruno&array=test&array=value"); + }); +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/string body.bru b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/string body.bru new file mode 100644 index 000000000..674923a54 --- /dev/null +++ b/packages/bruno-tests/collection/scripting/api/req/setBody/form-urlencoded/string body.bru @@ -0,0 +1,32 @@ +meta { + name: string body + type: http + seq: 3 +} + +post { + url: {{echo-host}} + body: formUrlEncoded + auth: inherit +} + +script:pre-request { + req.setBody("key=value&name=bruno"); +} + +tests { + test("req.setBody() with string format - request body", function() { + const data = req.getBody(); + expect(data).to.eql("key=value&name=bruno"); + }); + + test("req.setBody() with string format - response body", function() { + const data = res.getBody(); + expect(data).to.eql("key=value&name=bruno"); + }); +} + +settings { + encodeUrl: true + timeout: 0 +}