Files
bruno/packages/bruno-lang/v2/tests/examples/examples.spec.js
sanish chirayath b61d2212f6 fix: Consistent multipart form handling and @contentType support in examples (#6325)
* fix: multiline multipart items within multipart within response example

* change multiline  editor to single line fot contentType

---------

Co-authored-by: Bijin A B <bijin@usebruno.com>
2025-12-11 01:17:39 +05:30

378 lines
15 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const bruToJson = require('../../src/bruToJson');
const jsonToBru = require('../../src/jsonToBru');
describe('Examples functionality', () => {
describe('Fixture-based tests', () => {
it('should parse examples-simple.bru correctly', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'examples-simple.bru'), 'utf8');
const expected = require('./fixtures/json/examples-simple.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should parse examples-complex.bru correctly', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'examples-complex.bru'), 'utf8');
const output = bruToJson(input);
// Basic structure validation
expect(output.meta).toBeDefined();
expect(output.http).toBeDefined();
expect(output.examples).toBeDefined();
expect(Array.isArray(output.examples)).toBe(true);
expect(output.examples).toHaveLength(3);
// Check each example has the expected structure
output.examples.forEach((example, index) => {
expect(example.name).toBeDefined();
expect(example.description).toBeDefined();
expect(example.request).toBeDefined();
expect(example.request.url).toBeDefined();
if (example.response) {
expect(example.response.status).toBeDefined();
expect(example.response.body).toBeDefined();
}
});
// Check specific examples
const jsonExample = output.examples[0];
expect(jsonExample.name).toBe('JSON API Example');
expect(jsonExample.request.url).toBeDefined();
if (jsonExample.request.body && jsonExample.request.body.json) {
expect(jsonExample.request.body.json).toContain('"format": "json"');
}
const xmlExample = output.examples[1];
expect(xmlExample.name).toBe('XML API Example');
if (xmlExample.request.body && xmlExample.request.body.xml) {
expect(xmlExample.request.body.xml).toContain('<format>xml</format>');
}
const textExample = output.examples[2];
expect(textExample.name).toBe('Text API Example');
});
});
describe('Basic examples parsing', () => {
it('should parse a single example block', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-single-example.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-single-example.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should parse multiple example blocks', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-multiple-examples.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-multiple-examples.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should handle examples with response blocks', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-response-example.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-response-example.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
});
describe('Examples with different body types', () => {
it('should handle examples with JSON body', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-json-body.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-json-body.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should handle examples with XML body', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-xml-body.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-xml-body.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should handle examples with text body', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-text-body.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-text-body.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
});
describe('Edge cases', () => {
it('should handle empty example blocks', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-empty-example.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-empty-example.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should work without any examples', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-no-examples.bru'), 'utf8');
const expected = require('./fixtures/json/bruToJson-no-examples.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
});
describe('jsonToBru conversion', () => {
it('should convert JSON with examples to BRU format', () => {
const jsonInput = require('./fixtures/json/jsonToBru-simple.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'jsonToBru-simple.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should handle multiple examples correctly', () => {
const jsonInput = require('./fixtures/json/jsonToBru-multiple.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'jsonToBru-multiple.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should handle examples with response blocks', () => {
const jsonInput = require('./fixtures/json/jsonToBru-response.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'jsonToBru-response.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should handle examples with different body types', () => {
const jsonInput = require('./fixtures/json/jsonToBru-bodytypes.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'jsonToBru-bodytypes.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should handle round-trip conversion correctly', () => {
const originalBru = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'examples-simple.bru'), 'utf8');
const jsonFromBru = bruToJson(originalBru);
const bruFromJson = jsonToBru(jsonFromBru);
const jsonFromBruAgain = bruToJson(bruFromJson);
// The examples should be preserved through the round-trip
expect(jsonFromBruAgain.examples).toBeDefined();
expect(Array.isArray(jsonFromBruAgain.examples)).toBe(true);
expect(jsonFromBruAgain.examples).toHaveLength(2);
expect(jsonFromBruAgain.examples[0].name).toBe('Get User by ID');
expect(jsonFromBruAgain.examples[1].name).toBe('Create New User');
});
it('should handle empty examples array', () => {
const jsonInput = {
meta: {
name: 'No Examples API',
type: 'http'
},
http: {
method: 'get',
url: 'https://api.example.com/test'
},
examples: []
};
const expected = `meta {
name: No Examples API
type: http
}
get {
url: https://api.example.com/test
}
`;
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should handle examples with minimal structure', () => {
const jsonInput = {
meta: {
name: 'Test API',
type: 'http'
},
http: {
url: 'https://api.example.com/test',
method: 'get'
},
examples: [
{
name: 'Example Request',
description: 'A simple example',
request: {
url: 'https://api.example.com/example',
method: 'get'
}
}
]
};
const expected = `meta {
name: Test API
type: http
}
get {
url: https://api.example.com/test
}
example {
name: Example Request
description: A simple example
request: {
url: https://api.example.com/example
method: get
}
}
`;
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
});
describe('Complex examples with auth', () => {
it('should parse complex-with-auth.bru correctly', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'complex-with-auth.bru'), 'utf8');
const expected = require('./fixtures/json/complex-with-auth.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should parse form-data-complex.bru correctly', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'form-data-complex.bru'), 'utf8');
const expected = require('./fixtures/json/form-data-complex.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should parse multiple-examples-variations.bru correctly', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'multiple-examples-variations.bru'), 'utf8');
const expected = require('./fixtures/json/multiple-examples-variations.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should parse oauth2-examples.bru correctly', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'oauth2-examples.bru'), 'utf8');
const expected = require('./fixtures/json/oauth2-examples.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
describe('jsonToBru conversion for complex fixtures', () => {
it('should convert complex-with-auth.json to BRU format and preserve examples', () => {
const jsonInput = require('./fixtures/json/complex-with-auth.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'complex-with-auth.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should convert form-data-complex.json to BRU format and preserve examples', () => {
const jsonInput = require('./fixtures/json/form-data-complex.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'form-data-complex.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should convert multiple-examples-variations.json to BRU format and preserve examples', () => {
const jsonInput = require('./fixtures/json/multiple-examples-variations.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'multiple-examples-variations.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
it('should convert oauth2-examples.json to BRU format and preserve examples', () => {
const jsonInput = require('./fixtures/json/oauth2-examples.json');
const expected = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'oauth2-examples.bru'), 'utf8');
const output = jsonToBru(jsonInput);
expect(output).toEqual(expected);
});
});
});
describe('Examples with multiline strings and contentType', () => {
it('should parse examples with multiline strings and @contentType annotations', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'examples-multiline-contenttype.bru'), 'utf8');
const expected = require('./fixtures/json/examples-multiline-contenttype.json');
const output = bruToJson(input);
expect(output).toEqual(expected);
});
it('should correctly extract contentType from multiline values', () => {
const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'examples-multiline-contenttype.bru'), 'utf8');
const output = bruToJson(input);
const example = output.examples[0];
const multipartForm = example.request.body.multipartForm;
// Check that multiline values with @contentType are parsed correctly
const testField = multipartForm.find((f) => f.name === 'test');
expect(testField).toBeDefined();
expect(testField.value).toContain('"hello"');
expect(testField.contentType).toBe('application/json');
// Check single-line value with @contentType
const simpleField = multipartForm.find((f) => f.name === 'simple');
expect(simpleField).toBeDefined();
expect(simpleField.value).toBe('cat and mouse');
expect(simpleField.contentType).toBe('text/plain');
// Check multiline value without @contentType
const arrayField = multipartForm.find((f) => f.name === 'array');
expect(arrayField).toBeDefined();
expect(arrayField.value).toContain('"coolade"');
expect(arrayField.contentType).toBe('');
// Check complex multiline JSON with @contentType
const jsonValueField = multipartForm.find((f) => f.name === 'jsonValue');
expect(jsonValueField).toBeDefined();
expect(jsonValueField.value).toContain('"key": "value"');
expect(jsonValueField.contentType).toBe('application/json');
});
it('should handle round-trip conversion for multiline strings with contentType', () => {
const originalBru = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'examples-multiline-contenttype.bru'), 'utf8');
const jsonFromBru = bruToJson(originalBru);
const bruFromJson = jsonToBru(jsonFromBru);
const jsonFromBruAgain = bruToJson(bruFromJson);
// The examples should be preserved through the round-trip
expect(jsonFromBruAgain.examples).toBeDefined();
expect(Array.isArray(jsonFromBruAgain.examples)).toBe(true);
expect(jsonFromBruAgain.examples).toHaveLength(1);
const example = jsonFromBruAgain.examples[0];
const multipartForm = example.request.body.multipartForm;
// Verify contentType is preserved
const testField = multipartForm.find((f) => f.name === 'test');
expect(testField.contentType).toBe('application/json');
expect(testField.value).toContain('"hello"');
const jsonValueField = multipartForm.find((f) => f.name === 'jsonValue');
expect(jsonValueField.contentType).toBe('application/json');
expect(jsonValueField.value).toContain('"key": "value"');
});
});
});