mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-08 06:28:33 +00:00
* feat(cookies): add direct cookie access methods and update translations
- Introduced new methods for direct cookie access: `bru.cookies.get`, `bru.cookies.has`, and `bru.cookies.toObject`.
- Updated translation mappings in `bruno-to-postman-translator` and `postman-to-bruno-translator` to support these new methods.
- Enhanced tests to verify correct translation between `bru` and `pm` cookie methods, including mixed usage scenarios.
- Updated `Bru` class to handle cookie access based on the current request URL.
* feat(cookies): enhance cookie management with new methods and refactor
- Added new cookie methods: `toString`, `clear`, `delete`, `one`, `all`, `idx`, `count`, `indexOf`, `find`, `filter`, `each`, `map`, and `reduce` to `bru.cookies`.
- Refactored `Bru` class to utilize a new `CookieList` for cookie management, improving structure and readability.
- Updated translation mappings in `bruno-to-postman-translator` and `postman-to-bruno-translator` to include new cookie methods.
- Introduced `PropertyList` and `ReadOnlyPropertyList` classes for better data structure management.
- Enhanced tests for comprehensive coverage of new cookie functionalities and their interactions.
* docs(readonly-property-list): clarify array usage in constructor comments
* feat(cookies): add direct cookie manipulation tests and methods
* feat(cookies): add hasCookie method for checking cookie existence
* fix
* refactor(cookies): simplify cookie method translations
* feat(cookies): expand cookie API with new methods and tests
- Added new cookie methods: `get`, `has`, `toString`, `clear`, `upsert`, `remove`, `idx`, and `indexOf` to enhance cookie management.
- Updated translation mappings for `bru.cookies` to include new methods in `bruno-to-postman-translator` and `postman-to-bruno-translator`.
- Introduced tests for new methods and their interactions, ensuring comprehensive coverage of cookie functionalities.
- Enhanced existing tests to validate correct behavior of cookie methods across different scenarios.
* refactor(cookies): update CookieList to extend PropertyList and improve error handling
* test(cookies): add regression tests for jar and direct cookie patterns
- Introduced regression tests to ensure that jar patterns are correctly prioritized over direct cookie access patterns in translations.
- Updated `CookieList` to extend `ReadOnlyPropertyList` instead of `PropertyList`, clarifying its functionality.
- Refactored cookie method handling in the `bru` shim to utilize a new asynchronous bridge for improved error handling and consistency.
* refactor(cookies): update translations and remove PropertyList
- Enhanced comments in `postman-translations.js` to clarify the order of cookie jar translations.
- Updated `cookie-list.js` comments to better describe the factory function for the cookie jar.
- Removed the `PropertyList` class and its associated tests, streamlining the codebase and focusing on `ReadOnlyPropertyList` and `CookieList` for cookie management.
* fix(cookies): normalize tough-cookie objects and improve remove method comments
- Updated `CookieList` to normalize tough-cookie instances to plain objects, preventing circular references and exposing internal structures.
- Enhanced comments in the `remove` method to clarify behavior when removing non-existent or empty-named cookies.
* test(cookies): update tests to use async/await for consistency
* test(cookies): use async/await in cookie tests for consistency
* refactor(readonly-property-list): update get and reduce methods for improved behavior
* fix(cookies): update cookie method signature in autocomplete hints and enhance translation comments
- Modified the autocomplete hint for `bru.cookies.has` to include the new signature with an optional value parameter.
- Improved comments in `postman-translations.js` to clarify the order of cookie jar translation patterns for better understanding.
* refactor(cookies): introduce PropertyList for enhanced cookie management
* refactor(property-list): simplify repopulate method and enhance item handling logic
* feat(cookies): implement PropertyList bridge for enhanced cookie management
- Introduced a new `createPropertyListBridge` utility to streamline the integration of cookie methods into the QuickJS VM.
- Replaced the previous async cookie bridge with a more flexible approach, allowing for both synchronous and asynchronous cookie operations.
- Added comprehensive tests to validate the functionality of the new cookie methods in both developer and safe modes.
- Updated existing cookie tests to ensure compatibility with the new PropertyList structure.
* fix(tests): correct expected passed requests in cookie tests
- Updated the expected number of passed requests in the cookie tests from 34 to 6 to reflect the correct validation results.
- Ensured consistency in test assertions across multiple test cases for the PropertyList API.
* fix(cookies): update cookie URLs to use localhost for testing
- Changed all cookie-related test scripts to use `{{localhost}}` instead of `{{host}}` for the ping URL, ensuring consistency in local testing environments.
- Updated the cookie test suite to reflect the new URL structure, enhancing the reliability of the tests.
- Removed outdated cookie test files to streamline the test suite.
* refactor(cookies): standardize cookie handling with localhost variable
- Updated cookie test scripts to utilize the `{{localhost}}` variable for setting and retrieving cookies, ensuring consistency across tests.
- Enhanced clarity in comments regarding cookie behavior for different domains.
- Improved test assertions to validate cookie management functionality more effectively.
* refactor(property-list, readonly-property-list): update methods to use private class fields
* feat(cookies): enhance CookieList API with detailed documentation and method improvements
- Updated the `CookieList` class to provide comprehensive documentation on cookie management methods, including `add`, `upsert`, `remove`, and `delete`.
- Improved method signatures to support both callback and Promise-based usage for asynchronous operations.
- Added detailed descriptions for read and write methods, including examples and expected behavior.
- Enhanced the integration of the `CookieList` with the QuickJS VM by updating the property list bridge to include `toJSON` in sync read object methods.
* feat(cookies): add detailed examples and improve async bridge documentation
- Enhanced the `createPropertyListBridge` function documentation with comprehensive examples for setting up cookie methods in QuickJS.
- Clarified the two-phase setup process for async write methods, detailing the registration of bridge functions and the generation of JavaScript code for method wrappers.
- Added a new test case for the `toJSON()` method to ensure it returns a cloned array of all cookies, validating the expected structure and properties.
* fix(assert-runtime): correct syntax error in response parser assignment
- Added a semicolon at the end of the response parser assignment to ensure proper syntax in the AssertRuntime class.
226 lines
7.6 KiB
JavaScript
226 lines
7.6 KiB
JavaScript
const ReadOnlyPropertyList = require('../src/readonly-property-list');
|
|
|
|
describe('ReadOnlyPropertyList', () => {
|
|
// ── Static Mode ──────────────────────────────────────────────────────
|
|
|
|
describe('static mode', () => {
|
|
let list;
|
|
|
|
beforeEach(() => {
|
|
list = new ReadOnlyPropertyList({
|
|
keyProperty: 'key',
|
|
items: [
|
|
{ key: 'a', value: '1' },
|
|
{ key: 'b', value: '2' },
|
|
{ key: 'c', value: '3' }
|
|
]
|
|
});
|
|
});
|
|
|
|
test('get() returns value by key', () => {
|
|
expect(list.get('a')).toBe('1');
|
|
expect(list.get('missing')).toBeUndefined();
|
|
});
|
|
|
|
test('one() returns full item by key', () => {
|
|
expect(list.one('b')).toEqual({ key: 'b', value: '2' });
|
|
});
|
|
|
|
test('all() returns cloned array', () => {
|
|
const items = list.all();
|
|
expect(items).toHaveLength(3);
|
|
items.push({ key: 'd', value: '4' });
|
|
expect(list.count()).toBe(3);
|
|
});
|
|
|
|
test('idx() returns item by position', () => {
|
|
expect(list.idx(0)).toEqual({ key: 'a', value: '1' });
|
|
expect(list.idx(10)).toBeUndefined();
|
|
});
|
|
|
|
test('count() returns number of items', () => {
|
|
expect(list.count()).toBe(3);
|
|
});
|
|
|
|
test('has() checks existence', () => {
|
|
expect(list.has('a')).toBe(true);
|
|
expect(list.has('a', '1')).toBe(true);
|
|
expect(list.has('a', 'wrong')).toBe(false);
|
|
expect(list.has('missing')).toBe(false);
|
|
});
|
|
|
|
test('toObject() converts to key-value object', () => {
|
|
expect(list.toObject()).toEqual({ a: '1', b: '2', c: '3' });
|
|
});
|
|
|
|
test('toString() converts to string', () => {
|
|
expect(list.toString()).toBe('a=1; b=2; c=3');
|
|
});
|
|
|
|
test('toJSON() returns cloned array of all items', () => {
|
|
const json = list.toJSON();
|
|
expect(json).toEqual([
|
|
{ key: 'a', value: '1' },
|
|
{ key: 'b', value: '2' },
|
|
{ key: 'c', value: '3' }
|
|
]);
|
|
json.push({ key: 'd', value: '4' });
|
|
expect(list.count()).toBe(3);
|
|
});
|
|
|
|
test('indexOf() finds item by structural equality', () => {
|
|
expect(list.indexOf({ key: 'b', value: '2' })).toBe(1);
|
|
expect(list.indexOf({ key: 'missing', value: '0' })).toBe(-1);
|
|
});
|
|
|
|
test('indexOf() returns -1 for non-object input', () => {
|
|
expect(list.indexOf(null)).toBe(-1);
|
|
expect(list.indexOf('string')).toBe(-1);
|
|
});
|
|
|
|
test('find() returns first matching item', () => {
|
|
const item = list.find((i) => i.value === '2');
|
|
expect(item).toEqual({ key: 'b', value: '2' });
|
|
});
|
|
|
|
test('find() returns undefined when no match', () => {
|
|
expect(list.find((i) => i.value === 'missing')).toBeUndefined();
|
|
});
|
|
|
|
test('filter() returns matching items', () => {
|
|
const items = list.filter((i) => i.value !== '2');
|
|
expect(items).toHaveLength(2);
|
|
expect(items[0].key).toBe('a');
|
|
expect(items[1].key).toBe('c');
|
|
});
|
|
|
|
test('each() iterates over all items', () => {
|
|
const keys = [];
|
|
list.each((item) => keys.push(item.key));
|
|
expect(keys).toEqual(['a', 'b', 'c']);
|
|
});
|
|
|
|
test('map() transforms items', () => {
|
|
const values = list.map((item) => item.value);
|
|
expect(values).toEqual(['1', '2', '3']);
|
|
});
|
|
|
|
test('reduce() accumulates values', () => {
|
|
const sum = list.reduce((acc, item) => acc + item.value, '');
|
|
expect(sum).toBe('123');
|
|
});
|
|
|
|
test('reduce() without initial value uses first element as accumulator', () => {
|
|
const numList = new ReadOnlyPropertyList({
|
|
items: [
|
|
{ key: 'a', value: 1 },
|
|
{ key: 'b', value: 2 },
|
|
{ key: 'c', value: 3 }
|
|
]
|
|
});
|
|
const result = numList.reduce((acc, item) => acc + item.value);
|
|
// First element becomes accumulator: { key: 'a', value: 1 } + 2 + 3
|
|
expect(result).toEqual({ key: 'a', value: 1 } + 2 + 3);
|
|
});
|
|
|
|
test('reduce() without initial value on single-element list returns that element', () => {
|
|
const singleList = new ReadOnlyPropertyList({
|
|
items: [{ key: 'only', value: 42 }]
|
|
});
|
|
const result = singleList.reduce((acc, item) => acc + item.value);
|
|
expect(result).toEqual({ key: 'only', value: 42 });
|
|
});
|
|
|
|
test('reduce() without initial value on empty list throws TypeError', () => {
|
|
const emptyList = new ReadOnlyPropertyList({ items: [] });
|
|
expect(() => emptyList.reduce((acc, item) => acc + item.value)).toThrow(TypeError);
|
|
});
|
|
|
|
test('get() returns last value when duplicate keys exist, consistent with toObject()', () => {
|
|
const dupList = new ReadOnlyPropertyList({
|
|
items: [
|
|
{ key: 'x', value: 'first' },
|
|
{ key: 'x', value: 'second' }
|
|
]
|
|
});
|
|
expect(dupList.get('x')).toBe('second');
|
|
expect(dupList.toObject().x).toBe('second');
|
|
});
|
|
});
|
|
|
|
// ── Dynamic Mode ─────────────────────────────────────────────────────
|
|
|
|
describe('dynamic mode', () => {
|
|
test('reads from dataSource on every call', () => {
|
|
let callCount = 0;
|
|
const list = new ReadOnlyPropertyList({
|
|
dataSource: () => {
|
|
callCount++;
|
|
return [
|
|
{ key: 'x', value: '10' },
|
|
{ key: 'y', value: '20' }
|
|
];
|
|
}
|
|
});
|
|
|
|
expect(list.get('x')).toBe('10');
|
|
expect(list.count()).toBe(2);
|
|
expect(list.all()).toHaveLength(2);
|
|
expect(callCount).toBe(3);
|
|
});
|
|
});
|
|
|
|
// ── No Mutation Methods ──────────────────────────────────────────────
|
|
|
|
describe('does not have mutation methods', () => {
|
|
const list = new ReadOnlyPropertyList({ items: [] });
|
|
|
|
test.each([
|
|
'add', 'prepend', 'insert', 'insertAfter',
|
|
'upsert', 'remove', 'clear',
|
|
'populate', 'repopulate', 'assimilate'
|
|
])('%s is not defined', (method) => {
|
|
expect(list[method]).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
// ── Edge Cases ───────────────────────────────────────────────────────
|
|
|
|
describe('edge cases', () => {
|
|
test('empty list', () => {
|
|
const list = new ReadOnlyPropertyList({ items: [] });
|
|
expect(list.count()).toBe(0);
|
|
expect(list.toObject()).toEqual({});
|
|
});
|
|
|
|
test('default constructor', () => {
|
|
const list = new ReadOnlyPropertyList();
|
|
expect(list.count()).toBe(0);
|
|
});
|
|
|
|
test('custom keyProperty', () => {
|
|
const list = new ReadOnlyPropertyList({
|
|
keyProperty: 'name',
|
|
items: [{ name: 'Content-Type', value: 'application/json' }]
|
|
});
|
|
expect(list.get('Content-Type')).toBe('application/json');
|
|
});
|
|
});
|
|
|
|
// ── Static Methods ──────────────────────────────────────────────────
|
|
|
|
describe('static methods', () => {
|
|
test('isPropertyList() returns true for ReadOnlyPropertyList', () => {
|
|
const list = new ReadOnlyPropertyList({ items: [] });
|
|
expect(ReadOnlyPropertyList.isPropertyList(list)).toBe(true);
|
|
});
|
|
|
|
test('isPropertyList() returns false for plain objects', () => {
|
|
expect(ReadOnlyPropertyList.isPropertyList({})).toBe(false);
|
|
expect(ReadOnlyPropertyList.isPropertyList(null)).toBe(false);
|
|
expect(ReadOnlyPropertyList.isPropertyList([])).toBe(false);
|
|
expect(ReadOnlyPropertyList.isPropertyList('string')).toBe(false);
|
|
});
|
|
});
|
|
});
|