mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-27 22:54:07 +00:00
184 lines
7.1 KiB
JavaScript
184 lines
7.1 KiB
JavaScript
const {
|
|
getValueString,
|
|
extractTypedAnnotations,
|
|
buildAnnotationsFromVariable,
|
|
serializeAnnotations
|
|
} = require('../src/utils');
|
|
|
|
describe('getValueString', () => {
|
|
it('returns single line value as-is', () => {
|
|
expect(getValueString('hello world')).toBe('hello world');
|
|
});
|
|
|
|
it('wraps multiline value in triple quotes with indentation', () => {
|
|
expect(getValueString('line1\nline2\nline3')).toBe('\'\'\'\n line1\n line2\n line3\n\'\'\'');
|
|
});
|
|
|
|
it('normalizes different newline types', () => {
|
|
expect(getValueString('line1\r\nline2\rline3\nline4')).toBe('\'\'\'\n line1\n line2\n line3\n line4\n\'\'\'');
|
|
});
|
|
|
|
it('returns empty string for empty/null/undefined', () => {
|
|
expect(getValueString('')).toBe('');
|
|
expect(getValueString(null)).toBe('');
|
|
expect(getValueString(undefined)).toBe('');
|
|
});
|
|
|
|
it('returns "0" for the number 0 (truthy guard)', () => {
|
|
expect(getValueString(0)).toBe('0');
|
|
});
|
|
|
|
it('returns "false" for boolean false (truthy guard)', () => {
|
|
expect(getValueString(false)).toBe('false');
|
|
});
|
|
|
|
it('stringifies numbers and booleans to their primitive form', () => {
|
|
expect(getValueString(42)).toBe('42');
|
|
expect(getValueString(true)).toBe('true');
|
|
});
|
|
|
|
it('JSON-stringifies object values and wraps multiline output in triple quotes', () => {
|
|
const out = getValueString({ a: 1, b: 'x' });
|
|
expect(out).toContain('"a": 1');
|
|
expect(out).toContain('"b": "x"');
|
|
});
|
|
});
|
|
|
|
describe('extractTypedAnnotations', () => {
|
|
it('sets dataType and coerces value when a dataType annotation is present', () => {
|
|
const result = { value: '42' };
|
|
extractTypedAnnotations([{ name: 'number' }], result);
|
|
expect(result.dataType).toBe('number');
|
|
expect(result.value).toBe(42);
|
|
});
|
|
|
|
it('does nothing when no dataType annotation is present', () => {
|
|
const result = { value: 'abc' };
|
|
extractTypedAnnotations([{ name: 'description', value: 'doc' }], result);
|
|
expect(result.dataType).toBeUndefined();
|
|
expect(result.value).toBe('abc');
|
|
});
|
|
|
|
it('does not materialize @string as an explicit dataType', () => {
|
|
const result = { value: 'abc' };
|
|
extractTypedAnnotations([{ name: 'string' }], result);
|
|
expect(result.dataType).toBeUndefined();
|
|
});
|
|
|
|
it('picks the last dataType annotation when multiple are stacked', () => {
|
|
const result = { value: '99' };
|
|
extractTypedAnnotations([{ name: 'object' }, { name: 'number' }], result);
|
|
expect(result.dataType).toBe('number');
|
|
expect(result.value).toBe(99);
|
|
});
|
|
|
|
it('preserves the declared dataType and leaves the raw value when coercion is impossible', () => {
|
|
// The DataTypeSelector relies on this: when dataType is preserved but the
|
|
// coerced value's type doesn't match, the UI surfaces a warning icon.
|
|
const result = { value: 'not-a-number' };
|
|
extractTypedAnnotations([{ name: 'number' }], result);
|
|
expect(result.dataType).toBe('number');
|
|
expect(result.value).toBe('not-a-number');
|
|
});
|
|
|
|
it('preserves @boolean even when the literal is not a boolean string', () => {
|
|
const result = { value: 'maybe' };
|
|
extractTypedAnnotations([{ name: 'boolean' }], result);
|
|
expect(result.dataType).toBe('boolean');
|
|
expect(result.value).toBe('maybe');
|
|
});
|
|
|
|
it('preserves @object even when the value is not parseable JSON', () => {
|
|
const result = { value: 'plain text' };
|
|
extractTypedAnnotations([{ name: 'object' }], result);
|
|
expect(result.dataType).toBe('object');
|
|
expect(result.value).toBe('plain text');
|
|
});
|
|
|
|
it('handles null / empty annotations safely', () => {
|
|
const result = { value: 'abc' };
|
|
extractTypedAnnotations(null, result);
|
|
extractTypedAnnotations([], result);
|
|
expect(result.dataType).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('buildAnnotationsFromVariable', () => {
|
|
it('returns an empty array when no dataType and no annotations', () => {
|
|
expect(buildAnnotationsFromVariable({})).toEqual([]);
|
|
});
|
|
|
|
it('prepends a dataType annotation from the dataType field', () => {
|
|
expect(buildAnnotationsFromVariable({ dataType: 'number' })).toEqual([{ name: 'number' }]);
|
|
});
|
|
|
|
it('drops any existing dataType annotation and rebuilds from the dataType field', () => {
|
|
const out = buildAnnotationsFromVariable({
|
|
dataType: 'number',
|
|
annotations: [{ name: 'string' }, { name: 'description', value: 'doc' }]
|
|
});
|
|
expect(out).toEqual([{ name: 'number' }, { name: 'description', value: 'doc' }]);
|
|
});
|
|
|
|
it('does not emit a dataType annotation for the string default', () => {
|
|
expect(buildAnnotationsFromVariable({ dataType: 'string' })).toEqual([]);
|
|
});
|
|
|
|
it('preserves non-dataType annotations when dataType is absent', () => {
|
|
expect(buildAnnotationsFromVariable({
|
|
annotations: [{ name: 'description', value: 'doc' }]
|
|
})).toEqual([{ name: 'description', value: 'doc' }]);
|
|
});
|
|
});
|
|
|
|
describe('serializeAnnotations', () => {
|
|
it('returns an empty string for null/undefined/empty input', () => {
|
|
expect(serializeAnnotations(null)).toBe('');
|
|
expect(serializeAnnotations(undefined)).toBe('');
|
|
expect(serializeAnnotations([])).toBe('');
|
|
});
|
|
|
|
it('serializes a valueless annotation as @name with a trailing newline', () => {
|
|
expect(serializeAnnotations([{ name: 'number' }])).toBe('@number\n');
|
|
});
|
|
|
|
it('serializes a string-valued annotation using single-quote delimiters by default', () => {
|
|
expect(serializeAnnotations([{ name: 'description', value: 'a doc' }])).toBe('@description(\'a doc\')\n');
|
|
});
|
|
|
|
it('switches to double-quote delimiters when the value contains a single quote', () => {
|
|
expect(serializeAnnotations([{ name: 'description', value: 'O\'Reilly' }])).toBe('@description("O\'Reilly")\n');
|
|
});
|
|
|
|
it('keeps single-quote delimiters when the value contains a double quote', () => {
|
|
expect(serializeAnnotations([{ name: 'description', value: 'say "hi"' }])).toBe('@description(\'say "hi"\')\n');
|
|
});
|
|
|
|
it('wraps multiline values in triple-quote delimiters with 2-space indentation', () => {
|
|
expect(serializeAnnotations([{ name: 'description', value: 'line1\nline2' }])).toBe(
|
|
'@description(\'\'\'\n line1\n line2\n\'\'\')\n'
|
|
);
|
|
});
|
|
|
|
it('joins multiple annotations with newlines and adds a single trailing newline', () => {
|
|
expect(
|
|
serializeAnnotations([
|
|
{ name: 'number' },
|
|
{ name: 'description', value: 'doc' }
|
|
])
|
|
).toBe('@number\n@description(\'doc\')\n');
|
|
});
|
|
|
|
it('coerces non-string values to strings via String() before quoting', () => {
|
|
expect(serializeAnnotations([{ name: 'count', value: 42 }])).toBe('@count(\'42\')\n');
|
|
expect(serializeAnnotations([{ name: 'enabled', value: false }])).toBe('@enabled(\'false\')\n');
|
|
});
|
|
|
|
it('treats null/empty-string values as present (not as missing)', () => {
|
|
// `a.value === undefined` is the only branch that renders without parentheses,
|
|
// so null and '' both serialize as quoted empty-ish values.
|
|
expect(serializeAnnotations([{ name: 'description', value: null }])).toBe('@description(\'null\')\n');
|
|
expect(serializeAnnotations([{ name: 'description', value: '' }])).toBe('@description(\'\')\n');
|
|
});
|
|
});
|