feat: making request and response scripts work

This commit is contained in:
Anoop M D 2023-02-06 23:00:50 +05:30
parent 60c96f7d27
commit 22a14aa67a
15 changed files with 153 additions and 86 deletions

View File

@ -89,7 +89,7 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
</div>
) : null}
</div>
<section className="flex w-full mt-5">{getTabPanel(focusedTab.requestPaneTab)}</section>
<section className={`flex w-full ${focusedTab.requestPaneTab === 'script' ? '' : 'mt-5'}`}>{getTabPanel(focusedTab.requestPaneTab)}</section>
</StyledWrapper>
);
};

View File

@ -2,8 +2,12 @@ import styled from 'styled-components';
const StyledWrapper = styled.div`
div.CodeMirror {
/* todo: find a better way */
height: calc(100vh - 220px);
height: inherit;
}
div.title {
color: rgb(155 155 155);
font-weight: 500;
}
`;

View File

@ -2,20 +2,21 @@ import React from 'react';
import get from 'lodash/get';
import { useDispatch } from 'react-redux';
import CodeEditor from 'components/CodeEditor';
import { updateRequestScript } from 'providers/ReduxStore/slices/collections';
import { updateRequestScript, updateResponseScript } from 'providers/ReduxStore/slices/collections';
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import { useTheme } from 'providers/Theme';
import StyledWrapper from './StyledWrapper';
const Script = ({ item, collection }) => {
const dispatch = useDispatch();
const script = item.draft ? get(item, 'draft.request.script') : get(item, 'request.script');
const requestScript = item.draft ? get(item, 'draft.request.script.req') : get(item, 'request.script.req');
const responseScript = item.draft ? get(item, 'draft.request.script.res') : get(item, 'request.script.res');
const {
storedTheme
} = useTheme();
const onEdit = (value) => {
const onRequestScriptEdit = (value) => {
dispatch(
updateRequestScript({
script: value,
@ -25,19 +26,43 @@ const Script = ({ item, collection }) => {
);
};
const onResponseScriptEdit = (value) => {
dispatch(
updateResponseScript({
script: value,
itemUid: item.uid,
collectionUid: collection.uid
})
);
};
const onRun = () => dispatch(sendRequest(item, collection.uid));
const onSave = () => dispatch(saveRequest(item.uid, collection.uid));
return (
<StyledWrapper className="w-full">
<CodeEditor
collection={collection} value={script || ''}
theme={storedTheme}
onEdit={onEdit}
mode='javascript'
onRun={onRun}
onSave={onSave}
/>
<StyledWrapper className="w-full flex flex-col">
<div className='flex-1'>
<div className='mb-1 title'>Request</div>
<CodeEditor
collection={collection} value={requestScript || ''}
theme={storedTheme}
onEdit={onRequestScriptEdit}
mode='javascript'
onRun={onRun}
onSave={onSave}
/>
</div>
<div className='flex-1 mt-6'>
<div className='mt-1 mb-1 title'>Response</div>
<CodeEditor
collection={collection} value={responseScript || ''}
theme={storedTheme}
onEdit={onResponseScriptEdit}
mode='javascript'
onRun={onRun}
onSave={onSave}
/>
</div>
</StyledWrapper>
);
};

View File

@ -652,7 +652,23 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
item.draft.request.script = action.payload.script;
item.draft.request.script = item.draft.request.script || {};
item.draft.request.script.req = action.payload.script;
}
}
},
updateResponseScript: (state, action) => {
const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
if (collection) {
const item = findItemInCollection(collection, action.payload.itemUid);
if (item && isItemARequest(item)) {
if (!item.draft) {
item.draft = cloneDeep(item);
}
item.draft.request.script = item.draft.request.script || {};
item.draft.request.script.res = action.payload.script;
}
}
},
@ -971,6 +987,7 @@ export const {
updateRequestGraphqlQuery,
updateRequestGraphqlVariables,
updateRequestScript,
updateResponseScript,
updateRequestTests,
updateRequestMethod,
collectionAddFileEvent,

View File

@ -193,9 +193,9 @@ const darkTheme = {
codemirror: {
bg: '#1e1e1e',
border: 'transparent',
border: '#373737',
gutter: {
bg: '#1e1e1e'
bg: '#262626'
},
variable: {
valid: 'rgb(11 178 126)',

View File

@ -181,7 +181,6 @@ const add = async (win, pathname, collectionUid, collectionPath) => {
try {
const bru = fs.readFileSync(pathname, 'utf8');
file.data = bruToJson(bru);
console.log(JSON.stringify(file.data, null, 2));
hydrateRequestWithUuid(file.data, pathname);
win.webContents.send('main:collection-tree-updated', 'addFile', file);
} catch (err) {

View File

@ -39,7 +39,7 @@ const bruToJson = (bru) => {
"params": _.get(json, "query", []),
"headers": _.get(json, "headers", []),
"body": _.get(json, "body", {}),
"script": _.get(json, "script", ""),
"script": _.get(json, "script", {}),
"tests": _.get(json, "tests", "")
}
};
@ -84,8 +84,8 @@ const jsonToBru = (json) => {
query: _.get(json, 'request.params', []),
headers: _.get(json, 'request.headers', []),
body: _.get(json, 'request.body', {}),
script: _.get(json, 'script', ''),
tests: _.get(json, 'tests', ''),
script: _.get(json, 'request.script', {}),
tests: _.get(json, 'request.tests', ''),
};
return jsonToBruV2(bruJson);

View File

@ -99,10 +99,10 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
const envVars = getEnvVars(environment);
if(request.script && request.script.length) {
let script = request.script + '\n if (typeof onRequest === "function") {onRequest(__brunoRequest);}';
const requestScript = get(request, 'script.req');
if(requestScript && requestScript.length) {
const scriptRuntime = new ScriptRuntime();
const result = scriptRuntime.runRequestScript(script, request, envVars, collectionVariables, collectionPath);
const result = scriptRuntime.runRequestScript(requestScript, request, envVars, collectionVariables, collectionPath);
mainWindow.webContents.send('main:script-environment-update', {
environment: result.environment,
@ -130,10 +130,10 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
const response = await axios(request);
if(request.script && request.script.length) {
let script = request.script + '\n if (typeof onResponse === "function") {onResponse(__brunoResponse);}';
const responseScript = get(request, 'script.res');
if(responseScript && responseScript.length) {
const scriptRuntime = new ScriptRuntime();
const result = scriptRuntime.runResponseScript(script, response, envVars, collectionVariables, collectionPath);
const result = scriptRuntime.runResponseScript(responseScript, response, envVars, collectionVariables, collectionPath);
mainWindow.webContents.send('main:script-environment-update', {
environment: result.environment,
@ -280,10 +280,10 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
request.data = form;
}
if(request.script && request.script.length) {
let script = request.script + '\n if (typeof onRequest === "function") {onRequest(__brunoRequest);}';
const requestScript = get(request, 'script.req');
if(requestScript && requestScript.length) {
const scriptRuntime = new ScriptRuntime();
const result = scriptRuntime.runRequestScript(script, request, envVars, collectionVariables, collectionPath);
const result = scriptRuntime.runRequestScript(requestScript, request, envVars, collectionVariables, collectionPath);
mainWindow.webContents.send('main:script-environment-update', {
environment: result.environment,
@ -312,10 +312,10 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
const response = await axios(request);
timeEnd = Date.now();
if(request.script && request.script.length) {
let script = request.script + '\n if (typeof onResponse === "function") {onResponse(__brunoResponse);}';
const responseScript = get(request, 'script.res');
if(responseScript && responseScript.length) {
const scriptRuntime = new ScriptRuntime();
const result = scriptRuntime.runResponseScript(script, response, envVars, collectionVariables, collectionPath);
const result = scriptRuntime.runResponseScript(responseScript, response, envVars, collectionVariables, collectionPath);
mainWindow.webContents.send('main:script-environment-update', {
environment: result.environment,

View File

@ -59,7 +59,7 @@ const prepareRequest = (request) => {
axiosRequest.data = graphqlQuery;
}
if (request.script && request.script.length) {
if (request.script) {
axiosRequest.script = request.script;
}

View File

@ -1,40 +1,10 @@
// Inbuilt Library Support
const atob = require('atob');
const btoa = require('btoa');
const _ = require('lodash');
const moment = require('moment');
const uuid = require('uuid');
const nanoid = require('nanoid');
const CryptoJS = require('crypto-js');
class Bru {
constructor(environment, collectionVariables) {
this._environment = environment;
this._collectionVariables = collectionVariables;
}
require(module) {
switch(module) {
case 'atob':
return atob;
case 'btoa':
return btoa;
case 'lodash':
return _;
case 'moment':
return moment;
case 'uuid':
return uuid;
case 'nanoid':
return nanoid;
case 'crypto-js':
return CryptoJS;
default:
throw new Error(`Module ${module} is not supported`);
}
}
getEnvVar(key) {
return this._environment[key];
}

View File

@ -35,11 +35,11 @@ class BrunoRequest {
this._request.headers[name] = value;
}
getData() {
getBody() {
return this._request.data;
}
setData(data) {
setBody(data) {
this._request.data = data;
}
}

View File

@ -1,6 +1,10 @@
class BrunoResponse {
constructor(response) {
this._response = response;
this.status = response.status;
this.statusText = response.statusText;
this.headers = response.headers;
this.body = response.data;
}
getStatus() {
@ -15,7 +19,7 @@ class BrunoResponse {
return this._response.headers;
}
getData() {
getBody() {
return this._response.data;
}
}

View File

@ -4,24 +4,42 @@ const Bru = require('./bru');
const BrunoRequest = require('./bruno-request');
const BrunoResponse = require('./bruno-response');
// Inbuilt Library Support
const atob = require('atob');
const btoa = require('btoa');
const lodash = require('lodash');
const moment = require('moment');
const uuid = require('uuid');
const nanoid = require('nanoid');
const CryptoJS = require('crypto-js');
class ScriptRuntime {
constructor() {
}
runRequestScript(script, request, environment, collectionVariables, collectionPath) {
const bru = new Bru(environment, collectionVariables);
const __brunoRequest = new BrunoRequest(request);
const $bru = new Bru(environment, collectionVariables);
const $req = new BrunoRequest(request);
const context = {
bru,
__brunoRequest
$bru,
$req
};
const vm = new NodeVM({
sandbox: context,
require: {
context: 'sandbox',
external: true,
root: [collectionPath]
root: [collectionPath],
mock: {
atob,
btoa,
lodash,
moment,
uuid,
nanoid,
'crypto-js': CryptoJS
}
}
});
@ -35,19 +53,28 @@ class ScriptRuntime {
}
runResponseScript(script, response, environment, collectionVariables, collectionPath) {
const bru = new Bru(environment, collectionVariables);
const __brunoResponse = new BrunoResponse(response);
const $bru = new Bru(environment, collectionVariables);
const $res = new BrunoResponse(response);
const context = {
bru,
__brunoResponse
$bru,
$res
};
const vm = new NodeVM({
sandbox: context,
require: {
context: 'sandbox',
external: true,
root: [collectionPath]
root: [collectionPath],
mock: {
atob,
btoa,
lodash,
moment,
uuid,
nanoid,
'crypto-js': CryptoJS
}
}
});

View File

@ -7,23 +7,32 @@ const BrunoResponse = require('./bruno-response');
const Test = require('./test');
const TestResults = require('./test-results');
// Inbuilt Library Support
const atob = require('atob');
const btoa = require('btoa');
const lodash = require('lodash');
const moment = require('moment');
const uuid = require('uuid');
const nanoid = require('nanoid');
const CryptoJS = require('crypto-js');
class TestRuntime {
constructor() {
}
runTests(testsFile, request, response, environment, collectionVariables, collectionPath) {
const bru = new Bru(environment, collectionVariables);
const req = new BrunoRequest(request);
const res = new BrunoResponse(response);
const $bru = new Bru(environment, collectionVariables);
const $req = new BrunoRequest(request);
const $res = new BrunoResponse(response);
const __brunoTestResults = new TestResults();
const test = Test(__brunoTestResults, chai);
const context = {
bru,
req,
res,
test,
$bru,
$req,
$res,
expect: chai.expect,
assert: chai.assert,
__brunoTestResults: __brunoTestResults
@ -34,7 +43,16 @@ class TestRuntime {
require: {
context: 'sandbox',
external: true,
root: [collectionPath]
root: [collectionPath],
mock: {
atob,
btoa,
lodash,
moment,
uuid,
nanoid,
'crypto-js': CryptoJS
}
}
});

View File

@ -53,7 +53,10 @@ const requestSchema = Yup.object({
headers: Yup.array().of(keyValueSchema).required('headers are required'),
params: Yup.array().of(keyValueSchema).required('params are required'),
body: requestBodySchema,
script: Yup.string().nullable(),
script: Yup.object({
req: Yup.string().nullable(),
res: Yup.string().nullable()
}).noUnknown(true).strict(),
tests: Yup.string().nullable()
}).noUnknown(true).strict();