mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-22 04:05:42 +00:00
* chore: basic annotation support * chore: string and escape cases * feat: add basic multiline support * fix: simplify dedentation logic in annotation multiline text block * chore: fix asserts * feat: add annotation support to env and collection * feat: enhance annotation parsing with support for quoted arguments and nested parentheses * refactor: feedback, remove inline annotations * feat: move serializeAnnotations function to utils and update imports
834 lines
25 KiB
JavaScript
834 lines
25 KiB
JavaScript
const parser = require('../src/bruToJson');
|
|
const jsonToBru = require('../src/jsonToBru');
|
|
const envParser = require('../src/envToJson');
|
|
const jsonToEnv = require('../src/jsonToEnv');
|
|
const collectionParser = require('../src/collectionBruToJson');
|
|
const jsonToCollectionBru = require('../src/jsonToCollectionBru');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
describe('pair annotations', () => {
|
|
it('above-line annotations in asserts', () => {
|
|
const input = `
|
|
assert {
|
|
@description('hello')
|
|
res.status: eq 200
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.assertions).toEqual([
|
|
{ name: 'res.status', value: 'eq 200', enabled: true, annotations: [{ name: 'description', value: 'hello' }] }
|
|
]);
|
|
});
|
|
|
|
it('above-line annotation', () => {
|
|
const input = `
|
|
headers {
|
|
@description('hello')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers).toEqual([
|
|
{ name: 'key', value: 'value', enabled: true, annotations: [{ name: 'description', value: 'hello' }] }
|
|
]);
|
|
});
|
|
|
|
it('annotation without args', () => {
|
|
const input = `
|
|
headers {
|
|
@string
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers).toEqual([
|
|
{ name: 'key', value: 'value', enabled: true, annotations: [{ name: 'string' }] }
|
|
]);
|
|
});
|
|
|
|
it('multiple above-line annotations on same pair', () => {
|
|
const input = `
|
|
headers {
|
|
@string
|
|
@description('x')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers).toEqual([
|
|
{
|
|
name: 'key',
|
|
value: 'value',
|
|
enabled: true,
|
|
annotations: [{ name: 'string' }, { name: 'description', value: 'x' }]
|
|
}
|
|
]);
|
|
});
|
|
|
|
it('multiple above-line annotations', () => {
|
|
const input = `
|
|
headers {
|
|
@string
|
|
@description('hello')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers).toEqual([
|
|
{
|
|
name: 'key',
|
|
value: 'value',
|
|
enabled: true,
|
|
annotations: [{ name: 'string' }, { name: 'description', value: 'hello' }]
|
|
}
|
|
]);
|
|
});
|
|
|
|
it('no annotation — output unchanged (backward compat)', () => {
|
|
const input = `
|
|
headers {
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers).toEqual([{ name: 'key', value: 'value', enabled: true }]);
|
|
expect(output.headers[0]).not.toHaveProperty('annotations');
|
|
});
|
|
|
|
it('disabled pair with annotation', () => {
|
|
const input = `
|
|
headers {
|
|
@string
|
|
~key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers).toEqual([
|
|
{ name: 'key', value: 'value', enabled: false, annotations: [{ name: 'string' }] }
|
|
]);
|
|
});
|
|
|
|
it('double-quoted annotation arg', () => {
|
|
const input = `
|
|
headers {
|
|
@description("hello")
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'hello' }]);
|
|
});
|
|
|
|
it('single quote inside double-quoted annotation arg (e.g. O\'Reilly)', () => {
|
|
const input = `
|
|
headers {
|
|
@description("O'Reilly")
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'O\'Reilly' }]);
|
|
});
|
|
|
|
it('double quote inside single-quoted annotation arg (e.g. say "hello")', () => {
|
|
const input = `
|
|
headers {
|
|
@description('say "hello"')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'say "hello"' }]);
|
|
});
|
|
|
|
it('smoke test escaping special characters', () => {
|
|
const input = fs.readFileSync(path.join(__dirname, './fixtures/annotations.bru'));
|
|
const output = parser(input);
|
|
expect(output.vars.req[0].annotations).toEqual([{ name: 'description', value: 'found in C:\\Users\\File\\Path' }]);
|
|
expect(output.vars.req[1].annotations).toEqual([{ name: 'description', value: 'height of 2\' ' }]);
|
|
});
|
|
|
|
it('unquoted annotation arg', () => {
|
|
const input = `
|
|
headers {
|
|
@version(2)
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'version', value: '2' }]);
|
|
});
|
|
|
|
it('float (decimal) unquoted annotation arg', () => {
|
|
const input = `
|
|
headers {
|
|
@version(3.14)
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'version', value: '3.14' }]);
|
|
});
|
|
|
|
it('empty string arg', () => {
|
|
const input = `
|
|
headers {
|
|
@description('')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: '' }]);
|
|
});
|
|
|
|
it('whitespace-only string arg preserves spaces', () => {
|
|
const input = `
|
|
headers {
|
|
@description(' ')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: ' ' }]);
|
|
});
|
|
|
|
it('leading and trailing whitespace in string arg is preserved', () => {
|
|
const input = `
|
|
headers {
|
|
@description(' hello ')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: ' hello ' }]);
|
|
});
|
|
|
|
it('unicode characters in annotation arg', () => {
|
|
const input = `
|
|
headers {
|
|
@description('日本語')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: '日本語' }]);
|
|
});
|
|
|
|
it('URL with query string in annotation arg', () => {
|
|
const input = `
|
|
headers {
|
|
@description('https://example.com/path?q=1&r=2#anchor')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'https://example.com/path?q=1&r=2#anchor' }]);
|
|
});
|
|
|
|
it('colon inside annotation arg value', () => {
|
|
const input = `
|
|
headers {
|
|
@description('Content-Type: application/json')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'Content-Type: application/json' }]);
|
|
});
|
|
|
|
it('email address (@ symbol) inside annotation arg value', () => {
|
|
const input = `
|
|
headers {
|
|
@description('user@example.com')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'user@example.com' }]);
|
|
});
|
|
|
|
it('template variable syntax inside annotation arg value', () => {
|
|
const input = `
|
|
headers {
|
|
@description('{{baseUrl}}/endpoint')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: '{{baseUrl}}/endpoint' }]);
|
|
});
|
|
|
|
it('tab character inside annotation arg value', () => {
|
|
const input = `headers {\n @description('col1\tcol2')\n key: value\n}\n`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'col1\tcol2' }]);
|
|
});
|
|
|
|
it('multiline string values', () => {
|
|
const input = `headers {
|
|
@description('''
|
|
make it rain
|
|
make it rain2
|
|
''')
|
|
key: value
|
|
}`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'make it rain\nmake it rain2' }]);
|
|
});
|
|
|
|
it('serializeAnnotations — multiline value uses triple-quote delimiters and roundtrips correctly', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: 'line one\nline two' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
expect(bru).toContain('@description(\'\'\'\n line one\n line two\n \'\'\')\n x-key: val'); const parsed = parser(bru);
|
|
expect(parsed.headers[0].annotations).toEqual([{ name: 'description', value: 'line one\nline two' }]);
|
|
});
|
|
|
|
it('serializeAnnotations — empty string value roundtrips correctly', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: '' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
const parsed = parser(bru);
|
|
expect(parsed.headers[0].annotations).toEqual([{ name: 'description', value: '' }]);
|
|
});
|
|
|
|
it('serializeAnnotations — URL with special chars uses single-quote delimiters', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: 'https://example.com?q=1&r=2' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
expect(bru).toContain('@description(\'https://example.com?q=1&r=2\')\n x-key: val');
|
|
});
|
|
|
|
it('serializeAnnotations — template variable in value roundtrips correctly', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: '{{baseUrl}}/path' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
const parsed = parser(bru);
|
|
expect(parsed.headers[0].annotations).toEqual([{ name: 'description', value: '{{baseUrl}}/path' }]);
|
|
});
|
|
|
|
it('annotation on params:query block', () => {
|
|
const input = `
|
|
params:query {
|
|
@string
|
|
q: search
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.params).toEqual([
|
|
{ name: 'q', value: 'search', enabled: true, type: 'query', annotations: [{ name: 'string' }] }
|
|
]);
|
|
});
|
|
|
|
it('annotation on vars:pre-request block', () => {
|
|
const input = `
|
|
vars:pre-request {
|
|
@description('base url')
|
|
myVar: http://localhost
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.vars.req).toEqual([
|
|
{
|
|
name: 'myVar',
|
|
value: 'http://localhost',
|
|
enabled: true,
|
|
local: false,
|
|
annotations: [{ name: 'description', value: 'base url' }]
|
|
}
|
|
]);
|
|
});
|
|
|
|
it('roundtrip: bru → json → bru → json equal', () => {
|
|
const input = `get {
|
|
url: https://example.com
|
|
}
|
|
|
|
headers {
|
|
@description('Content type')
|
|
content-type: application/json
|
|
@string
|
|
~accept: */*
|
|
}
|
|
`;
|
|
const json1 = parser(input);
|
|
const bru = jsonToBru(json1);
|
|
const json2 = parser(bru);
|
|
expect(json2.headers).toEqual(json1.headers);
|
|
});
|
|
|
|
it('serializeAnnotations — annotation without value', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'string' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
expect(bru).toContain('@string\n x-key: val');
|
|
});
|
|
|
|
it('serializeAnnotations — annotation with value', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [
|
|
{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: 'my header' }] }
|
|
]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
expect(bru).toContain('@description(\'my header\')\n x-key: val');
|
|
});
|
|
|
|
it('serializeAnnotations — disabled pair with annotation', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: false, annotations: [{ name: 'string' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
expect(bru).toContain('@string\n ~x-key: val');
|
|
});
|
|
|
|
it('serializeAnnotations — value with single quote uses double-quote delimiters (e.g. O\'Reilly)', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: 'O\'Reilly' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
expect(bru).toContain('@description("O\'Reilly")\n x-key: val');
|
|
});
|
|
|
|
it('serializeAnnotations — value with double quote uses single-quote delimiters (e.g. say "hello")', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: 'say "hello"' }] }]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
expect(bru).toContain('@description(\'say "hello"\')\n x-key: val');
|
|
});
|
|
|
|
it('parseAndSerialise - bru sourced roundtrip check - headers', () => {
|
|
const input = `headers {
|
|
@description('hello')
|
|
key: value
|
|
}
|
|
`;
|
|
const parsed = parser(input);
|
|
const output = jsonToBru(parsed);
|
|
|
|
expect(input).toEqual(output);
|
|
});
|
|
|
|
it('parseAndSerialise - json sourced roundtrip check - headers', () => {
|
|
const input = {
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'description', value: 'say "hello"' }] }]
|
|
};
|
|
const stringified = jsonToBru(input);
|
|
const output = parser(stringified);
|
|
|
|
expect(input).toEqual(output);
|
|
});
|
|
|
|
it('parseAndSerialise - bru sourced roundtrip check - asserts', () => {
|
|
const input = `assert {
|
|
@description('make it rain')
|
|
res.status: eq 200
|
|
}
|
|
`;
|
|
|
|
const parsed = parser(input);
|
|
const output = jsonToBru(parsed);
|
|
|
|
expect(input).toEqual(output);
|
|
});
|
|
|
|
it('parseAndSerialise - json sourced roundtrip check - asserts', () => {
|
|
const input = {
|
|
assertions: [
|
|
{
|
|
annotations: [{ name: 'description', value: 'hello' }],
|
|
name: 'res.status', value: 'eq 200', enabled: true }
|
|
]
|
|
};
|
|
|
|
const parsed = jsonToBru(input);
|
|
const output = parser(parsed);
|
|
|
|
expect(input).toEqual(output);
|
|
});
|
|
|
|
it('paren inside single-quoted annotation arg — Token (JWT)', () => {
|
|
const input = `headers {
|
|
@description('Token (JWT)')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'Token (JWT)' }]);
|
|
});
|
|
|
|
it('paren inside double-quoted annotation arg — Result (OK)', () => {
|
|
const input = `headers {
|
|
@description("Result (OK)")
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'Result (OK)' }]);
|
|
});
|
|
|
|
it('multiple parens inside single-quoted annotation arg', () => {
|
|
const input = `headers {
|
|
@description('func(a, b) returns (c)')
|
|
key: value
|
|
}
|
|
`;
|
|
const output = parser(input);
|
|
expect(output.headers[0].annotations).toEqual([{ name: 'description', value: 'func(a, b) returns (c)' }]);
|
|
});
|
|
|
|
it('roundtrip — value containing parens survives json→bru→json — Token (JWT)', () => {
|
|
const json = {
|
|
meta: { name: 'test', type: 'http', seq: 1 },
|
|
http: { method: 'get', url: 'https://example.com' },
|
|
headers: [
|
|
{ name: 'Authorization', value: 'Bearer token', enabled: true, annotations: [{ name: 'description', value: 'Token (JWT)' }] }
|
|
]
|
|
};
|
|
const bru = jsonToBru(json);
|
|
const parsed = parser(bru);
|
|
expect(parsed.headers[0].annotations).toEqual([{ name: 'description', value: 'Token (JWT)' }]);
|
|
});
|
|
|
|
it('inline annotation on a header is rejected', () => {
|
|
const input = `
|
|
headers {
|
|
@string key: value
|
|
}
|
|
`;
|
|
expect(() => parser(input)).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('env pair annotations', () => {
|
|
it('above-line annotation with string arg on a var', () => {
|
|
const input = `vars {
|
|
@description('my api key')
|
|
API_KEY: abc123
|
|
}
|
|
`;
|
|
const output = envParser(input);
|
|
expect(output.variables).toEqual([
|
|
{ name: 'API_KEY', value: 'abc123', enabled: true, secret: false, annotations: [{ name: 'description', value: 'my api key' }] }
|
|
]);
|
|
});
|
|
|
|
it('above-line annotation on a var', () => {
|
|
const input = `vars {
|
|
@deprecated
|
|
OLD_KEY: old_value
|
|
}
|
|
`;
|
|
const output = envParser(input);
|
|
expect(output.variables).toEqual([
|
|
{ name: 'OLD_KEY', value: 'old_value', enabled: true, secret: false, annotations: [{ name: 'deprecated' }] }
|
|
]);
|
|
});
|
|
|
|
it('annotation without args on a var', () => {
|
|
const input = `vars {
|
|
@string
|
|
API_KEY: abc
|
|
}
|
|
`;
|
|
const output = envParser(input);
|
|
expect(output.variables[0].annotations).toEqual([{ name: 'string' }]);
|
|
});
|
|
|
|
it('multiple annotations on a var', () => {
|
|
const input = `vars {
|
|
@string
|
|
@description('base url')
|
|
BASE_URL: http://localhost
|
|
}
|
|
`;
|
|
const output = envParser(input);
|
|
expect(output.variables[0].annotations).toEqual([{ name: 'string' }, { name: 'description', value: 'base url' }]);
|
|
});
|
|
|
|
it('disabled var with annotation', () => {
|
|
const input = `vars {
|
|
@deprecated
|
|
~OLD_KEY: old_value
|
|
}
|
|
`;
|
|
const output = envParser(input);
|
|
expect(output.variables).toEqual([
|
|
{ name: 'OLD_KEY', value: 'old_value', enabled: false, secret: false, annotations: [{ name: 'deprecated' }] }
|
|
]);
|
|
});
|
|
|
|
it('no annotation — output unchanged (backward compat)', () => {
|
|
const input = `vars {
|
|
API_KEY: abc123
|
|
}
|
|
`;
|
|
const output = envParser(input);
|
|
expect(output.variables[0]).not.toHaveProperty('annotations');
|
|
expect(output.variables[0]).toEqual({ name: 'API_KEY', value: 'abc123', enabled: true, secret: false });
|
|
});
|
|
|
|
it('secret vars are unaffected by annotation support', () => {
|
|
const input = `vars:secret [
|
|
SECRET_KEY
|
|
]
|
|
`;
|
|
const output = envParser(input);
|
|
expect(output.variables).toEqual([{ name: 'SECRET_KEY', value: '', enabled: true, secret: true }]);
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToEnv — annotation without value', () => {
|
|
const json = {
|
|
variables: [{ name: 'API_KEY', value: 'abc', enabled: true, secret: false, annotations: [{ name: 'deprecated' }] }]
|
|
};
|
|
const bru = jsonToEnv(json);
|
|
expect(bru).toContain('@deprecated\n API_KEY: abc');
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToEnv — annotation with value', () => {
|
|
const json = {
|
|
variables: [{ name: 'BASE_URL', value: 'http://localhost', enabled: true, secret: false, annotations: [{ name: 'description', value: 'base url' }] }]
|
|
};
|
|
const bru = jsonToEnv(json);
|
|
expect(bru).toContain('@description(\'base url\')\n BASE_URL: http://localhost');
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToEnv — disabled var with annotation', () => {
|
|
const json = {
|
|
variables: [{ name: 'OLD_KEY', value: 'old', enabled: false, secret: false, annotations: [{ name: 'deprecated' }] }]
|
|
};
|
|
const bru = jsonToEnv(json);
|
|
expect(bru).toContain('@deprecated\n ~OLD_KEY: old');
|
|
});
|
|
|
|
it('parseAndSerialise - bru sourced roundtrip check - env vars', () => {
|
|
const input = `vars {
|
|
@description('api key')
|
|
API_KEY: abc123
|
|
}
|
|
`;
|
|
const parsed = envParser(input);
|
|
const output = jsonToEnv(parsed);
|
|
expect(output).toEqual(input);
|
|
});
|
|
|
|
it('parseAndSerialise - json sourced roundtrip check - env vars', () => {
|
|
const input = {
|
|
variables: [{ name: 'API_KEY', value: 'abc123', enabled: true, secret: false, annotations: [{ name: 'description', value: 'api key' }] }]
|
|
};
|
|
const bru = jsonToEnv(input);
|
|
const output = envParser(bru);
|
|
expect(output).toEqual(input);
|
|
});
|
|
|
|
it('inline annotation on an env var is rejected', () => {
|
|
const input = `vars {
|
|
@deprecated API_KEY: abc
|
|
}
|
|
`;
|
|
expect(() => envParser(input)).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('collection pair annotations', () => {
|
|
it('above-line annotation on a header (collection)', () => {
|
|
const input = `headers {
|
|
@description('content type')
|
|
content-type: application/json
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.headers).toEqual([
|
|
{ name: 'content-type', value: 'application/json', enabled: true, annotations: [{ name: 'description', value: 'content type' }] }
|
|
]);
|
|
});
|
|
|
|
it('above-line annotation on a header', () => {
|
|
const input = `headers {
|
|
@deprecated
|
|
old-header: old-value
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.headers).toEqual([
|
|
{ name: 'old-header', value: 'old-value', enabled: true, annotations: [{ name: 'deprecated' }] }
|
|
]);
|
|
});
|
|
|
|
it('annotation on a query param', () => {
|
|
const input = `query {
|
|
@string
|
|
q: search
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.query).toEqual([
|
|
{ name: 'q', value: 'search', enabled: true, annotations: [{ name: 'string' }] }
|
|
]);
|
|
});
|
|
|
|
it('disabled header with annotation', () => {
|
|
const input = `headers {
|
|
@deprecated
|
|
~x-old: value
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.headers).toEqual([
|
|
{ name: 'x-old', value: 'value', enabled: false, annotations: [{ name: 'deprecated' }] }
|
|
]);
|
|
});
|
|
|
|
it('annotation on vars:pre-request', () => {
|
|
const input = `vars:pre-request {
|
|
@description('base url')
|
|
BASE_URL: http://localhost
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.vars.req).toEqual([
|
|
{ name: 'BASE_URL', value: 'http://localhost', enabled: true, local: false, annotations: [{ name: 'description', value: 'base url' }] }
|
|
]);
|
|
});
|
|
|
|
it('annotation on vars:post-response', () => {
|
|
const input = `vars:post-response {
|
|
@string
|
|
token: abc
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.vars.res).toEqual([
|
|
{ name: 'token', value: 'abc', enabled: true, local: false, annotations: [{ name: 'string' }] }
|
|
]);
|
|
});
|
|
|
|
it('local var (@-prefixed) is not misidentified as annotation', () => {
|
|
const input = `vars:pre-request {
|
|
@localVar: http://localhost
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.vars.req).toEqual([
|
|
{ name: 'localVar', value: 'http://localhost', enabled: true, local: true }
|
|
]);
|
|
expect(output.vars.req[0]).not.toHaveProperty('annotations');
|
|
});
|
|
|
|
it('no annotation — output unchanged (backward compat)', () => {
|
|
const input = `headers {
|
|
content-type: application/json
|
|
}
|
|
`;
|
|
const output = collectionParser(input);
|
|
expect(output.headers[0]).not.toHaveProperty('annotations');
|
|
expect(output.headers[0]).toEqual({ name: 'content-type', value: 'application/json', enabled: true });
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToCollectionBru — header without value', () => {
|
|
const json = {
|
|
headers: [{ name: 'x-key', value: 'val', enabled: true, annotations: [{ name: 'string' }] }]
|
|
};
|
|
const bru = jsonToCollectionBru(json);
|
|
expect(bru).toContain('@string\n x-key: val');
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToCollectionBru — header with annotation value', () => {
|
|
const json = {
|
|
headers: [{ name: 'content-type', value: 'application/json', enabled: true, annotations: [{ name: 'description', value: 'content type' }] }]
|
|
};
|
|
const bru = jsonToCollectionBru(json);
|
|
expect(bru).toContain('@description(\'content type\')\n content-type: application/json');
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToCollectionBru — disabled header with annotation', () => {
|
|
const json = {
|
|
headers: [{ name: 'x-old', value: 'val', enabled: false, annotations: [{ name: 'deprecated' }] }]
|
|
};
|
|
const bru = jsonToCollectionBru(json);
|
|
expect(bru).toContain('@deprecated\n ~x-old: val');
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToCollectionBru — query param with annotation', () => {
|
|
const json = {
|
|
query: [{ name: 'q', value: 'search', enabled: true, annotations: [{ name: 'string' }] }]
|
|
};
|
|
const bru = jsonToCollectionBru(json);
|
|
expect(bru).toContain('@string\n q: search');
|
|
});
|
|
|
|
it('serializeAnnotations in jsonToCollectionBru — vars:pre-request with annotation', () => {
|
|
const json = {
|
|
vars: {
|
|
req: [{ name: 'BASE_URL', value: 'http://localhost', enabled: true, local: false, annotations: [{ name: 'description', value: 'base url' }] }]
|
|
}
|
|
};
|
|
const bru = jsonToCollectionBru(json);
|
|
expect(bru).toContain('@description(\'base url\')\n BASE_URL: http://localhost');
|
|
});
|
|
|
|
it('parseAndSerialise - bru sourced roundtrip check - collection headers', () => {
|
|
const input = `headers {
|
|
@description('content type')
|
|
content-type: application/json
|
|
}
|
|
`;
|
|
const parsed = collectionParser(input);
|
|
const output = jsonToCollectionBru(parsed);
|
|
expect(output).toEqual(input);
|
|
});
|
|
|
|
it('parseAndSerialise - json sourced roundtrip check - collection headers', () => {
|
|
const input = {
|
|
headers: [{ name: 'content-type', value: 'application/json', enabled: true, annotations: [{ name: 'description', value: 'content type' }] }]
|
|
};
|
|
const bru = jsonToCollectionBru(input);
|
|
const output = collectionParser(bru);
|
|
expect(output).toEqual(input);
|
|
});
|
|
|
|
it('parseAndSerialise - bru sourced roundtrip check - collection vars:pre-request', () => {
|
|
const input = `vars:pre-request {
|
|
@description('base url')
|
|
BASE_URL: http://localhost
|
|
}
|
|
`;
|
|
const parsed = collectionParser(input);
|
|
const output = jsonToCollectionBru(parsed);
|
|
expect(output).toEqual(input);
|
|
});
|
|
|
|
it('inline annotation on a collection header is rejected', () => {
|
|
const input = `headers {
|
|
@string x-key: val
|
|
}
|
|
`;
|
|
expect(() => collectionParser(input)).toThrow();
|
|
});
|
|
});
|