diff --git a/packages/bruno-converters/src/common/index.js b/packages/bruno-converters/src/common/index.js index db5972890..765533f10 100644 --- a/packages/bruno-converters/src/common/index.js +++ b/packages/bruno-converters/src/common/index.js @@ -110,7 +110,7 @@ export const validateSchema = (collection = {}) => { return collection; } catch (err) { console.log('Error validating schema', err); - throw new Error('The Collection has an invalid schema'); + throw new Error(`The Collection has an invalid schema: ${err.message}`); } }; diff --git a/packages/bruno-filestore/src/formats/bru/index.ts b/packages/bruno-filestore/src/formats/bru/index.ts index ba000e1d6..7a899c265 100644 --- a/packages/bruno-filestore/src/formats/bru/index.ts +++ b/packages/bruno-filestore/src/formats/bru/index.ts @@ -367,6 +367,17 @@ export const bruExampleToJson = (data: string | any, parsed: boolean = false, pa transformedType = 'http-request'; } + /** + * Backward compatibility (pre-v3.0.2 - v3.2.0): Postman imports before PR #6876 stored status/statusText swapped + * (code: "OK", text: "202" instead of code: 202, text: "OK"). Detect and swap back. + * TODO(Sid / Shubh): Remove after v5 — all collections should be migrated by then. + */ + let status = _.get(json, 'response.status', '200'); + let statusText = _.get(json, 'response.statusText', 'OK'); + if (isNaN(Number(status)) && !isNaN(Number(statusText))) { + [status, statusText] = [statusText, status]; + } + // Follow the same structure as the main request, but with missing fields for examples const transformedJson = { type: transformedType, @@ -388,8 +399,8 @@ export const bruExampleToJson = (data: string | any, parsed: boolean = false, pa name: header.name, value: header.value })), - status: String(_.get(json, 'response.status', '200')), - statusText: _.get(json, 'response.statusText', 'OK'), + status: Number(status) || 200, + statusText: statusText || 'OK', body: { type: _.get(json, 'response.body.type', 'json'), content: _.get(json, 'response.body.content', '') diff --git a/packages/bruno-filestore/src/formats/bru/tests/example-status-swap.spec.js b/packages/bruno-filestore/src/formats/bru/tests/example-status-swap.spec.js new file mode 100644 index 000000000..0bbca41a9 --- /dev/null +++ b/packages/bruno-filestore/src/formats/bru/tests/example-status-swap.spec.js @@ -0,0 +1,109 @@ +const { bruExampleToJson } = require('../index'); + +describe('bruExampleToJson - status/statusText swap fix', () => { + it('should parse normal status and statusText correctly', () => { + const parsed = { + name: 'Normal Example', + description: '', + request: { url: 'https://api.example.com/test', method: 'get' }, + response: { + headers: [], + status: '200', + statusText: 'OK', + body: { type: 'json', content: '{}' } + } + }; + + const result = bruExampleToJson(parsed, true, 'http', 'GET'); + expect(result.response.status).toBe(200); + expect(result.response.statusText).toBe('OK'); + }); + + it('should swap back status and statusText when they are reversed (pre-fix Postman import)', () => { + const parsed = { + name: 'Swapped Example', + description: '', + request: { url: 'https://api.example.com/test', method: 'get' }, + response: { + headers: [], + status: 'Accepted', + statusText: '202', + body: { type: 'json', content: '{}' } + } + }; + + const result = bruExampleToJson(parsed, true, 'http', 'GET'); + expect(result.response.status).toBe(202); + expect(result.response.statusText).toBe('Accepted'); + }); + + it('should swap back status OK and statusText 200', () => { + const parsed = { + name: 'Swapped OK Example', + description: '', + request: { url: 'https://api.example.com/test', method: 'get' }, + response: { + headers: [], + status: 'OK', + statusText: '200', + body: { type: 'json', content: '{}' } + } + }; + + const result = bruExampleToJson(parsed, true, 'http', 'GET'); + expect(result.response.status).toBe(200); + expect(result.response.statusText).toBe('OK'); + }); + + it('should swap back status Not Found and statusText 404', () => { + const parsed = { + name: 'Swapped Not Found Example', + description: '', + request: { url: 'https://api.example.com/test', method: 'get' }, + response: { + headers: [], + status: 'Not Found', + statusText: '404', + body: { type: 'json', content: '{}' } + } + }; + + const result = bruExampleToJson(parsed, true, 'http', 'GET'); + expect(result.response.status).toBe(404); + expect(result.response.statusText).toBe('Not Found'); + }); + + it('should not swap when status is already numeric and statusText is text (correct order)', () => { + const parsed = { + name: 'Correct Order Example', + description: '', + request: { url: 'https://api.example.com/test', method: 'get' }, + response: { + headers: [], + status: '404', + statusText: 'Not Found', + body: { type: 'json', content: '{}' } + } + }; + + const result = bruExampleToJson(parsed, true, 'http', 'GET'); + expect(result.response.status).toBe(404); + expect(result.response.statusText).toBe('Not Found'); + }); + + it('should use defaults when response has no status', () => { + const parsed = { + name: 'No Status Example', + description: '', + request: { url: 'https://api.example.com/test', method: 'get' }, + response: { + headers: [], + body: { type: 'json', content: '{}' } + } + }; + + const result = bruExampleToJson(parsed, true, 'http', 'GET'); + expect(result.response.status).toBe(200); + expect(result.response.statusText).toBe('OK'); + }); +}); diff --git a/packages/bruno-lang/v2/tests/examples/examples.spec.js b/packages/bruno-lang/v2/tests/examples/examples.spec.js index db0707708..b1163d982 100644 --- a/packages/bruno-lang/v2/tests/examples/examples.spec.js +++ b/packages/bruno-lang/v2/tests/examples/examples.spec.js @@ -122,6 +122,14 @@ describe('Examples functionality', () => { expect(output).toEqual(expected); }); + + it('should parse swapped status/statusText from pre-fix Postman imports', () => { + const input = fs.readFileSync(path.join(__dirname, 'fixtures', 'bru', 'bruToJson-swapped-status.bru'), 'utf8'); + const expected = require('./fixtures/json/bruToJson-swapped-status.json'); + const output = bruToJson(input); + + expect(output).toEqual(expected); + }); }); describe('jsonToBru conversion', () => { diff --git a/packages/bruno-lang/v2/tests/examples/fixtures/bru/bruToJson-swapped-status.bru b/packages/bruno-lang/v2/tests/examples/fixtures/bru/bruToJson-swapped-status.bru new file mode 100644 index 000000000..af390f060 --- /dev/null +++ b/packages/bruno-lang/v2/tests/examples/fixtures/bru/bruToJson-swapped-status.bru @@ -0,0 +1,36 @@ +meta { + name: Test API + type: http +} + +get { + url: https://api.example.com/test +} + +example { + name: Swapped Status Example + description: Example with swapped status and statusText from pre-fix Postman import + + request: { + url: https://api.example.com/users/123 + method: get + mode: none + } + + response: { + status: { + code: Accepted + text: 202 + } + + body: { + type: json + content: ''' + { + "id": 123, + "name": "John Doe" + } + ''' + } + } +} diff --git a/packages/bruno-lang/v2/tests/examples/fixtures/json/bruToJson-swapped-status.json b/packages/bruno-lang/v2/tests/examples/fixtures/json/bruToJson-swapped-status.json new file mode 100644 index 000000000..77fb8ed42 --- /dev/null +++ b/packages/bruno-lang/v2/tests/examples/fixtures/json/bruToJson-swapped-status.json @@ -0,0 +1,32 @@ +{ + "meta": { + "name": "Test API", + "type": "http", + "seq": 1 + }, + "http": { + "method": "get", + "url": "https://api.example.com/test" + }, + "examples": [ + { + "name": "Swapped Status Example", + "description": "Example with swapped status and statusText from pre-fix Postman import", + "request": { + "url": "https://api.example.com/users/123", + "method": "get", + "body": { + "mode": "none" + } + }, + "response": { + "status": "Accepted", + "statusText": "202", + "body": { + "type": "json", + "content": "{\n \"id\": 123,\n \"name\": \"John Doe\"\n}" + } + } + } + ] +}