mirror of
https://github.com/usebruno/bruno.git
synced 2026-07-03 01:18:32 +00:00
Compare commits
2 Commits
fix/env-ta
...
feat/yaml-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17365b0d63 | ||
|
|
0b19b26ce7 |
@@ -5,6 +5,16 @@ const chokidar = require('chokidar');
|
||||
const { hasBruExtension, isWSLPath, normalizeAndResolvePath, normalizeWslPath, sizeInMB } = require('../utils/filesystem');
|
||||
const { bruToEnvJson, bruToJson, bruToJsonViaWorker ,collectionBruToJson } = require('../bru');
|
||||
const { dotenvToJson } = require('@usebruno/lang');
|
||||
const {
|
||||
parseRequest,
|
||||
stringifyRequest,
|
||||
parseCollection,
|
||||
stringifyCollection,
|
||||
parseFolder,
|
||||
stringifyFolder,
|
||||
parseEnvironment,
|
||||
stringifyEnvironment
|
||||
} = require('../filestore');
|
||||
|
||||
const { uuid } = require('../utils/common');
|
||||
const { getRequestUid } = require('../cache/requestUids');
|
||||
@@ -80,7 +90,7 @@ const addEnvironmentFile = async (win, pathname, collectionUid, collectionPath)
|
||||
|
||||
let bruContent = fs.readFileSync(pathname, 'utf8');
|
||||
|
||||
file.data = await bruToEnvJson(bruContent);
|
||||
file.data = await parseEnvironment(bruContent, { format: 'bru' });
|
||||
file.data.name = basename.substring(0, basename.length - 4);
|
||||
file.data.uid = getRequestUid(pathname);
|
||||
|
||||
@@ -209,8 +219,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
try {
|
||||
let bruContent = fs.readFileSync(pathname, 'utf8');
|
||||
|
||||
file.data = await collectionBruToJson(bruContent);
|
||||
|
||||
file.data = await parseCollection(bruContent, { format: 'bru' });
|
||||
hydrateBruCollectionFileWithUuid(file.data);
|
||||
win.webContents.send('main:collection-tree-updated', 'addFile', file);
|
||||
return;
|
||||
@@ -234,8 +243,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
try {
|
||||
let bruContent = fs.readFileSync(pathname, 'utf8');
|
||||
|
||||
file.data = await collectionBruToJson(bruContent);
|
||||
|
||||
file.data = await parseFolder(bruContent, { format: 'bru' });
|
||||
hydrateBruCollectionFileWithUuid(file.data);
|
||||
win.webContents.send('main:collection-tree-updated', 'addFile', file);
|
||||
return;
|
||||
@@ -259,7 +267,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
// If worker thread is not used, we can directly parse the file
|
||||
if (!useWorkerThread) {
|
||||
try {
|
||||
file.data = await bruToJson(bruContent);
|
||||
file.data = await parseRequest(bruContent, { format: 'bru' });
|
||||
file.partial = false;
|
||||
file.loading = false;
|
||||
file.size = sizeInMB(fileStats?.size);
|
||||
@@ -279,7 +287,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
type: 'http-request'
|
||||
};
|
||||
|
||||
const metaJson = await bruToJson(parseBruFileMeta(bruContent), true);
|
||||
const metaJson = await parseRequest(parseBruFileMeta(bruContent), { format: 'bru' });
|
||||
file.data = metaJson;
|
||||
file.partial = true;
|
||||
file.loading = false;
|
||||
@@ -296,7 +304,7 @@ const add = async (win, pathname, collectionUid, collectionPath, useWorkerThread
|
||||
win.webContents.send('main:collection-tree-updated', 'addFile', file);
|
||||
|
||||
// This is to update the file info in the UI
|
||||
file.data = await bruToJsonViaWorker(bruContent);
|
||||
file.data = await parseRequest(bruContent, { format: 'bru', useWorker: true });
|
||||
file.partial = false;
|
||||
file.loading = false;
|
||||
hydrateRequestWithUuid(file.data, pathname);
|
||||
|
||||
@@ -4,116 +4,31 @@ const {
|
||||
jsonToBruV2,
|
||||
bruToEnvJsonV2,
|
||||
envJsonToBruV2,
|
||||
collectionBruToJson: _collectionBruToJson,
|
||||
jsonToCollectionBru: _jsonToCollectionBru
|
||||
collectionBruToJson,
|
||||
jsonToCollectionBru
|
||||
} = require('@usebruno/lang');
|
||||
const BruParserWorker = require('./workers');
|
||||
|
||||
const bruParserWorker = new BruParserWorker();
|
||||
|
||||
const collectionBruToJson = async (data, parsed = false) => {
|
||||
try {
|
||||
const json = parsed ? data : _collectionBruToJson(data);
|
||||
|
||||
const transformedJson = {
|
||||
request: {
|
||||
headers: _.get(json, 'headers', []),
|
||||
auth: _.get(json, 'auth', {}),
|
||||
script: _.get(json, 'script', {}),
|
||||
vars: _.get(json, 'vars', {}),
|
||||
tests: _.get(json, 'tests', '')
|
||||
},
|
||||
docs: _.get(json, 'docs', '')
|
||||
};
|
||||
|
||||
// add meta if it exists
|
||||
// this is only for folder bru file
|
||||
// in the future, all of this will be replaced by standard bru lang
|
||||
if (json.meta) {
|
||||
transformedJson.meta = {
|
||||
name: json.meta.name
|
||||
};
|
||||
}
|
||||
|
||||
return transformedJson;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const jsonToCollectionBru = async (json, isFolder) => {
|
||||
try {
|
||||
const collectionBruJson = {
|
||||
headers: _.get(json, 'request.headers', []),
|
||||
script: {
|
||||
req: _.get(json, 'request.script.req', ''),
|
||||
res: _.get(json, 'request.script.res', '')
|
||||
},
|
||||
vars: {
|
||||
req: _.get(json, 'request.vars.req', []),
|
||||
res: _.get(json, 'request.vars.res', [])
|
||||
},
|
||||
tests: _.get(json, 'request.tests', ''),
|
||||
docs: _.get(json, 'docs', '')
|
||||
};
|
||||
|
||||
// add meta if it exists
|
||||
// this is only for folder bru file
|
||||
// in the future, all of this will be replaced by standard bru lang
|
||||
if (json?.meta) {
|
||||
collectionBruJson.meta = {
|
||||
name: json.meta.name
|
||||
};
|
||||
}
|
||||
|
||||
if (!isFolder) {
|
||||
collectionBruJson.auth = _.get(json, 'request.auth', {});
|
||||
}
|
||||
|
||||
return _jsonToCollectionBru(collectionBruJson);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const bruToEnvJson = async (bru) => {
|
||||
try {
|
||||
const json = bruToEnvJsonV2(bru);
|
||||
|
||||
// the app env format requires each variable to have a type
|
||||
// this need to be evaluated and safely removed
|
||||
// i don't see it being used in schema validation
|
||||
if (json && json.variables && json.variables.length) {
|
||||
_.each(json.variables, (v) => (v.type = 'text'));
|
||||
}
|
||||
|
||||
return json;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const envJsonToBru = async (json) => {
|
||||
try {
|
||||
const bru = envJsonToBruV2(json);
|
||||
return bru;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The transformer function for converting a BRU file to JSON.
|
||||
*
|
||||
* We map the json response from the bru lang and transform it into the DSL
|
||||
* format that the app uses
|
||||
*
|
||||
* @param {string} data The BRU file content.
|
||||
* @param {string} bru The BRU file content.
|
||||
* @returns {object} The JSON representation of the BRU file.
|
||||
*/
|
||||
const bruToJson = (data, parsed = false) => {
|
||||
const parseRequest = async (bru, options = {}) => {
|
||||
try {
|
||||
const json = parsed ? data : bruToJsonV2(data);
|
||||
let json;
|
||||
|
||||
if(options.useWorker) {
|
||||
json = await bruParserWorker?.bruToJson(data);
|
||||
} else {
|
||||
json = bruToJsonV2(bru);
|
||||
}
|
||||
|
||||
let requestType = _.get(json, 'meta.type');
|
||||
if (requestType === 'http') {
|
||||
@@ -153,15 +68,6 @@ const bruToJson = (data, parsed = false) => {
|
||||
}
|
||||
};
|
||||
|
||||
const bruToJsonViaWorker = async (data) => {
|
||||
try {
|
||||
const json = await bruParserWorker?.bruToJson(data);
|
||||
return bruToJson(json, true);
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The transformer function for converting a JSON to BRU file.
|
||||
*
|
||||
@@ -171,7 +77,7 @@ const bruToJsonViaWorker = async (data) => {
|
||||
* @param {object} json The JSON representation of the BRU file.
|
||||
* @returns {string} The BRU file content.
|
||||
*/
|
||||
const jsonToBru = async (json) => {
|
||||
const stringifyRequest = async (json, options = {}) => {
|
||||
let type = _.get(json, 'type');
|
||||
if (type === 'http-request') {
|
||||
type = 'http';
|
||||
@@ -208,59 +114,140 @@ const jsonToBru = async (json) => {
|
||||
docs: _.get(json, 'request.docs', '')
|
||||
};
|
||||
|
||||
const bru = jsonToBruV2(bruJson);
|
||||
return bru;
|
||||
if(options.useWorker) {
|
||||
return await bruParserWorker?.jsonToBru(bruJson);
|
||||
} else {
|
||||
return jsonToBruV2(bruJson);
|
||||
}
|
||||
};
|
||||
|
||||
const jsonToBruViaWorker = async (json) => {
|
||||
let type = _.get(json, 'type');
|
||||
if (type === 'http-request') {
|
||||
type = 'http';
|
||||
} else if (type === 'graphql-request') {
|
||||
type = 'graphql';
|
||||
} else {
|
||||
type = 'http';
|
||||
const parseCollection = async (bru) => {
|
||||
try {
|
||||
const json = collectionBruToJson(bru);
|
||||
|
||||
const transformedJson = {
|
||||
request: {
|
||||
headers: _.get(json, 'headers', []),
|
||||
auth: _.get(json, 'auth', {}),
|
||||
script: _.get(json, 'script', {}),
|
||||
vars: _.get(json, 'vars', {}),
|
||||
tests: _.get(json, 'tests', '')
|
||||
},
|
||||
docs: _.get(json, 'docs', '')
|
||||
};
|
||||
|
||||
return transformedJson;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const sequence = _.get(json, 'seq');
|
||||
const bruJson = {
|
||||
meta: {
|
||||
name: _.get(json, 'name'),
|
||||
type: type,
|
||||
seq: !isNaN(sequence) ? Number(sequence) : 1
|
||||
},
|
||||
http: {
|
||||
method: _.lowerCase(_.get(json, 'request.method')),
|
||||
url: _.get(json, 'request.url'),
|
||||
auth: _.get(json, 'request.auth.mode', 'none'),
|
||||
body: _.get(json, 'request.body.mode', 'none')
|
||||
},
|
||||
params: _.get(json, 'request.params', []),
|
||||
headers: _.get(json, 'request.headers', []),
|
||||
auth: _.get(json, 'request.auth', {}),
|
||||
body: _.get(json, 'request.body', {}),
|
||||
script: _.get(json, 'request.script', {}),
|
||||
vars: {
|
||||
req: _.get(json, 'request.vars.req', []),
|
||||
res: _.get(json, 'request.vars.res', [])
|
||||
},
|
||||
assertions: _.get(json, 'request.assertions', []),
|
||||
tests: _.get(json, 'request.tests', ''),
|
||||
docs: _.get(json, 'request.docs', '')
|
||||
};
|
||||
const stringifyCollection = async (json) => {
|
||||
try {
|
||||
const collectionBruJson = {
|
||||
headers: _.get(json, 'request.headers', []),
|
||||
auth: _.get(json, 'request.auth', {}),
|
||||
script: {
|
||||
req: _.get(json, 'request.script.req', ''),
|
||||
res: _.get(json, 'request.script.res', '')
|
||||
},
|
||||
vars: {
|
||||
req: _.get(json, 'request.vars.req', []),
|
||||
res: _.get(json, 'request.vars.res', [])
|
||||
},
|
||||
tests: _.get(json, 'request.tests', ''),
|
||||
docs: _.get(json, 'docs', '')
|
||||
};
|
||||
|
||||
const bru = await bruParserWorker?.jsonToBru(bruJson)
|
||||
return bru;
|
||||
return jsonToCollectionBru(collectionBruJson);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const parseFolder = async (bru) => {
|
||||
try {
|
||||
const json = collectionBruToJson(bru);
|
||||
|
||||
const transformedJson = {
|
||||
meta: {
|
||||
name: _.get(json, 'meta.name')
|
||||
},
|
||||
request: {
|
||||
headers: _.get(json, 'headers', []),
|
||||
auth: _.get(json, 'auth', {}),
|
||||
script: _.get(json, 'script', {}),
|
||||
vars: _.get(json, 'vars', {}),
|
||||
tests: _.get(json, 'tests', '')
|
||||
},
|
||||
docs: _.get(json, 'docs', '')
|
||||
};
|
||||
|
||||
return transformedJson;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const stringifyFolder = async (json) => {
|
||||
try {
|
||||
const folderBruJson = {
|
||||
meta: {
|
||||
name: _.get(json, 'meta.name')
|
||||
},
|
||||
headers: _.get(json, 'request.headers', []),
|
||||
script: {
|
||||
req: _.get(json, 'request.script.req', ''),
|
||||
res: _.get(json, 'request.script.res', '')
|
||||
},
|
||||
vars: {
|
||||
req: _.get(json, 'request.vars.req', []),
|
||||
res: _.get(json, 'request.vars.res', [])
|
||||
},
|
||||
tests: _.get(json, 'request.tests', ''),
|
||||
docs: _.get(json, 'docs', '')
|
||||
};
|
||||
|
||||
return jsonToCollectionBru(folderBruJson);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const parseEnvironment = async (bru) => {
|
||||
try {
|
||||
const json = bruToEnvJsonV2(bru);
|
||||
|
||||
// the app env format requires each variable to have a type
|
||||
// this need to be evaluated and safely removed
|
||||
// i don't see it being used in schema validation
|
||||
if (json && json.variables && json.variables.length) {
|
||||
_.each(json.variables, (v) => (v.type = 'text'));
|
||||
}
|
||||
|
||||
return json;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
const stringifyEnvironment = async (json) => {
|
||||
try {
|
||||
const bru = envJsonToBruV2(json);
|
||||
return bru;
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
bruToJson,
|
||||
bruToJsonViaWorker,
|
||||
jsonToBru,
|
||||
bruToEnvJson,
|
||||
envJsonToBru,
|
||||
collectionBruToJson,
|
||||
jsonToCollectionBru,
|
||||
jsonToBruViaWorker
|
||||
parseRequest,
|
||||
stringifyRequest,
|
||||
parseCollection,
|
||||
stringifyCollection,
|
||||
parseFolder,
|
||||
stringifyFolder,
|
||||
parseEnvironment,
|
||||
stringifyEnvironment
|
||||
};
|
||||
69
packages/bruno-electron/src/filestore/index.js
Normal file
69
packages/bruno-electron/src/filestore/index.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import {
|
||||
parseRequest as bruParseRequest,
|
||||
stringifyRequest as bruStringifyRequest,
|
||||
parseFolder as bruParseFolder,
|
||||
stringifyFolder as bruStringifyFolder,
|
||||
parseCollection as bruParseCollection,
|
||||
stringifyCollection as bruStringifyCollection,
|
||||
parseEnvironment as bruParseEnvironment,
|
||||
stringifyEnvironment as bruStringifyEnvironment
|
||||
} from './bru';
|
||||
|
||||
const parseRequest = (bru, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruParseRequest(bru);
|
||||
}
|
||||
};
|
||||
|
||||
const stringifyRequest = (json, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruStringifyRequest(json);
|
||||
}
|
||||
};
|
||||
|
||||
const parseFolder = (bru, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruParseFolder(bru);
|
||||
}
|
||||
};
|
||||
|
||||
const stringifyFolder = (json, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruStringifyFolder(json);
|
||||
}
|
||||
};
|
||||
|
||||
const parseCollection = (bru, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruParseCollection(bru);
|
||||
}
|
||||
};
|
||||
|
||||
const stringifyCollection = (json, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruStringifyCollection(json);
|
||||
}
|
||||
};
|
||||
|
||||
const parseEnvironment = (bru, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruParseEnvironment(bru);
|
||||
}
|
||||
};
|
||||
|
||||
const stringifyEnvironment = (json, options = {}) => {
|
||||
if (options.format === 'bru') {
|
||||
return bruStringifyEnvironment(json);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
parseRequest,
|
||||
stringifyRequest,
|
||||
parseFolder,
|
||||
stringifyFolder,
|
||||
parseCollection,
|
||||
stringifyCollection,
|
||||
parseEnvironment,
|
||||
stringifyEnvironment
|
||||
};
|
||||
346
packages/bruno-lang/v3/src/common.js
Normal file
346
packages/bruno-lang/v3/src/common.js
Normal file
@@ -0,0 +1,346 @@
|
||||
const _ = require('lodash');
|
||||
|
||||
const getMeta = (json) => {
|
||||
const sequence = _.get(json, 'seq');
|
||||
const meta = {
|
||||
name: _.get(json, 'name')
|
||||
};
|
||||
|
||||
const description = _.get(json, 'description');
|
||||
if (description) {
|
||||
meta.description = description;
|
||||
}
|
||||
|
||||
meta.seq = !isNaN(sequence) ? Number(sequence) : 1;
|
||||
|
||||
return meta;
|
||||
};
|
||||
|
||||
const getParams = (req) => {
|
||||
return {
|
||||
query: _.map(_.filter(req?.params || [], param => param.type === 'query'), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type: param.type
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
}),
|
||||
path: _.map(_.filter(req?.params || [], param => param.type === 'path'), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type: param.type
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
const getHeaders = (req) => {
|
||||
return _.map(_.get(req, 'headers', []), (header) => {
|
||||
const headerObj = {
|
||||
name: header.name,
|
||||
value: header.value,
|
||||
};
|
||||
|
||||
if (header.description) {
|
||||
headerObj.description = header.description;
|
||||
}
|
||||
|
||||
if (header.enabled === false) {
|
||||
headerObj.disabled = true;
|
||||
}
|
||||
|
||||
return headerObj;
|
||||
});
|
||||
};
|
||||
|
||||
const getBody = (req) => {
|
||||
const body = _.get(req, 'body', {});
|
||||
const mode = _.get(body, 'mode', 'none');
|
||||
|
||||
if (mode === 'none') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mode === 'graphql') {
|
||||
return {
|
||||
type: 'graphql',
|
||||
query: _.get(body, 'graphql.query', ''),
|
||||
variables: _.get(body, 'graphql.variables', '')
|
||||
};
|
||||
}
|
||||
|
||||
if (mode === 'sparql') {
|
||||
return {
|
||||
type: 'sparql',
|
||||
query: _.get(body, 'sparql', '')
|
||||
};
|
||||
}
|
||||
|
||||
if (mode === 'formUrlEncoded') {
|
||||
return {
|
||||
type: 'form-urlencoded',
|
||||
data: _.map(_.get(body, 'formUrlEncoded', []), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
if (mode === 'multipartForm') {
|
||||
return {
|
||||
type: 'multipart-form',
|
||||
data: _.map(_.get(body, 'multipartForm', []), (param) => {
|
||||
const paramObj = {
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type: param.type
|
||||
};
|
||||
|
||||
if (param.description) {
|
||||
paramObj.description = param.description;
|
||||
}
|
||||
|
||||
if (param.enabled === false) {
|
||||
paramObj.disabled = true;
|
||||
}
|
||||
|
||||
if (param.contentType) {
|
||||
paramObj.content_type = param.contentType;
|
||||
}
|
||||
|
||||
return paramObj;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
let data = '';
|
||||
switch(mode) {
|
||||
case 'json':
|
||||
data = _.get(body, 'json', '');
|
||||
break;
|
||||
case 'text':
|
||||
data = _.get(body, 'text', '');
|
||||
break;
|
||||
case 'xml':
|
||||
data = _.get(body, 'xml', '');
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
type: mode,
|
||||
data
|
||||
};
|
||||
};
|
||||
|
||||
const getAuth = (req) => {
|
||||
const auth = {};
|
||||
const mode = _.get(req, 'auth.mode', 'none');
|
||||
|
||||
if (req?.auth?.awsv4) {
|
||||
auth.awsv4 = {
|
||||
access_key_id: req?.auth?.awsv4?.accessKeyId,
|
||||
secret_access_key: req?.auth?.awsv4?.secretAccessKey,
|
||||
session_token: req?.auth?.awsv4?.sessionToken,
|
||||
service: req?.auth?.awsv4?.service,
|
||||
region: req?.auth?.awsv4?.region,
|
||||
profile_name: req?.auth?.awsv4?.profileName
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.basic) {
|
||||
auth.basic = {
|
||||
username: req?.auth?.basic?.username,
|
||||
password: req?.auth?.basic?.password
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.bearer) {
|
||||
auth.bearer = {
|
||||
token: req?.auth?.bearer?.token
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.digest) {
|
||||
auth.digest = {
|
||||
username: req?.auth?.digest?.username,
|
||||
password: req?.auth?.digest?.password
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.ntlm) {
|
||||
auth.ntlm = {
|
||||
username: req?.auth?.ntlm?.username,
|
||||
password: req?.auth?.ntlm?.password,
|
||||
domain: req?.auth?.ntlm?.domain
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.oauth2) {
|
||||
auth.oauth2 = {};
|
||||
|
||||
if (req?.auth?.oauth2?.grantType === 'password') {
|
||||
auth.oauth2 = {
|
||||
grant_type: 'password',
|
||||
access_token_url: req?.auth?.oauth2?.accessTokenUrl || '',
|
||||
username: req?.auth?.oauth2?.username || '',
|
||||
password: req?.auth?.oauth2?.password || '',
|
||||
client_id: req?.auth?.oauth2?.clientId || '',
|
||||
client_secret: req?.auth?.oauth2?.clientSecret || '',
|
||||
scope: req?.auth?.oauth2?.scope || ''
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.oauth2?.grantType === 'authorization_code') {
|
||||
auth.oauth2 = {
|
||||
grant_type: 'authorization_code',
|
||||
callback_url: req?.auth?.oauth2?.callbackUrl || '',
|
||||
authorization_url: req?.auth?.oauth2?.authorizationUrl || '',
|
||||
access_token_url: req?.auth?.oauth2?.accessTokenUrl || '',
|
||||
client_id: req?.auth?.oauth2?.clientId || '',
|
||||
client_secret: req?.auth?.oauth2?.clientSecret || '',
|
||||
scope: req?.auth?.oauth2?.scope || '',
|
||||
state: req?.auth?.oauth2?.state || '',
|
||||
pkce: req?.auth?.oauth2?.pkce || false
|
||||
};
|
||||
}
|
||||
|
||||
if (req?.auth?.oauth2?.grantType === 'client_credentials') {
|
||||
auth.oauth2 = {
|
||||
grant_type: 'client_credentials',
|
||||
access_token_url: req?.auth?.oauth2?.accessTokenUrl || '',
|
||||
client_id: req?.auth?.oauth2?.clientId || '',
|
||||
client_secret: req?.auth?.oauth2?.clientSecret || '',
|
||||
scope: req?.auth?.oauth2?.scope || ''
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (req?.auth?.apikey) {
|
||||
auth.apikey = {
|
||||
key: req?.auth?.apikey?.key,
|
||||
value: req?.auth?.apikey?.value,
|
||||
placement: req?.auth?.apikey?.placement
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: mode,
|
||||
...auth
|
||||
};
|
||||
};
|
||||
|
||||
const getVars = (req) => {
|
||||
const preRequest = _.map(_.get(req, 'vars.req', []), (variable) => {
|
||||
const varObj = {
|
||||
name: variable.name,
|
||||
value: variable.value
|
||||
};
|
||||
|
||||
if (variable.description) {
|
||||
varObj.description = variable.description;
|
||||
}
|
||||
|
||||
if (variable.enabled === false) {
|
||||
varObj.disabled = true;
|
||||
}
|
||||
|
||||
return varObj;
|
||||
});
|
||||
|
||||
const postResponse = _.map(_.get(req, 'vars.res', []), (variable) => {
|
||||
const varObj = {
|
||||
name: variable.name,
|
||||
value: variable.value
|
||||
};
|
||||
|
||||
if (variable.description) {
|
||||
varObj.description = variable.description;
|
||||
}
|
||||
|
||||
if (variable.enabled === false) {
|
||||
varObj.disabled = true;
|
||||
}
|
||||
|
||||
return varObj;
|
||||
});
|
||||
|
||||
const vars = {};
|
||||
|
||||
if(preRequest.length) {
|
||||
vars['pre-request'] = preRequest;
|
||||
}
|
||||
|
||||
if(postResponse.length) {
|
||||
vars['post-response'] = postResponse;
|
||||
}
|
||||
|
||||
return !_.isEmpty(vars) ? vars : null;
|
||||
};
|
||||
|
||||
const getScripts = (req) => {
|
||||
const preRequestScript = _.get(req, 'script.req', '');
|
||||
const postResponseScript = _.get(req, 'script.res', '');
|
||||
|
||||
const scripts = {};
|
||||
if (preRequestScript) {
|
||||
scripts['pre-request'] = preRequestScript;
|
||||
}
|
||||
if (postResponseScript) {
|
||||
scripts['post-response'] = postResponseScript;
|
||||
}
|
||||
|
||||
return !_.isEmpty(scripts) ? scripts : null;
|
||||
};
|
||||
|
||||
const getTests = (req) => {
|
||||
return _.get(req, 'tests', '');
|
||||
};
|
||||
|
||||
const getDocs = (req) => {
|
||||
return _.get(req, 'docs', '');
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getMeta,
|
||||
getParams,
|
||||
getHeaders,
|
||||
getBody,
|
||||
getAuth,
|
||||
getVars,
|
||||
getScripts,
|
||||
getTests,
|
||||
getDocs
|
||||
};
|
||||
8
packages/bruno-lang/v3/src/index.js
Normal file
8
packages/bruno-lang/v3/src/index.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const _ = require('lodash');
|
||||
const stringifyRequest = require('./stringifyRequest');
|
||||
const parseRequest = require('./parseRequest');
|
||||
|
||||
module.exports = {
|
||||
parseRequest,
|
||||
stringifyRequest,
|
||||
};
|
||||
235
packages/bruno-lang/v3/src/parseRequest.js
Normal file
235
packages/bruno-lang/v3/src/parseRequest.js
Normal file
@@ -0,0 +1,235 @@
|
||||
const yaml = require('js-yaml');
|
||||
const _ = require('lodash');
|
||||
|
||||
const parseRequest = (yamlContent) => {
|
||||
const yamlData = yaml.load(yamlContent);
|
||||
const isHttp = !!yamlData.http;
|
||||
const request = isHttp ? yamlData.http : yamlData.graphql;
|
||||
|
||||
const item = {
|
||||
name: yamlData.meta.name,
|
||||
description: yamlData.meta.description || '',
|
||||
seq: yamlData.meta.seq,
|
||||
type: isHttp ? 'http-request' : 'graphql-request'
|
||||
};
|
||||
|
||||
item.request = {
|
||||
method: request.method.toUpperCase(),
|
||||
url: request.url,
|
||||
headers: _.map(request.headers || [], header => ({
|
||||
name: header.name,
|
||||
value: header.value,
|
||||
description: header.description || '',
|
||||
enabled: !header.disabled
|
||||
})),
|
||||
params: _.flatMap(request.params || {}, (params, type) => {
|
||||
return _.map(params, param => ({
|
||||
name: param.name,
|
||||
value: param.value,
|
||||
type,
|
||||
description: param.description || '',
|
||||
enabled: !param.disabled
|
||||
}));
|
||||
}),
|
||||
body: {
|
||||
mode: 'none',
|
||||
json: null,
|
||||
text: null,
|
||||
xml: null,
|
||||
sparql: null,
|
||||
formUrlEncoded: [],
|
||||
multipartForm: [],
|
||||
graphql: null
|
||||
},
|
||||
auth: {
|
||||
mode: 'none',
|
||||
awsv4: null,
|
||||
basic: null,
|
||||
bearer: null,
|
||||
ntlm: null,
|
||||
digest: null,
|
||||
oauth2: null,
|
||||
wsse: null,
|
||||
apikey: null
|
||||
},
|
||||
vars: {
|
||||
req: [],
|
||||
res: []
|
||||
},
|
||||
script: {
|
||||
req: '',
|
||||
res: ''
|
||||
},
|
||||
tests: '',
|
||||
docs: ''
|
||||
};
|
||||
|
||||
// Handle body
|
||||
if (request.body) {
|
||||
item.request.body.mode = request.body.type;
|
||||
switch(request.body.type) {
|
||||
case 'json':
|
||||
item.request.body.json = request.body.data;
|
||||
break;
|
||||
case 'text':
|
||||
item.request.body.text = request.body.data;
|
||||
break;
|
||||
case 'xml':
|
||||
item.request.body.xml = request.body.data;
|
||||
break;
|
||||
case 'sparql':
|
||||
item.request.body.sparql = request.body.data;
|
||||
break;
|
||||
case 'formUrlEncoded':
|
||||
item.request.body.formUrlEncoded = _.map(request.body.data, formItem => ({
|
||||
name: formItem.name,
|
||||
value: formItem.value,
|
||||
description: formItem.description || '',
|
||||
enabled: !formItem.disabled
|
||||
}));
|
||||
break;
|
||||
case 'multipartForm':
|
||||
item.request.body.multipartForm = _.map(request.body.data, formItem => ({
|
||||
name: formItem.name,
|
||||
value: formItem.value,
|
||||
description: formItem.description || '',
|
||||
enabled: !formItem.disabled,
|
||||
contentType: formItem.content_type || ''
|
||||
}));
|
||||
break;
|
||||
case 'graphql':
|
||||
item.request.body.graphql = {
|
||||
query: request.body.data.query || '',
|
||||
variables: request.body.data.variables || ''
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle auth
|
||||
if (request.auth) {
|
||||
item.request.auth.mode = request.auth.type;
|
||||
|
||||
switch(request.auth.type) {
|
||||
case 'awsv4':
|
||||
item.request.auth.awsv4 = {
|
||||
accessKeyId: request.auth.access_key_id,
|
||||
secretAccessKey: request.auth.secret_access_key,
|
||||
sessionToken: request.auth.session_token,
|
||||
service: request.auth.service,
|
||||
region: request.auth.region,
|
||||
profileName: request.auth.profile_name
|
||||
}
|
||||
break;
|
||||
case 'basic':
|
||||
item.request.auth.basic = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password
|
||||
}
|
||||
break;
|
||||
case 'bearer':
|
||||
item.request.auth.bearer = {
|
||||
token: request.auth.token
|
||||
}
|
||||
break;
|
||||
case 'digest':
|
||||
item.request.auth.digest = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password
|
||||
}
|
||||
break;
|
||||
case 'ntlm':
|
||||
item.request.auth.ntlm = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password,
|
||||
domain: request.auth.domain
|
||||
}
|
||||
break;
|
||||
case 'wsse':
|
||||
item.request.auth.wsse = {
|
||||
username: request.auth.username,
|
||||
password: request.auth.password
|
||||
}
|
||||
break;
|
||||
case 'apikey':
|
||||
item.request.auth.apikey = {
|
||||
key: request.auth.key,
|
||||
value: request.auth.value,
|
||||
placement: request.auth.placement
|
||||
}
|
||||
break;
|
||||
case 'oauth2':
|
||||
if (request.auth.grant_type === 'password') {
|
||||
item.request.auth.oauth2 = {
|
||||
grantType: 'password',
|
||||
accessTokenUrl: request.auth.access_token_url || '',
|
||||
clientId: request.auth.client_id || '',
|
||||
clientSecret: request.auth.client_secret || '',
|
||||
scope: request.auth.scope || '',
|
||||
username: request.auth.username || '',
|
||||
password: request.auth.password || ''
|
||||
};
|
||||
} else if (request.auth.grant_type === 'authorization_code') {
|
||||
item.request.auth.oauth2 = {
|
||||
grantType: 'authorization_code',
|
||||
accessTokenUrl: request.auth.access_token_url || '',
|
||||
clientId: request.auth.client_id || '',
|
||||
clientSecret: request.auth.client_secret || '',
|
||||
scope: request.auth.scope || '',
|
||||
callbackUrl: request.auth.callback_url || '',
|
||||
authorizationUrl: request.auth.authorization_url || '',
|
||||
state: request.auth.state || '',
|
||||
pkce: request.auth.pkce || false
|
||||
};
|
||||
} else if (request.auth.grant_type === 'client_credentials') {
|
||||
item.request.auth.oauth2 = {
|
||||
grantType: 'client_credentials',
|
||||
accessTokenUrl: request.auth.access_token_url || '',
|
||||
clientId: request.auth.client_id || '',
|
||||
clientSecret: request.auth.client_secret || '',
|
||||
scope: request.auth.scope || ''
|
||||
};
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle vars
|
||||
if (yamlData.vars) {
|
||||
item.request.vars = {
|
||||
req: _.map(yamlData.vars['pre-request'] || [], v => ({
|
||||
name: v.name,
|
||||
value: v.value,
|
||||
description: v.description || '',
|
||||
enabled: !v.disabled
|
||||
})),
|
||||
res: _.map(yamlData.vars['post-response'] || [], v => ({
|
||||
name: v.name,
|
||||
value: v.value,
|
||||
description: v.description || '',
|
||||
enabled: !v.disabled
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
// Handle scripts
|
||||
if (yamlData.scripts) {
|
||||
item.request.script = {
|
||||
req: yamlData.scripts['pre-request'] || '',
|
||||
res: yamlData.scripts['post-response'] || ''
|
||||
};
|
||||
}
|
||||
|
||||
// Handle tests and docs
|
||||
if (yamlData.tests) {
|
||||
item.request.tests = yamlData.tests;
|
||||
}
|
||||
|
||||
if (yamlData.docs) {
|
||||
item.request.docs = yamlData.docs;
|
||||
}
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
module.exports = parseRequest;
|
||||
54
packages/bruno-lang/v3/src/stringifyRequest.js
Normal file
54
packages/bruno-lang/v3/src/stringifyRequest.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const yaml = require('js-yaml');
|
||||
const _ = require('lodash');
|
||||
const { getMeta, getParams, getHeaders, getVars, getScripts, getBody, getAuth, getTests, getDocs } = require('./common');
|
||||
|
||||
const stringifyRequest = (json) => {
|
||||
const request = json?.request;
|
||||
const requestBody = getBody(request);
|
||||
const requestAuth = getAuth(request);
|
||||
const isGraphql = requestBody?.type === 'graphql';
|
||||
|
||||
const requestData = {
|
||||
method: _.lowerCase(_.get(json, 'request.method')),
|
||||
url: _.get(json, 'request.url'),
|
||||
params: getParams(request),
|
||||
headers: getHeaders(request),
|
||||
};
|
||||
|
||||
if (requestBody && requestBody.type !== 'none') {
|
||||
requestData.body = requestBody;
|
||||
}
|
||||
|
||||
if (requestAuth && requestAuth.mode !== 'none') {
|
||||
requestData.auth = requestAuth;
|
||||
}
|
||||
|
||||
const finalJson = {
|
||||
meta: getMeta(json),
|
||||
[isGraphql ? 'graphql' : 'http']: requestData
|
||||
};
|
||||
|
||||
const vars = getVars(request);
|
||||
if (vars) {
|
||||
finalJson.vars = vars;
|
||||
}
|
||||
|
||||
const scripts = getScripts(request);
|
||||
if (scripts) {
|
||||
finalJson.scripts = scripts;
|
||||
}
|
||||
|
||||
const tests = getTests(request);
|
||||
if (tests) {
|
||||
finalJson.tests = tests;
|
||||
}
|
||||
|
||||
const docs = getDocs(request);
|
||||
if (docs) {
|
||||
finalJson.docs = docs;
|
||||
}
|
||||
|
||||
return yaml.dump(finalJson);
|
||||
};
|
||||
|
||||
module.exports = stringifyRequest;
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "Get User GraphQL",
|
||||
"seq": 1,
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.example.com/graphql",
|
||||
"headers": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "graphql",
|
||||
"graphql": {
|
||||
"query": "query GetUser($id: ID!) {\n user(id: $id) {\n id\n name\n email\n }\n}",
|
||||
"variables": "{\n \"id\": \"123\"\n}"
|
||||
}
|
||||
},
|
||||
"auth": {
|
||||
"mode": "bearer",
|
||||
"bearer": {
|
||||
"token": "jwt-token"
|
||||
}
|
||||
},
|
||||
"vars": {
|
||||
"req": [
|
||||
{
|
||||
"name": "userId",
|
||||
"value": "123"
|
||||
}
|
||||
]
|
||||
},
|
||||
"script": {
|
||||
"req": "// Pre-request script for GraphQL"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
meta:
|
||||
name: Get User GraphQL
|
||||
seq: 1
|
||||
graphql:
|
||||
method: post
|
||||
url: https://api.example.com/graphql
|
||||
params:
|
||||
query: []
|
||||
path: []
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: graphql
|
||||
query: |-
|
||||
query GetUser($id: ID!) {
|
||||
user(id: $id) {
|
||||
id
|
||||
name
|
||||
email
|
||||
}
|
||||
}
|
||||
variables: |-
|
||||
{
|
||||
"id": "123"
|
||||
}
|
||||
auth:
|
||||
type: bearer
|
||||
bearer:
|
||||
token: jwt-token
|
||||
vars:
|
||||
pre-request:
|
||||
- name: userId
|
||||
value: '123'
|
||||
scripts:
|
||||
pre-request: // Pre-request script for GraphQL
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "HTTP Methods",
|
||||
"seq": 1,
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"url": "https://api.example.com/users",
|
||||
"headers": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json",
|
||||
"description": "Content type header",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "Accept",
|
||||
"value": "application/json",
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"params": [
|
||||
{
|
||||
"name": "userId",
|
||||
"value": "123",
|
||||
"type": "path",
|
||||
"description": "User ID parameter",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"name": "filter",
|
||||
"value": "active",
|
||||
"type": "query",
|
||||
"enabled": false
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "json",
|
||||
"json": "{\n \"name\": \"John Doe\",\n \"email\": \"john@example.com\"\n}"
|
||||
},
|
||||
"auth": {
|
||||
"mode": "basic",
|
||||
"basic": {
|
||||
"username": "admin",
|
||||
"password": "secret"
|
||||
}
|
||||
},
|
||||
"vars": {
|
||||
"req": [
|
||||
{
|
||||
"name": "userId",
|
||||
"value": "123",
|
||||
"description": "User ID variable",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"res": [
|
||||
{
|
||||
"name": "token",
|
||||
"value": "response.token",
|
||||
"enabled": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"script": {
|
||||
"req": "// Pre-request script\nconsole.log('pre-request');",
|
||||
"res": "// Post-response script\nconsole.log('post-response');"
|
||||
},
|
||||
"tests": "// Test script\nassert.response.status === 200;",
|
||||
"docs": "# User Creation API\nThis endpoint creates a new user."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
meta:
|
||||
name: HTTP Methods
|
||||
seq: 1
|
||||
http:
|
||||
method: post
|
||||
url: https://api.example.com/users
|
||||
params:
|
||||
query:
|
||||
- name: filter
|
||||
value: active
|
||||
type: query
|
||||
disabled: true
|
||||
path:
|
||||
- name: userId
|
||||
value: '123'
|
||||
type: path
|
||||
description: User ID parameter
|
||||
headers:
|
||||
- name: Content-Type
|
||||
value: application/json
|
||||
description: Content type header
|
||||
- name: Accept
|
||||
value: application/json
|
||||
disabled: true
|
||||
body:
|
||||
type: json
|
||||
data: |-
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "john@example.com"
|
||||
}
|
||||
auth:
|
||||
type: basic
|
||||
basic:
|
||||
username: admin
|
||||
password: secret
|
||||
vars:
|
||||
pre-request:
|
||||
- name: userId
|
||||
value: '123'
|
||||
description: User ID variable
|
||||
post-response:
|
||||
- name: token
|
||||
value: response.token
|
||||
disabled: true
|
||||
scripts:
|
||||
pre-request: |-
|
||||
// Pre-request script
|
||||
console.log('pre-request');
|
||||
post-response: |-
|
||||
// Post-response script
|
||||
console.log('post-response');
|
||||
tests: |-
|
||||
// Test script
|
||||
assert.response.status === 200;
|
||||
docs: |-
|
||||
# User Creation API
|
||||
This endpoint creates a new user.
|
||||
103
packages/bruno-lang/v3/tests/stringifyRequest/graphql.test.js
Normal file
103
packages/bruno-lang/v3/tests/stringifyRequest/graphql.test.js
Normal file
@@ -0,0 +1,103 @@
|
||||
const { stringifyRequest } = require('../../src');
|
||||
const yaml = require('js-yaml');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('GraphQL Request Handling', () => {
|
||||
const loadFixture = (filename) => {
|
||||
const filePath = path.join(__dirname, '__fixtures__', filename);
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
};
|
||||
|
||||
it('should generate exact YAML matching the fixture', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
const expectedYaml = fs.readFileSync(
|
||||
path.join(__dirname, '__fixtures__', 'graphql-request.yml'),
|
||||
'utf8'
|
||||
);
|
||||
const generatedYaml = stringifyRequest(json);
|
||||
|
||||
// Normalize line endings and whitespace for comparison
|
||||
const normalizeString = (str) => str.replace(/\r\n/g, '\n').trim();
|
||||
expect(normalizeString(generatedYaml)).toBe(normalizeString(expectedYaml));
|
||||
});
|
||||
|
||||
it('should correctly format GraphQL request', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
// Verify GraphQL section exists instead of HTTP
|
||||
expect(result.graphql).toBeDefined();
|
||||
expect(result.http).toBeUndefined();
|
||||
|
||||
// Verify basic properties
|
||||
expect(result.graphql.method).toBe('post');
|
||||
expect(result.graphql.url).toBe('https://api.example.com/graphql');
|
||||
|
||||
// Verify headers
|
||||
expect(result.graphql.headers).toHaveLength(1);
|
||||
expect(result.graphql.headers[0]).toEqual({
|
||||
name: 'Content-Type',
|
||||
value: 'application/json'
|
||||
});
|
||||
|
||||
// Verify body
|
||||
expect(result.graphql.body).toEqual({
|
||||
type: 'graphql',
|
||||
query: 'query GetUser($id: ID!) {\n user(id: $id) {\n id\n name\n email\n }\n}',
|
||||
variables: '{\n \"id\": \"123\"\n}'
|
||||
});
|
||||
|
||||
// Verify auth
|
||||
expect(result.graphql.auth).toEqual({
|
||||
type: 'bearer',
|
||||
bearer: {
|
||||
token: 'jwt-token'
|
||||
}
|
||||
});
|
||||
|
||||
// Verify vars
|
||||
expect(result.vars['pre-request']).toHaveLength(1);
|
||||
expect(result.vars['pre-request'][0]).toEqual({
|
||||
name: 'userId',
|
||||
value: '123'
|
||||
});
|
||||
|
||||
// Verify scripts
|
||||
expect(result.scripts['pre-request']).toBe('// Pre-request script for GraphQL');
|
||||
});
|
||||
|
||||
it('should handle GraphQL request without variables', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
json.request.body.graphql.variables = '';
|
||||
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
expect(result.graphql.body.variables).toBe('');
|
||||
});
|
||||
|
||||
it('should handle GraphQL request without optional components', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
|
||||
// Remove optional components
|
||||
delete json.request.auth;
|
||||
delete json.request.vars;
|
||||
delete json.request.script;
|
||||
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.graphql.auth).toEqual({ type: 'none' });
|
||||
expect(result.vars).toBeUndefined();
|
||||
expect(result.scripts).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should detect GraphQL request based on body mode', () => {
|
||||
const json = loadFixture('graphql-request.json');
|
||||
|
||||
// Change URL but keep GraphQL body
|
||||
json.request.url = 'https://api.example.com/not-graphql';
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.graphql).toBeDefined();
|
||||
expect(result.http).toBeUndefined();
|
||||
});
|
||||
});
|
||||
244
packages/bruno-lang/v3/tests/stringifyRequest/http.test.js
Normal file
244
packages/bruno-lang/v3/tests/stringifyRequest/http.test.js
Normal file
@@ -0,0 +1,244 @@
|
||||
const { stringifyRequest } = require('../../src');
|
||||
const yaml = require('js-yaml');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
describe('HTTP Request Handling', () => {
|
||||
const loadFixture = (filename) => {
|
||||
const filePath = path.join(__dirname, '__fixtures__', filename);
|
||||
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||
};
|
||||
|
||||
it('should generate exact YAML matching the fixture', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const expectedYaml = fs.readFileSync(
|
||||
path.join(__dirname, '__fixtures__', 'http-request.yml'),
|
||||
'utf8'
|
||||
);
|
||||
const generatedYaml = stringifyRequest(json);
|
||||
|
||||
// Normalize line endings and whitespace for comparison
|
||||
const normalizeString = (str) => str.replace(/\r\n/g, '\n').trim();
|
||||
expect(normalizeString(generatedYaml)).toBe(normalizeString(expectedYaml));
|
||||
});
|
||||
|
||||
it('should correctly format basic HTTP request', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
// Verify HTTP section exists instead of GraphQL
|
||||
expect(result.http).toBeDefined();
|
||||
expect(result.graphql).toBeUndefined();
|
||||
|
||||
// Verify basic properties
|
||||
expect(result.meta.name).toBe('HTTP Methods');
|
||||
expect(result.meta.seq).toBe(1);
|
||||
expect(result.http.method).toBe('post');
|
||||
expect(result.http.url).toBe('https://api.example.com/users');
|
||||
});
|
||||
|
||||
it('should handle request with query parameters', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.params.query).toEqual([
|
||||
{
|
||||
name: 'filter',
|
||||
value: 'active',
|
||||
type: 'query',
|
||||
disabled: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle request with path parameters', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.params.path).toEqual([
|
||||
{
|
||||
name: 'userId',
|
||||
value: '123',
|
||||
type: 'path',
|
||||
description: 'User ID parameter'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle request with headers', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.headers).toEqual([
|
||||
{
|
||||
name: 'Content-Type',
|
||||
value: 'application/json',
|
||||
description: 'Content type header'
|
||||
},
|
||||
{
|
||||
name: 'Accept',
|
||||
value: 'application/json',
|
||||
disabled: true
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
describe('Body Handling', () => {
|
||||
it('should handle JSON body', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.body).toEqual({
|
||||
type: 'json',
|
||||
data: '{\n "name": "John Doe",\n "email": "john@example.com"\n}'
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle form-urlencoded body', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.body = {
|
||||
mode: 'formUrlEncoded',
|
||||
formUrlEncoded: [
|
||||
{ name: 'username', value: 'johndoe', description: 'Username field', enabled: true },
|
||||
{ name: 'password', value: 'secret', enabled: false }
|
||||
]
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.body).toEqual({
|
||||
type: 'form-urlencoded',
|
||||
data: [
|
||||
{ name: 'username', value: 'johndoe', description: 'Username field' },
|
||||
{ name: 'password', value: 'secret', disabled: true }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multipart-form body', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.body = {
|
||||
mode: 'multipartForm',
|
||||
multipartForm: [
|
||||
{ name: 'file', value: ['path/to/file'], type: 'file', enabled: true },
|
||||
{ name: 'description', value: 'profile photo', type: 'text', enabled: true }
|
||||
]
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.body).toEqual({
|
||||
type: 'multipart-form',
|
||||
data: [
|
||||
{ name: 'file', value: ['path/to/file'], type: 'file' },
|
||||
{ name: 'description', value: 'profile photo', type: 'text' }
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Auth Handling', () => {
|
||||
it('should handle basic auth', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.auth).toEqual({
|
||||
type: 'basic',
|
||||
basic: {
|
||||
username: 'admin',
|
||||
password: 'secret'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle bearer auth', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.auth = {
|
||||
mode: 'bearer',
|
||||
bearer: { token: 'xyz123' }
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.auth).toEqual({
|
||||
type: 'bearer',
|
||||
bearer: {
|
||||
token: 'xyz123'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle oauth2 password grant', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.auth = {
|
||||
mode: 'oauth2',
|
||||
oauth2: {
|
||||
grantType: 'password',
|
||||
accessTokenUrl: 'https://api.example.com/oauth/token',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
clientId: 'client123',
|
||||
clientSecret: 'secret123',
|
||||
scope: 'read write'
|
||||
}
|
||||
};
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.auth).toEqual({
|
||||
type: 'oauth2',
|
||||
oauth2: {
|
||||
grant_type: 'password',
|
||||
access_token_url: 'https://api.example.com/oauth/token',
|
||||
username: 'user',
|
||||
password: 'pass',
|
||||
client_id: 'client123',
|
||||
client_secret: 'secret123',
|
||||
scope: 'read write'
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variables and Scripts', () => {
|
||||
it('should handle pre-request variables', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.vars['pre-request']).toEqual([
|
||||
{ name: 'userId', value: '123', description: 'User ID variable' }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle post-response variables', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.vars['post-response']).toEqual([
|
||||
{ name: 'token', value: 'response.token', disabled: true }
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle scripts', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.scripts['pre-request']).toBe('// Pre-request script\nconsole.log(\'pre-request\');');
|
||||
expect(result.scripts['post-response']).toBe('// Post-response script\nconsole.log(\'post-response\');');
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle tests and docs', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.tests).toBe('// Test script\nassert.response.status === 200;');
|
||||
expect(result.docs).toBe('# User Creation API\nThis endpoint creates a new user.');
|
||||
});
|
||||
|
||||
it('should handle disabled components', () => {
|
||||
const json = loadFixture('http-request.json');
|
||||
json.request.headers[0].enabled = false;
|
||||
json.request.params[0].enabled = false;
|
||||
const result = yaml.load(stringifyRequest(json));
|
||||
|
||||
expect(result.http.headers[0].disabled).toBe(true);
|
||||
expect(result.http.params.query[0].disabled).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -41,7 +41,7 @@ const varsSchema = Yup.object({
|
||||
|
||||
// todo
|
||||
// anoop(4 feb 2023) - nobody uses this, and it needs to be removed
|
||||
local: Yup.boolean()
|
||||
local: Yup.boolean().optional()
|
||||
})
|
||||
.noUnknown(true)
|
||||
.strict();
|
||||
@@ -298,9 +298,10 @@ const folderRootSchema = Yup.object({
|
||||
|
||||
const itemSchema = Yup.object({
|
||||
uid: uidSchema,
|
||||
name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'),
|
||||
description: Yup.string().nullable(),
|
||||
type: Yup.string().oneOf(['http-request', 'graphql-request', 'folder', 'js']).required('type is required'),
|
||||
seq: Yup.number().min(1),
|
||||
name: Yup.string().min(1, 'name must be at least 1 character').required('name is required'),
|
||||
request: requestSchema.when('type', {
|
||||
is: (type) => ['http-request', 'graphql-request'].includes(type),
|
||||
then: (schema) => schema.required('request is required when item-type is request')
|
||||
|
||||
Reference in New Issue
Block a user