Skip to content

Fix/add missing translations #4637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -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(res.getHeaders()).to.have.property(',
'pm\\.environment\\.name': 'bru.getEnvName()',
'pm\\.response\\.status': 'res.statusText',
'pm\\.response\\.headers': 'res.getHeaders()',
Expand Down
31 changes: 29 additions & 2 deletions packages/bruno-converters/src/utils/jscode-shift-translator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});`);
});

Expand Down Expand Up @@ -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;');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);';
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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) {');
Expand Down Expand Up @@ -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"});
`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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 = `
Expand Down Expand Up @@ -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";';
Expand Down Expand Up @@ -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"));');
});
});
});