mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-11 09:51:30 +00:00
feat: add translations for direct cookie access methods (#7070)
* feat: add translations for direct cookie access methods - Implement translations for pm.cookies.has, pm.cookies.get, and pm.cookies.toObject to their corresponding bru.cookies methods. - Enhance the postman-to-bruno translator to handle these new cookie access patterns. - Add unit tests to verify the correct conversion of cookie access methods in various scenarios. * refactor: simplify optional member expression handling in postman-to-bruno translator - Streamlined the code for handling optional member expressions in the translation of cookie access methods. - Updated unit test to verify the correct output format for pm.cookies.toObject() conversion. * refactor: enhance handling of await expressions in cookie translations - Updated the postman-to-bruno translator to wrap await expressions in parentheses for improved clarity and consistency. - Adjusted unit tests to reflect the new output format for cookie access methods, ensuring accurate translation of pm.cookies.get calls. * refactor: update cookie access translations to use hasCookie method - Modified translations for pm.cookies.has to utilize the new bru.cookies.hasCookie method for improved clarity and functionality. - Updated related unit tests to reflect changes in expected output for cookie existence checks. - Added new tests to validate the behavior of the hasCookie method in various scenarios.
This commit is contained in:
@@ -68,6 +68,10 @@ const replacements = {
|
||||
'pm\\.execution\\.skipRequest': 'bru.runner.skipRequest',
|
||||
'pm\\.execution\\.setNextRequest\\(null\\)': 'bru.runner.stopExecution()',
|
||||
'pm\\.execution\\.setNextRequest\\(\'null\'\\)': 'bru.runner.stopExecution()',
|
||||
// Direct cookie access translations (pm.cookies.has/get/toObject)
|
||||
'pm\\.cookies\\.has\\(([^)]+)\\)': 'await bru.cookies.jar().hasCookie(req.getUrl(), $1)',
|
||||
'pm\\.cookies\\.get\\(([^)]+)\\)': '(await bru.cookies.jar().getCookie(req.getUrl(), $1))?.value',
|
||||
'pm\\.cookies\\.toObject\\(\\)': '(await bru.cookies.jar().getCookies(req.getUrl())).reduce((obj, c) => ({...obj, [c.key]: c.value}), {})',
|
||||
// Cookie jar translations
|
||||
'pm\\.cookies\\.jar\\(\\)': 'bru.cookies.jar()',
|
||||
'pm\\.cookies\\.jar\\(\\)\\.get\\(': 'bru.cookies.jar().getCookie(',
|
||||
|
||||
@@ -240,6 +240,94 @@ const complexTransformations = [
|
||||
args
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// pm.cookies.has(name) → await bru.cookies.jar().hasCookie(req.getUrl(), name)
|
||||
{
|
||||
pattern: 'pm.cookies.has',
|
||||
transform: (path, j) => {
|
||||
const callExpr = path.parent.value;
|
||||
const args = callExpr.arguments;
|
||||
|
||||
const hasCookieCall = j.callExpression(
|
||||
j.identifier('bru.cookies.jar().hasCookie'),
|
||||
[j.identifier('req.getUrl()'), ...args]
|
||||
);
|
||||
|
||||
return j.awaitExpression(hasCookieCall);
|
||||
}
|
||||
},
|
||||
|
||||
// pm.cookies.get(name) → (await bru.cookies.jar().getCookie(req.getUrl(), name))?.value
|
||||
{
|
||||
pattern: 'pm.cookies.get',
|
||||
transform: (path, j) => {
|
||||
const callExpr = path.parent.value;
|
||||
const args = callExpr.arguments;
|
||||
|
||||
const getCookieCall = j.callExpression(
|
||||
j.identifier('bru.cookies.jar().getCookie'),
|
||||
[j.identifier('req.getUrl()'), ...args]
|
||||
);
|
||||
|
||||
const awaitExpr = j.awaitExpression(getCookieCall);
|
||||
const parenAwait = j.parenthesizedExpression
|
||||
? j.parenthesizedExpression(awaitExpr)
|
||||
: awaitExpr;
|
||||
|
||||
return j.optionalMemberExpression(
|
||||
parenAwait,
|
||||
j.identifier('value'),
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
// pm.cookies.toObject() → (await bru.cookies.jar().getCookies(req.getUrl())).reduce((obj, c) => ({...obj, [c.key]: c.value}), {})
|
||||
{
|
||||
pattern: 'pm.cookies.toObject',
|
||||
transform: (path, j) => {
|
||||
const getCookiesCall = j.callExpression(
|
||||
j.identifier('bru.cookies.jar().getCookies'),
|
||||
[j.identifier('req.getUrl()')]
|
||||
);
|
||||
|
||||
const awaitExpr = j.awaitExpression(getCookiesCall);
|
||||
|
||||
// Build the reduce callback: (obj, c) => ({...obj, [c.key]: c.value})
|
||||
const objParam = j.identifier('obj');
|
||||
const cParam = j.identifier('c');
|
||||
|
||||
const spreadElement = j.spreadElement(objParam);
|
||||
const computedProp = j.property(
|
||||
'init',
|
||||
j.memberExpression(cParam, j.identifier('key')),
|
||||
j.memberExpression(cParam, j.identifier('value'))
|
||||
);
|
||||
computedProp.computed = true;
|
||||
|
||||
const objectExpr = j.objectExpression([spreadElement, computedProp]);
|
||||
|
||||
const arrowBody = j.parenthesizedExpression
|
||||
? j.parenthesizedExpression(objectExpr)
|
||||
: objectExpr;
|
||||
|
||||
const reduceFn = j.arrowFunctionExpression(
|
||||
[objParam, cParam],
|
||||
arrowBody
|
||||
);
|
||||
reduceFn.expression = true;
|
||||
|
||||
// Build: (await ...).reduce(fn, {})
|
||||
return j.callExpression(
|
||||
j.memberExpression(
|
||||
awaitExpr,
|
||||
j.identifier('reduce')
|
||||
),
|
||||
[reduceFn, j.objectExpression([])]
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -249,7 +337,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', 'pm.globals']);
|
||||
const varInitsToReplace = new Set(['pm', 'postman', 'pm.request', 'pm.response', 'pm.test', 'pm.expect', 'pm.environment', 'pm.variables', 'pm.collectionVariables', 'pm.execution', 'pm.globals', 'pm.cookies']);
|
||||
|
||||
/**
|
||||
* Process all transformations (both simple and complex) in the AST in a single pass
|
||||
|
||||
@@ -316,4 +316,57 @@ describe('postmanTranslations - cookie API conversions', () => {
|
||||
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
// Tests for pm.cookies direct access methods (has, get, toObject)
|
||||
|
||||
test('should convert pm.cookies.has(name) to await hasCookie', () => {
|
||||
const inputScript = `pm.cookies.has('token')`;
|
||||
const expectedOutput = `await bru.cookies.jar().hasCookie(req.getUrl(), 'token')`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should convert pm.cookies.get(name) to await getCookie?.value', () => {
|
||||
const inputScript = `pm.cookies.get('token')`;
|
||||
const expectedOutput = `(await bru.cookies.jar().getCookie(req.getUrl(), 'token'))?.value`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should convert pm.cookies.toObject() to getCookies reduce', () => {
|
||||
const inputScript = `pm.cookies.toObject()`;
|
||||
const expectedOutput = `(await bru.cookies.jar().getCookies(req.getUrl())).reduce((obj, c) => ({
|
||||
...obj,
|
||||
[c.key]: c.value
|
||||
}), {})`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should convert pm.cookies.has inside an if conditional', () => {
|
||||
const inputScript = `if (pm.cookies.has('auth')) { console.log('found'); }`;
|
||||
const expectedOutput = `if (await bru.cookies.jar().hasCookie(req.getUrl(), 'auth')) { console.log('found'); }`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should convert pm.cookies.get with a variable argument', () => {
|
||||
const inputScript = `const val = pm.cookies.get(cookieName)`;
|
||||
const expectedOutput = `const val = (await bru.cookies.jar().getCookie(req.getUrl(), cookieName))?.value`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should handle mixed pm.cookies.get and pm.cookies.jar().set without conflict', () => {
|
||||
const inputScript = `const v = pm.cookies.get('token'); pm.cookies.jar().set('https://example.com', 'a', 'b');`;
|
||||
const expectedOutput = `const v = (await bru.cookies.jar().getCookie(req.getUrl(), 'token'))?.value; bru.cookies.jar().setCookie('https://example.com', 'a', 'b');`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should handle combined has + get in same script', () => {
|
||||
const inputScript = `if (pm.cookies.has('auth')) { const token = pm.cookies.get('auth'); }`;
|
||||
const expectedOutput = `if (await bru.cookies.jar().hasCookie(req.getUrl(), 'auth')) { const token = (await bru.cookies.jar().getCookie(req.getUrl(), 'auth'))?.value; }`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should handle aliased access: const cookies = pm.cookies', () => {
|
||||
const inputScript = `const cookies = pm.cookies; cookies.get('token');`;
|
||||
const expectedOutput = `(await bru.cookies.jar().getCookie(req.getUrl(), 'token'))?.value;`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -81,6 +81,11 @@ class Bru {
|
||||
deleteCookie: (url, cookieName, callback) => {
|
||||
const interpolatedUrl = this.interpolate(url);
|
||||
return cookieJar.deleteCookie(interpolatedUrl, cookieName, callback);
|
||||
},
|
||||
|
||||
hasCookie: (url, cookieName, callback) => {
|
||||
const interpolatedUrl = this.interpolate(url);
|
||||
return cookieJar.hasCookie(interpolatedUrl, cookieName, callback);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -142,6 +142,19 @@ describe('Bruno Cookie Jar Wrapper - API Examples', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasCookie', () => {
|
||||
test('hasCookie returns true for existing cookie', async () => {
|
||||
await jar.setCookie(testUrl, 'authToken', 'jwt123');
|
||||
const exists = await jar.hasCookie(testUrl, 'authToken');
|
||||
expect(exists).toBe(true);
|
||||
});
|
||||
|
||||
test('hasCookie returns false for non-existent cookie', async () => {
|
||||
const exists = await jar.hasCookie(testUrl, 'nonexistent');
|
||||
expect(exists).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error Handling', () => {
|
||||
test('setCookie handles missing URL', async () => {
|
||||
await expect(jar.setCookie('', 'name', 'value')).rejects.toThrow('URL is required');
|
||||
|
||||
@@ -214,6 +214,35 @@ const cookieJarWrapper = () => {
|
||||
});
|
||||
},
|
||||
|
||||
// Check whether a cookie with the given name exists for the URL.
|
||||
hasCookie: function (
|
||||
url: string,
|
||||
cookieName: string,
|
||||
callback?: (err: Error | null | undefined, exists?: boolean) => void
|
||||
) {
|
||||
if (!url || !cookieName) {
|
||||
const error = new Error('URL and cookie name are required');
|
||||
if (callback) return callback(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
return cookieJar.getCookies(url, (err: Error | null, cookies?: Cookie[]) => {
|
||||
if (err) return callback(err);
|
||||
const cookieList = cookies || [];
|
||||
callback(null, cookieList.some((c) => c.key === cookieName));
|
||||
});
|
||||
}
|
||||
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
cookieJar.getCookies(url, (err: Error | null, cookies?: Cookie[]) => {
|
||||
if (err) return reject(err);
|
||||
const cookieList = cookies || [];
|
||||
resolve(cookieList.some((c) => c.key === cookieName));
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Get all cookies that would be sent to the given URL.
|
||||
getCookies: function (url: string, callback?: (err: Error | null | undefined, cookies?: Cookie[]) => void) {
|
||||
if (!url) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
meta {
|
||||
name: hasCookie
|
||||
type: http
|
||||
seq: 10
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/ping
|
||||
body: none
|
||||
auth: inherit
|
||||
}
|
||||
|
||||
script:pre-request {
|
||||
const jar = bru.cookies.jar()
|
||||
|
||||
jar.setCookie("https://testbench-sanity.usebruno.com", "existing_cookie", "some_value")
|
||||
}
|
||||
|
||||
tests {
|
||||
const jar = bru.cookies.jar()
|
||||
|
||||
test("should return true for a cookie that exists", async function() {
|
||||
const exists = await jar.hasCookie('https://testbench-sanity.usebruno.com', 'existing_cookie');
|
||||
expect(exists).to.be.true;
|
||||
});
|
||||
|
||||
test("should return false for a cookie that does not exist", async function() {
|
||||
const exists = await jar.hasCookie('https://testbench-sanity.usebruno.com', 'nonexistent_cookie');
|
||||
expect(exists).to.be.false;
|
||||
});
|
||||
|
||||
jar.hasCookie("https://testbench-sanity.usebruno.com", "existing_cookie", function(error, exists) {
|
||||
test("should work with callback pattern", function() {
|
||||
expect(error).to.be.null;
|
||||
expect(exists).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
jar.clear()
|
||||
}
|
||||
|
||||
settings {
|
||||
encodeUrl: true
|
||||
}
|
||||
Reference in New Issue
Block a user