From 3dfb158382aad2d2a5b47f509862e944cc12d0c1 Mon Sep 17 00:00:00 2001 From: sanish-bruno Date: Fri, 9 May 2025 17:56:32 +0530 Subject: [PATCH] feat: add missing translations --- .../src/postman/postman-translations.js | 5 ++ .../src/utils/jscode-shift-translator.js | 31 ++++++- .../transpiler-tests/combined.test.js | 81 ++++++++++++++++++- .../legacy-tests-syntax.test.js | 4 +- .../transpiler-tests/response.test.js | 73 ++++++++++++++++- .../transpiler-tests/variables.test.js | 27 ++++++- 6 files changed, 211 insertions(+), 10 deletions(-) diff --git a/packages/bruno-converters/src/postman/postman-translations.js b/packages/bruno-converters/src/postman/postman-translations.js index 23195b5b8..0f9941e4f 100644 --- a/packages/bruno-converters/src/postman/postman-translations.js +++ b/packages/bruno-converters/src/postman/postman-translations.js @@ -20,6 +20,11 @@ const replacements = { 'pm\\.response\\.text\\(\\)': 'JSON.stringify(res.getBody())', 'pm\\.expect\\.fail\\(': 'expect.fail(', 'pm\\.response\\.responseTime': 'res.getResponseTime()', + 'pm\\.globals\\.set\\(': 'bru.setGlobalEnvVar(', + 'pm\\.globals\\.get\\(': 'bru.getGlobalEnvVar(', + 'pm\\.response\\.headers\\.get\\(': 'res.getHeader(', + 'pm\\.response\\.to\\.have\\.body\\(': 'expect(res.getBody()).to.equal(', + 'pm\\.response\\.to\\.have\\.header\\(': 'expect(Object.keys(res.getHeaders())).to.include(', 'pm\\.environment\\.name': 'bru.getEnvName()', 'pm\\.response\\.status': 'res.statusText', 'pm\\.response\\.headers': 'res.getHeaders()', diff --git a/packages/bruno-converters/src/utils/jscode-shift-translator.js b/packages/bruno-converters/src/utils/jscode-shift-translator.js index 924f4eb1d..04555b072 100644 --- a/packages/bruno-converters/src/utils/jscode-shift-translator.js +++ b/packages/bruno-converters/src/utils/jscode-shift-translator.js @@ -38,6 +38,10 @@ function getMemberExpressionString(node) { // Simple 1:1 translations for straightforward replacements const simpleTranslations = { + // Global Variables + 'pm.globals.get': 'bru.getGlobalEnvVar', + 'pm.globals.set': 'bru.setGlobalEnvVar', + // Environment variables 'pm.environment.get': 'bru.getEnvVar', 'pm.environment.set': 'bru.setEnvVar', @@ -124,7 +128,12 @@ const complexTransformations = [ return j.callExpression(j.identifier('JSON.stringify'), [j.identifier('res.getBody()')]); } }, - + { + pattern: 'pm.response.headers.get', + transform: (path, j) => { + return j.callExpression(j.identifier('res.getHeader'), path.parent.value.arguments); + } + }, // Handle pm.response.to.have.status { pattern: 'pm.response.to.have.status', @@ -191,6 +200,24 @@ const complexTransformations = [ } }, + // handle pm.response.to.have.body to expect(res.getBody()).to.equal(arg) + { + pattern: 'pm.response.to.have.body', + transform: (path, j) => { + const callExpr = path.parent.value; + + const args = callExpr.arguments; + + return j.callExpression( + j.memberExpression( + j.callExpression(j.identifier('expect'), [j.identifier('res.getBody()')]), + j.identifier('to.equal') + ), + args + ); + + } + }, // Handle pm.execution.setNextRequest(null) { @@ -225,7 +252,7 @@ complexTransformations.forEach(transform => { complexTransformationsMap[transform.pattern] = transform; }); -const varInitsToReplace = new Set(['pm', 'postman', 'pm.request','pm.response', 'pm.test', 'pm.expect', 'pm.environment', 'pm.variables', 'pm.collectionVariables', 'pm.execution']); +const varInitsToReplace = new Set(['pm', 'postman', 'pm.request','pm.response', 'pm.test', 'pm.expect', 'pm.environment', 'pm.variables', 'pm.collectionVariables', 'pm.execution', 'pm.globals']); /** * Process all transformations (both simple and complex) in the AST in a single pass diff --git a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/combined.test.js b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/combined.test.js index 8d3508e05..4916a10c0 100644 --- a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/combined.test.js +++ b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/combined.test.js @@ -411,8 +411,85 @@ describe('Combined API Features Translation', () => { `; const translatedCode = translateCode(code); expect(translatedCode).toBe(` - const globals = pm.globals; - const key = globals.get("key"); + const key = bru.getGlobalEnvVar("key"); `); }) + + it('should handle pm.response.to.have.body integrated with other assertions', () => { + const code = ` + pm.test("Response validation", function() { + pm.response.to.have.status(200); + pm.response.to.have.body({"success": true}); + pm.response.to.have.header("Content-Type", "application/json"); + }); + `; + const translatedCode = translateCode(code); + + const expectedOutput = ` + test("Response validation", function() { + expect(res.getStatus()).to.equal(200); + expect(res.getBody()).to.equal({"success": true}); + expect(res.getHeaders()).to.have.property("Content-Type".toLowerCase(), "application/json"); + }); + `; + expect(translatedCode).toBe(expectedOutput); + }); + + it('should handle pm.response.to.have.body with dynamic content', () => { + const code = ` + const expectedResponse = { + id: pm.environment.get("userId"), + token: pm.variables.get("authToken"), + timestamp: new Date().getTime() + }; + + pm.test("Dynamic response validation", function() { + pm.response.to.have.body(expectedResponse); + }); + `; + const translatedCode = translateCode(code); + + const expectedOutput = ` + const expectedResponse = { + id: bru.getEnvVar("userId"), + token: bru.getVar("authToken"), + timestamp: new Date().getTime() + }; + + test("Dynamic response validation", function() { + expect(res.getBody()).to.equal(expectedResponse); + }); + ` + expect(translatedCode).toBe(expectedOutput); + }); + + it('should handle pm.response.to.have.body in control structures', () => { + const code = ` + const jsonData = pm.response.json(); + + if (jsonData.status === "success") { + pm.response.to.have.body({ + status: "success", + data: jsonData.data + }); + } else { + pm.expect(jsonData.error).to.exist; + } + `; + const translatedCode = translateCode(code); + + const expectedOutput = ` + const jsonData = res.getBody(); + + if (jsonData.status === "success") { + expect(res.getBody()).to.equal({ + status: "success", + data: jsonData.data + }); + } else { + expect(jsonData.error).to.exist; + } + `; + expect(translatedCode).toBe(expectedOutput); + }); }); \ No newline at end of file diff --git a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/legacy-tests-syntax.test.js b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/legacy-tests-syntax.test.js index e548aa03c..34c6f32a6 100644 --- a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/legacy-tests-syntax.test.js +++ b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/legacy-tests-syntax.test.js @@ -27,7 +27,7 @@ describe('Legacy Tests[] Syntax Translation', () => { const translatedCode = translateCode(code); expect(translatedCode).toBe(` test("Content-Type is application/json", function() { - expect(Boolean(res.getHeaders().get("Content-Type") === "application/json")).to.be.true; + expect(Boolean(res.getHeader("Content-Type") === "application/json")).to.be.true; });`); }); @@ -273,7 +273,7 @@ describe('Legacy Tests[] Syntax Translation', () => { expect(translatedCode).toContain('test("Has content-type header", function() {'); expect(translatedCode).toContain('expect(Boolean(res.getHeaders().has("Content-Type"))).to.be.true;'); expect(translatedCode).toContain('test("Content-Type is JSON", function() {'); - expect(translatedCode).toContain('expect(Boolean(res.getHeaders().get("Content-Type").includes("application/json"))).to.be.true;'); + expect(translatedCode).toContain('expect(Boolean(res.getHeader("Content-Type").includes("application/json"))).to.be.true;'); expect(translatedCode).toContain('const expectedItems = parseInt(bru.getEnvVar("expectedItemCount"));'); expect(translatedCode).toContain('test("Has correct number of items", function() {'); expect(translatedCode).toContain('expect(Boolean(response.items.length === expectedItems)).to.be.true;'); diff --git a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/response.test.js b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/response.test.js index 7fd4d902b..3a1e45dbc 100644 --- a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/response.test.js +++ b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/response.test.js @@ -32,6 +32,12 @@ describe('Response Translation', () => { expect(translatedCode).toBe('console.log("Status text:", res.statusText);'); }); + it('should translate pm.response.headers', () => { + const code = 'console.log("Headers:", pm.response.headers);'; + const translatedCode = translateCode(code); + expect(translatedCode).toBe('console.log("Headers:", res.getHeaders());'); + }); + // Complex response transformations it('should transform pm.response.to.have.status', () => { const code = 'pm.response.to.have.status(201);'; @@ -178,6 +184,17 @@ describe('Response Translation', () => { `); }); + it('should translate response.headers', () => { + const code = ` + const resp = pm.response; + const headers = resp.headers; + `; + const translatedCode = translateCode(code); + expect(translatedCode).toBe(` + const headers = res.getHeaders(); + `); + }); + it('should translate pm.response.statusText', () => { const code = ` const resp = pm.response; @@ -296,8 +313,8 @@ describe('Response Translation', () => { const translatedCode = translateCode(code); // Check how header access is translated - expect(translatedCode).toContain('const contentType = res.getHeaders().get(\'Content-Type\');'); - expect(translatedCode).toContain('const contentLength = res.getHeaders().get(\'Content-Length\');'); + expect(translatedCode).toContain('const contentType = res.getHeader(\'Content-Type\');'); + expect(translatedCode).toContain('const contentLength = res.getHeader(\'Content-Length\');'); expect(translatedCode).toContain('console.log("contentType", contentType);'); expect(translatedCode).toContain('console.log("contentLength", contentLength);'); expect(translatedCode).not.toContain('pm.test') @@ -340,7 +357,7 @@ describe('Response Translation', () => { const translatedCode = translateCode(code); expect(translatedCode).toContain('if (res.getStatus() >= 200 && res.getStatus() < 300) {'); - expect(translatedCode).toContain('if (res.getHeaders().get(\'Content-Type\').includes(\'application/json\')) {'); + expect(translatedCode).toContain('if (res.getHeader(\'Content-Type\').includes(\'application/json\')) {'); expect(translatedCode).toContain('const data = res.getBody();'); expect(translatedCode).toContain('bru.setEnvVar("authToken", data.token);'); expect(translatedCode).toContain('} else if (res.getStatus() === 404) {'); @@ -486,4 +503,54 @@ describe('Response Translation', () => { expect(translatedCode).toContain('checkHeaderPresent("Authorization");'); expect(translatedCode).toContain('validateHeader("Content-Type", "application/json");'); }); + + it('should transform pm.response.to.have.body with string literal', () => { + const code = 'pm.response.to.have.body("Expected response body");'; + const translatedCode = translateCode(code); + expect(translatedCode).toBe('expect(res.getBody()).to.equal("Expected response body");'); + }); + + it('should transform pm.response.to.have.body with variable parameter', () => { + const code = ` + const expectedBody = {"status": "success", "data": [1, 2, 3]}; + pm.response.to.have.body(expectedBody); + `; + const translatedCode = translateCode(code); + expect(translatedCode).toContain('const expectedBody = {"status": "success", "data": [1, 2, 3]};'); + expect(translatedCode).toContain('expect(res.getBody()).to.equal(expectedBody);'); + }); + + it('should transform pm.response.to.have.body with JSON object', () => { + const code = `pm.response.to.have.body({"status": "success", "message": "Operation completed"});`; + const translatedCode = translateCode(code); + expect(translatedCode).toBe('expect(res.getBody()).to.equal({"status": "success", "message": "Operation completed"});'); + }); + + it('should transform pm.response.to.have.body inside test function', () => { + const code = ` + pm.test("Response body validation", function() { + const expectedResponse = {"result": true}; + pm.response.to.have.body(expectedResponse); + }); + `; + const translatedCode = translateCode(code); + const expectedOutput = ` + test("Response body validation", function() { + const expectedResponse = {"result": true}; + expect(res.getBody()).to.equal(expectedResponse); + }); + ` + expect(translatedCode).toBe(expectedOutput); + }); + + it('should transform pm.response.to.have.body with response alias', () => { + const code = ` + const resp = pm.response; + resp.to.have.body({"status": "ok"}); + `; + const translatedCode = translateCode(code); + expect(translatedCode).toBe(` + expect(res.getBody()).to.equal({"status": "ok"}); + `); + }); }); \ No newline at end of file diff --git a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/variables.test.js b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/variables.test.js index b704e4a7e..b4439f826 100644 --- a/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/variables.test.js +++ b/packages/bruno-converters/tests/postman/postman-translations/transpiler-tests/variables.test.js @@ -45,6 +45,18 @@ describe('Variables Translation', () => { expect(translatedCode).toBe('bru.deleteVar("tempVar");'); }); + it('should handle pm.globals.get', () => { + const code = 'pm.globals.get("test");'; + const translatedCode = translateCode(code); + expect(translatedCode).toBe('bru.getGlobalEnvVar("test");'); + }); + + it('should handle pm.globals.set', () => { + const code = 'pm.globals.set("test", "value");'; + const translatedCode = translateCode(code); + expect(translatedCode).toBe('bru.setGlobalEnvVar("test", "value");'); + }); + // Alias tests for variables it('should handle variables aliases', () => { const code = ` @@ -79,6 +91,19 @@ describe('Variables Translation', () => { `); }); + it('should handle pm.globals aliases', () => { + const code = ` + const globals = pm.globals; + const get = globals.get("test"); + const set = globals.set("test", "value"); + `; + const translatedCode = translateCode(code); + expect(translatedCode).toBe(` + const get = bru.getGlobalEnvVar("test"); + const set = bru.setGlobalEnvVar("test", "value"); + `); + }) + // Combined tests it('should handle conditional expressions with variable calls', () => { const code = 'const userStatus = pm.variables.has("userId") ? "logged-in" : "guest";'; @@ -124,5 +149,5 @@ describe('Variables Translation', () => { const code = 'pm.collectionVariables.set("fullPath", pm.environment.get("baseUrl") + pm.variables.get("endpoint"));'; const translatedCode = translateCode(code); expect(translatedCode).toBe('bru.setVar("fullPath", bru.getEnvVar("baseUrl") + bru.getVar("endpoint"));'); - }); + }); }); \ No newline at end of file