mirror of
https://github.com/usebruno/bruno.git
synced 2025-08-19 08:31:34 +02:00
Merge pull request #3719 from lohxt1/feat/bru-runner-fns
feat: bru util fns -- skipRequest, stopExecution, getTestResults, getAssertionResults, runRequest
This commit is contained in:
20
package-lock.json
generated
20
package-lock.json
generated
@@ -24287,10 +24287,30 @@
|
|||||||
"name": "@usebruno/schema",
|
"name": "@usebruno/schema",
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "3.3.8"
|
||||||
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"packages/bruno-schema/node_modules/nanoid": {
|
||||||
|
"version": "3.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||||
|
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"packages/bruno-tests": {
|
"packages/bruno-tests": {
|
||||||
"name": "@usebruno/tests",
|
"name": "@usebruno/tests",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
|
@@ -76,7 +76,11 @@ if (!SERVER_RENDERED) {
|
|||||||
'bru.getRequestVar(key)',
|
'bru.getRequestVar(key)',
|
||||||
'bru.sleep(ms)',
|
'bru.sleep(ms)',
|
||||||
'bru.getGlobalEnvVar(key)',
|
'bru.getGlobalEnvVar(key)',
|
||||||
'bru.setGlobalEnvVar(key, value)'
|
'bru.setGlobalEnvVar(key, value)',
|
||||||
|
'bru.runner',
|
||||||
|
'bru.runner.setNextRequest(requestName)',
|
||||||
|
'bru.runner.skipRequest()',
|
||||||
|
'bru.runner.stopExecution()'
|
||||||
];
|
];
|
||||||
CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => {
|
CodeMirror.registerHelper('hint', 'brunoJS', (editor, options) => {
|
||||||
const cursor = editor.getCursor();
|
const cursor = editor.getCursor();
|
||||||
@@ -98,7 +102,7 @@ if (!SERVER_RENDERED) {
|
|||||||
if (curWordBru) {
|
if (curWordBru) {
|
||||||
hintWords.forEach((h) => {
|
hintWords.forEach((h) => {
|
||||||
if (h.includes('.') == curWordBru.includes('.') && h.startsWith(curWordBru)) {
|
if (h.includes('.') == curWordBru.includes('.') && h.startsWith(curWordBru)) {
|
||||||
result.list.push(curWordBru.includes('.') ? h.split('.')[1] : h);
|
result.list.push(curWordBru.includes('.') ? h.split('.')?.at(-1) : h);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
result.list?.sort();
|
result.list?.sort();
|
||||||
|
@@ -11,7 +11,7 @@ const ResponseSave = ({ item }) => {
|
|||||||
const saveResponseToFile = () => {
|
const saveResponseToFile = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
ipcRenderer
|
ipcRenderer
|
||||||
.invoke('renderer:save-response-to-file', response, item.requestSent.url)
|
.invoke('renderer:save-response-to-file', response, item?.requestSent?.url)
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
toast.error(get(err, 'error.message') || 'Something went wrong!');
|
toast.error(get(err, 'error.message') || 'Something went wrong!');
|
||||||
|
@@ -43,7 +43,7 @@ const Timeline = ({ request, response }) => {
|
|||||||
|
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<pre className="line response font-bold">
|
<pre className="line response font-bold">
|
||||||
<span className="arrow">{'<'}</span> {response.status} {response.statusText}
|
<span className="arrow">{'<'}</span> {response.status} - {response.statusText}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
{responseHeaders.map((h) => {
|
{responseHeaders.map((h) => {
|
||||||
|
@@ -59,7 +59,7 @@ export default function RunnerResults({ collection }) {
|
|||||||
pathname: info.pathname,
|
pathname: info.pathname,
|
||||||
relativePath: getRelativePath(collection.pathname, info.pathname)
|
relativePath: getRelativePath(collection.pathname, info.pathname)
|
||||||
};
|
};
|
||||||
if (newItem.status !== 'error') {
|
if (newItem.status !== 'error' && newItem.status !== 'skipped') {
|
||||||
if (newItem.testResults) {
|
if (newItem.testResults) {
|
||||||
const failed = newItem.testResults.filter((result) => result.status === 'fail');
|
const failed = newItem.testResults.filter((result) => result.status === 'fail');
|
||||||
newItem.testStatus = failed.length ? 'fail' : 'pass';
|
newItem.testStatus = failed.length ? 'fail' : 'pass';
|
||||||
@@ -163,29 +163,35 @@ export default function RunnerResults({ collection }) {
|
|||||||
<div className="pb-2 font-medium test-summary">
|
<div className="pb-2 font-medium test-summary">
|
||||||
Total Requests: {items.length}, Passed: {passedRequests.length}, Failed: {failedRequests.length}
|
Total Requests: {items.length}, Passed: {passedRequests.length}, Failed: {failedRequests.length}
|
||||||
</div>
|
</div>
|
||||||
|
{runnerInfo?.statusText ?
|
||||||
|
<div className="pb-2 font-medium danger">
|
||||||
|
{runnerInfo?.statusText}
|
||||||
|
</div>
|
||||||
|
: null}
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<div key={item.uid}>
|
<div key={item.uid}>
|
||||||
<div className="item-path mt-2">
|
<div className="item-path mt-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span>
|
<span>
|
||||||
{item.status !== 'error' && item.testStatus === 'pass' ? (
|
{item.status !== 'error' && item.testStatus === 'pass' && item.status !== 'skipped' ? (
|
||||||
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5} />
|
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5} />
|
||||||
) : (
|
) : (
|
||||||
<IconCircleX className="test-failure" size={20} strokeWidth={1.5} />
|
<IconCircleX className="test-failure" size={20} strokeWidth={1.5} />
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
className={`mr-1 ml-2 ${item.status == 'error' || item.testStatus == 'fail' ? 'danger' : ''}`}
|
className={`mr-1 ml-2 ${item.status == 'error' || item.status == 'skipped' || item.testStatus == 'fail' ? 'danger' : ''}`}
|
||||||
>
|
>
|
||||||
{item.relativePath}
|
{item.relativePath}
|
||||||
</span>
|
</span>
|
||||||
{item.status !== 'error' && item.status !== 'completed' ? (
|
{item.status !== 'error' && item.status !== 'skipped' && item.status !== 'completed' ? (
|
||||||
<IconRefresh className="animate-spin ml-1" size={18} strokeWidth={1.5} />
|
<IconRefresh className="animate-spin ml-1" size={18} strokeWidth={1.5} />
|
||||||
) : item.responseReceived?.status ? (
|
) : item.responseReceived?.status ? (
|
||||||
<span className="text-xs link cursor-pointer" onClick={() => setSelectedItem(item)}>
|
<span className="text-xs link cursor-pointer" onClick={() => setSelectedItem(item)}>
|
||||||
(<span className="mr-1">{item.responseReceived?.status}</span>
|
<span className="mr-1">{item.responseReceived?.status}</span>
|
||||||
<span>{item.responseReceived?.statusText}</span>)
|
-
|
||||||
|
<span>{item.responseReceived?.statusText}</span>
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="danger text-xs cursor-pointer" onClick={() => setSelectedItem(item)}>
|
<span className="danger text-xs cursor-pointer" onClick={() => setSelectedItem(item)}>
|
||||||
|
@@ -1675,6 +1675,9 @@ export const collectionsSlice = createSlice({
|
|||||||
if (type === 'testrun-ended') {
|
if (type === 'testrun-ended') {
|
||||||
const info = collection.runnerResult.info;
|
const info = collection.runnerResult.info;
|
||||||
info.status = 'ended';
|
info.status = 'ended';
|
||||||
|
if (action.payload.statusText) {
|
||||||
|
info.statusText = action.payload.statusText;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'request-queued') {
|
if (type === 'request-queued') {
|
||||||
@@ -1712,6 +1715,12 @@ export const collectionsSlice = createSlice({
|
|||||||
item.responseReceived = action.payload.responseReceived;
|
item.responseReceived = action.payload.responseReceived;
|
||||||
item.status = 'error';
|
item.status = 'error';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'runner-request-skipped') {
|
||||||
|
const item = collection.runnerResult.items.findLast((i) => i.uid === request.uid);
|
||||||
|
item.status = 'skipped';
|
||||||
|
item.responseReceived = action.payload.responseReceived;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resetCollectionRunner: (state, action) => {
|
resetCollectionRunner: (state, action) => {
|
||||||
|
@@ -39,6 +39,7 @@ const Oauth2Store = require('../../store/oauth2');
|
|||||||
const iconv = require('iconv-lite');
|
const iconv = require('iconv-lite');
|
||||||
const FormData = require('form-data');
|
const FormData = require('form-data');
|
||||||
const { createFormData } = require('../../utils/form-data');
|
const { createFormData } = require('../../utils/form-data');
|
||||||
|
const { findItemInCollectionByPathname } = require('../../utils/collection');
|
||||||
|
|
||||||
const safeStringifyJSON = (data) => {
|
const safeStringifyJSON = (data) => {
|
||||||
try {
|
try {
|
||||||
@@ -397,7 +398,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionUid,
|
collectionUid,
|
||||||
runtimeVariables,
|
runtimeVariables,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
) => {
|
) => {
|
||||||
// run pre-request script
|
// run pre-request script
|
||||||
let scriptResult;
|
let scriptResult;
|
||||||
@@ -412,7 +414,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionPath,
|
collectionPath,
|
||||||
onConsoleLog,
|
onConsoleLog,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
mainWindow.webContents.send('main:script-environment-update', {
|
mainWindow.webContents.send('main:script-environment-update', {
|
||||||
@@ -462,7 +465,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionUid,
|
collectionUid,
|
||||||
runtimeVariables,
|
runtimeVariables,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
) => {
|
) => {
|
||||||
// run post-response vars
|
// run post-response vars
|
||||||
const postResponseVars = get(request, 'vars.res', []);
|
const postResponseVars = get(request, 'vars.res', []);
|
||||||
@@ -510,7 +514,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionPath,
|
collectionPath,
|
||||||
onConsoleLog,
|
onConsoleLog,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
mainWindow.webContents.send('main:script-environment-update', {
|
mainWindow.webContents.send('main:script-environment-update', {
|
||||||
@@ -527,14 +532,28 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
return scriptResult;
|
return scriptResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
// handler for sending http request
|
const runRequest = async ({ item, collection, environment, runtimeVariables, runInBackground = false }) => {
|
||||||
ipcMain.handle('send-http-request', async (event, item, collection, environment, runtimeVariables) => {
|
|
||||||
const collectionUid = collection.uid;
|
const collectionUid = collection.uid;
|
||||||
const collectionPath = collection.pathname;
|
const collectionPath = collection.pathname;
|
||||||
const cancelTokenUid = uuid();
|
const cancelTokenUid = uuid();
|
||||||
const requestUid = uuid();
|
const requestUid = uuid();
|
||||||
|
|
||||||
mainWindow.webContents.send('main:run-request-event', {
|
const runRequestByItemPathname = async (relativeItemPathname) => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let itemPathname = path.join(collection?.pathname, relativeItemPathname);
|
||||||
|
if (itemPathname && !itemPathname?.endsWith('.bru')) {
|
||||||
|
itemPathname = `${itemPathname}.bru`;
|
||||||
|
}
|
||||||
|
const _item = findItemInCollectionByPathname(collection, itemPathname);
|
||||||
|
if(_item) {
|
||||||
|
const res = await runRequest({ item: _item, collection, environment, runtimeVariables, runInBackground: true });
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
reject(`bru.runRequest: invalid request path - ${itemPathname}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||||
type: 'request-queued',
|
type: 'request-queued',
|
||||||
requestUid,
|
requestUid,
|
||||||
collectionUid,
|
collectionUid,
|
||||||
@@ -565,7 +584,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionUid,
|
collectionUid,
|
||||||
runtimeVariables,
|
runtimeVariables,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
const axiosInstance = await configureRequest(
|
const axiosInstance = await configureRequest(
|
||||||
@@ -577,7 +597,7 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionPath
|
collectionPath
|
||||||
);
|
);
|
||||||
|
|
||||||
mainWindow.webContents.send('main:run-request-event', {
|
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||||
type: 'request-sent',
|
type: 'request-sent',
|
||||||
requestSent: {
|
requestSent: {
|
||||||
url: request.url,
|
url: request.url,
|
||||||
@@ -649,7 +669,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionUid,
|
collectionUid,
|
||||||
runtimeVariables,
|
runtimeVariables,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
// run assertions
|
// run assertions
|
||||||
@@ -665,7 +686,7 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
processEnvVars
|
processEnvVars
|
||||||
);
|
);
|
||||||
|
|
||||||
mainWindow.webContents.send('main:run-request-event', {
|
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||||
type: 'assertion-results',
|
type: 'assertion-results',
|
||||||
results: results,
|
results: results,
|
||||||
itemUid: item.uid,
|
itemUid: item.uid,
|
||||||
@@ -686,10 +707,11 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionPath,
|
collectionPath,
|
||||||
onConsoleLog,
|
onConsoleLog,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
mainWindow.webContents.send('main:run-request-event', {
|
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||||
type: 'test-results',
|
type: 'test-results',
|
||||||
results: testResults.results,
|
results: testResults.results,
|
||||||
itemUid: item.uid,
|
itemUid: item.uid,
|
||||||
@@ -723,6 +745,11 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handler for sending http request
|
||||||
|
ipcMain.handle('send-http-request', async (event, item, collection, environment, runtimeVariables) => {
|
||||||
|
return await runRequest({ item, collection, environment, runtimeVariables });
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle('send-collection-oauth2-request', async (event, collection, environment, runtimeVariables) => {
|
ipcMain.handle('send-collection-oauth2-request', async (event, collection, environment, runtimeVariables) => {
|
||||||
@@ -914,10 +941,26 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
const scriptingConfig = get(brunoConfig, 'scripts', {});
|
const scriptingConfig = get(brunoConfig, 'scripts', {});
|
||||||
scriptingConfig.runtime = getJsSandboxRuntime(collection);
|
scriptingConfig.runtime = getJsSandboxRuntime(collection);
|
||||||
const collectionRoot = get(collection, 'root', {});
|
const collectionRoot = get(collection, 'root', {});
|
||||||
|
let stopRunnerExecution = false;
|
||||||
|
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
saveCancelToken(cancelTokenUid, abortController);
|
saveCancelToken(cancelTokenUid, abortController);
|
||||||
|
|
||||||
|
const runRequestByItemPathname = async (relativeItemPathname) => {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
let itemPathname = path.join(collection?.pathname, relativeItemPathname);
|
||||||
|
if (itemPathname && !itemPathname?.endsWith('.bru')) {
|
||||||
|
itemPathname = `${itemPathname}.bru`;
|
||||||
|
}
|
||||||
|
const _item = findItemInCollectionByPathname(collection, itemPathname);
|
||||||
|
if(_item) {
|
||||||
|
const res = await runRequest({ item: _item, collection, environment, runtimeVariables, runInBackground: true });
|
||||||
|
resolve(res);
|
||||||
|
}
|
||||||
|
reject(`bru.runRequest: invalid request path - ${itemPathname}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
folder = collection;
|
folder = collection;
|
||||||
}
|
}
|
||||||
@@ -960,6 +1003,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopRunnerExecution = false;
|
||||||
|
|
||||||
const item = folderRequests[currentRequestIndex];
|
const item = folderRequests[currentRequestIndex];
|
||||||
let nextRequestName;
|
let nextRequestName;
|
||||||
const itemUid = item.uid;
|
const itemUid = item.uid;
|
||||||
@@ -993,13 +1038,33 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionUid,
|
collectionUid,
|
||||||
runtimeVariables,
|
runtimeVariables,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
if (preRequestScriptResult?.nextRequestName !== undefined) {
|
if (preRequestScriptResult?.nextRequestName !== undefined) {
|
||||||
nextRequestName = preRequestScriptResult.nextRequestName;
|
nextRequestName = preRequestScriptResult.nextRequestName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preRequestScriptResult?.stopExecution) {
|
||||||
|
stopRunnerExecution = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preRequestScriptResult?.skipRequest) {
|
||||||
|
mainWindow.webContents.send('main:run-folder-event', {
|
||||||
|
type: 'runner-request-skipped',
|
||||||
|
error: 'Request has been skipped from pre-request script',
|
||||||
|
responseReceived: {
|
||||||
|
status: 'skipped',
|
||||||
|
statusText: 'request skipped via pre-request script',
|
||||||
|
data: null
|
||||||
|
},
|
||||||
|
...eventData
|
||||||
|
});
|
||||||
|
currentRequestIndex++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// todo:
|
// todo:
|
||||||
// i have no clue why electron can't send the request object
|
// i have no clue why electron can't send the request object
|
||||||
// without safeParseJSON(safeStringifyJSON(request.data))
|
// without safeParseJSON(safeStringifyJSON(request.data))
|
||||||
@@ -1111,13 +1176,18 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionUid,
|
collectionUid,
|
||||||
runtimeVariables,
|
runtimeVariables,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
if (postRequestScriptResult?.nextRequestName !== undefined) {
|
if (postRequestScriptResult?.nextRequestName !== undefined) {
|
||||||
nextRequestName = postRequestScriptResult.nextRequestName;
|
nextRequestName = postRequestScriptResult.nextRequestName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (postRequestScriptResult?.stopExecution) {
|
||||||
|
stopRunnerExecution = true;
|
||||||
|
}
|
||||||
|
|
||||||
// run assertions
|
// run assertions
|
||||||
const assertions = get(item, 'request.assertions');
|
const assertions = get(item, 'request.assertions');
|
||||||
if (assertions) {
|
if (assertions) {
|
||||||
@@ -1151,7 +1221,8 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
collectionPath,
|
collectionPath,
|
||||||
onConsoleLog,
|
onConsoleLog,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
);
|
);
|
||||||
|
|
||||||
if (testResults?.nextRequestName !== undefined) {
|
if (testResults?.nextRequestName !== undefined) {
|
||||||
@@ -1182,6 +1253,18 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
...eventData
|
...eventData
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stopRunnerExecution) {
|
||||||
|
deleteCancelToken(cancelTokenUid);
|
||||||
|
mainWindow.webContents.send('main:run-folder-event', {
|
||||||
|
type: 'testrun-ended',
|
||||||
|
collectionUid,
|
||||||
|
folderUid,
|
||||||
|
statusText: 'collection run was terminated!'
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (nextRequestName !== undefined) {
|
if (nextRequestName !== undefined) {
|
||||||
nJumps++;
|
nJumps++;
|
||||||
if (nJumps > 10000) {
|
if (nJumps > 10000) {
|
||||||
|
@@ -203,9 +203,31 @@ const getTreePathFromCollectionToItem = (collection, _item) => {
|
|||||||
return path;
|
return path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const slash = (path) => {
|
||||||
|
const isExtendedLengthPath = /^\\\\\?\\/.test(path);
|
||||||
|
if (isExtendedLengthPath) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
return path?.replace?.(/\\/g, '/');
|
||||||
|
};
|
||||||
|
|
||||||
|
const findItemByPathname = (items = [], pathname) => {
|
||||||
|
return find(items, (i) => slash(i.pathname) === slash(pathname));
|
||||||
|
};
|
||||||
|
|
||||||
|
const findItemInCollectionByPathname = (collection, pathname) => {
|
||||||
|
let flattenedItems = flattenItems(collection.items);
|
||||||
|
|
||||||
|
return findItemByPathname(flattenedItems, pathname);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mergeHeaders,
|
mergeHeaders,
|
||||||
mergeVars,
|
mergeVars,
|
||||||
mergeScripts,
|
mergeScripts,
|
||||||
getTreePathFromCollectionToItem
|
getTreePathFromCollectionToItem,
|
||||||
|
slash,
|
||||||
|
findItemByPathname,
|
||||||
|
findItemInCollectionByPathname
|
||||||
}
|
}
|
@@ -13,6 +13,17 @@ class Bru {
|
|||||||
this.requestVariables = requestVariables || {};
|
this.requestVariables = requestVariables || {};
|
||||||
this.globalEnvironmentVariables = globalEnvironmentVariables || {};
|
this.globalEnvironmentVariables = globalEnvironmentVariables || {};
|
||||||
this.collectionPath = collectionPath;
|
this.collectionPath = collectionPath;
|
||||||
|
this.runner = {
|
||||||
|
skipRequest: () => {
|
||||||
|
this.skipRequest = true;
|
||||||
|
},
|
||||||
|
stopExecution: () => {
|
||||||
|
this.stopExecution = true;
|
||||||
|
},
|
||||||
|
setNextRequest: (nextRequest) => {
|
||||||
|
this.nextRequest = nextRequest;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_interpolate = (str) => {
|
_interpolate = (str) => {
|
||||||
|
@@ -408,6 +408,8 @@ class AssertRuntime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.assertionResults = assertionResults;
|
||||||
|
|
||||||
return assertionResults;
|
return assertionResults;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,8 @@ class ScriptRuntime {
|
|||||||
collectionPath,
|
collectionPath,
|
||||||
onConsoleLog,
|
onConsoleLog,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
) {
|
) {
|
||||||
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
||||||
const collectionVariables = request?.collectionVariables || {};
|
const collectionVariables = request?.collectionVariables || {};
|
||||||
@@ -92,6 +93,10 @@ class ScriptRuntime {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(runRequestByItemPathname) {
|
||||||
|
context.bru.runRequest = runRequestByItemPathname;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.runtime === 'quickjs') {
|
if (this.runtime === 'quickjs') {
|
||||||
await executeQuickJsVmAsync({
|
await executeQuickJsVmAsync({
|
||||||
script: script,
|
script: script,
|
||||||
@@ -104,7 +109,9 @@ class ScriptRuntime {
|
|||||||
envVariables: cleanJson(envVariables),
|
envVariables: cleanJson(envVariables),
|
||||||
runtimeVariables: cleanJson(runtimeVariables),
|
runtimeVariables: cleanJson(runtimeVariables),
|
||||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||||
nextRequestName: bru.nextRequest
|
nextRequestName: bru.nextRequest,
|
||||||
|
skipRequest: bru.skipRequest,
|
||||||
|
stopExecution: bru.stopExecution
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +159,9 @@ class ScriptRuntime {
|
|||||||
envVariables: cleanJson(envVariables),
|
envVariables: cleanJson(envVariables),
|
||||||
runtimeVariables: cleanJson(runtimeVariables),
|
runtimeVariables: cleanJson(runtimeVariables),
|
||||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||||
nextRequestName: bru.nextRequest
|
nextRequestName: bru.nextRequest,
|
||||||
|
skipRequest: bru.skipRequest,
|
||||||
|
stopExecution: bru.stopExecution
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +174,8 @@ class ScriptRuntime {
|
|||||||
collectionPath,
|
collectionPath,
|
||||||
onConsoleLog,
|
onConsoleLog,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
) {
|
) {
|
||||||
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
||||||
const collectionVariables = request?.collectionVariables || {};
|
const collectionVariables = request?.collectionVariables || {};
|
||||||
@@ -209,6 +219,10 @@ class ScriptRuntime {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(runRequestByItemPathname) {
|
||||||
|
context.bru.runRequest = runRequestByItemPathname;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.runtime === 'quickjs') {
|
if (this.runtime === 'quickjs') {
|
||||||
await executeQuickJsVmAsync({
|
await executeQuickJsVmAsync({
|
||||||
script: script,
|
script: script,
|
||||||
@@ -221,7 +235,9 @@ class ScriptRuntime {
|
|||||||
envVariables: cleanJson(envVariables),
|
envVariables: cleanJson(envVariables),
|
||||||
runtimeVariables: cleanJson(runtimeVariables),
|
runtimeVariables: cleanJson(runtimeVariables),
|
||||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||||
nextRequestName: bru.nextRequest
|
nextRequestName: bru.nextRequest,
|
||||||
|
skipRequest: bru.skipRequest,
|
||||||
|
stopExecution: bru.stopExecution
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +285,9 @@ class ScriptRuntime {
|
|||||||
envVariables: cleanJson(envVariables),
|
envVariables: cleanJson(envVariables),
|
||||||
runtimeVariables: cleanJson(runtimeVariables),
|
runtimeVariables: cleanJson(runtimeVariables),
|
||||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||||
nextRequestName: bru.nextRequest
|
nextRequestName: bru.nextRequest,
|
||||||
|
skipRequest: bru.skipRequest,
|
||||||
|
stopExecution: bru.stopExecution
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,6 +32,25 @@ const CryptoJS = require('crypto-js');
|
|||||||
const NodeVault = require('node-vault');
|
const NodeVault = require('node-vault');
|
||||||
const { executeQuickJsVmAsync } = require('../sandbox/quickjs');
|
const { executeQuickJsVmAsync } = require('../sandbox/quickjs');
|
||||||
|
|
||||||
|
const getResultsSummary = (results) => {
|
||||||
|
const summary = {
|
||||||
|
total: results.length,
|
||||||
|
passed: 0,
|
||||||
|
failed: 0,
|
||||||
|
skipped: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
results.forEach((r) => {
|
||||||
|
const passed = r.status === "pass";
|
||||||
|
if (passed) summary.passed += 1;
|
||||||
|
else if (r.status === "fail") summary.failed += 1;
|
||||||
|
else summary.skipped += 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
return summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestRuntime {
|
class TestRuntime {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
this.runtime = props?.runtime || 'vm2';
|
this.runtime = props?.runtime || 'vm2';
|
||||||
@@ -46,12 +65,14 @@ class TestRuntime {
|
|||||||
collectionPath,
|
collectionPath,
|
||||||
onConsoleLog,
|
onConsoleLog,
|
||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig,
|
||||||
|
runRequestByItemPathname
|
||||||
) {
|
) {
|
||||||
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
||||||
const collectionVariables = request?.collectionVariables || {};
|
const collectionVariables = request?.collectionVariables || {};
|
||||||
const folderVariables = request?.folderVariables || {};
|
const folderVariables = request?.folderVariables || {};
|
||||||
const requestVariables = request?.requestVariables || {};
|
const requestVariables = request?.requestVariables || {};
|
||||||
|
const assertionResults = request?.assertionResults || [];
|
||||||
const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables);
|
const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables);
|
||||||
const req = new BrunoRequest(request);
|
const req = new BrunoRequest(request);
|
||||||
const res = new BrunoResponse(response);
|
const res = new BrunoResponse(response);
|
||||||
@@ -75,6 +96,7 @@ class TestRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const __brunoTestResults = new TestResults();
|
const __brunoTestResults = new TestResults();
|
||||||
|
|
||||||
const test = Test(__brunoTestResults, chai);
|
const test = Test(__brunoTestResults, chai);
|
||||||
|
|
||||||
if (!testsFile || !testsFile.length) {
|
if (!testsFile || !testsFile.length) {
|
||||||
@@ -88,6 +110,36 @@ class TestRuntime {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bru.getTestResults = async () => {
|
||||||
|
let results = await __brunoTestResults.getResults();
|
||||||
|
const summary = getResultsSummary(results);
|
||||||
|
return {
|
||||||
|
summary,
|
||||||
|
results: results?.map?.(r => ({
|
||||||
|
status: r?.status,
|
||||||
|
description: r?.description,
|
||||||
|
expected: r?.expected,
|
||||||
|
actual: r?.actual,
|
||||||
|
error: r?.error
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
bru.getAssertionResults = async () => {
|
||||||
|
let results = assertionResults;
|
||||||
|
const summary = getResultsSummary(results);
|
||||||
|
return {
|
||||||
|
summary,
|
||||||
|
results: results?.map?.(r => ({
|
||||||
|
status: r?.status,
|
||||||
|
lhsExpr: r?.lhsExpr,
|
||||||
|
rhsExpr: r?.rhsExpr,
|
||||||
|
operator: r?.operator,
|
||||||
|
rhsOperand: r?.rhsOperand,
|
||||||
|
error: r?.error
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
test,
|
test,
|
||||||
bru,
|
bru,
|
||||||
@@ -113,6 +165,10 @@ class TestRuntime {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(runRequestByItemPathname) {
|
||||||
|
context.bru.runRequest = runRequestByItemPathname;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.runtime === 'quickjs') {
|
if (this.runtime === 'quickjs') {
|
||||||
await executeQuickJsVmAsync({
|
await executeQuickJsVmAsync({
|
||||||
script: testsFile,
|
script: testsFile,
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
|
const { cleanJson } = require('../../../utils');
|
||||||
const { marshallToVm } = require('../utils');
|
const { marshallToVm } = require('../utils');
|
||||||
|
|
||||||
const addBruShimToContext = (vm, bru) => {
|
const addBruShimToContext = (vm, bru) => {
|
||||||
const bruObject = vm.newObject();
|
const bruObject = vm.newObject();
|
||||||
|
const bruRunnerObject = vm.newObject();
|
||||||
|
|
||||||
let cwd = vm.newFunction('cwd', function () {
|
let cwd = vm.newFunction('cwd', function () {
|
||||||
return marshallToVm(bru.cwd(), vm);
|
return marshallToVm(bru.cwd(), vm);
|
||||||
@@ -93,6 +95,24 @@ const addBruShimToContext = (vm, bru) => {
|
|||||||
vm.setProp(bruObject, 'setNextRequest', setNextRequest);
|
vm.setProp(bruObject, 'setNextRequest', setNextRequest);
|
||||||
setNextRequest.dispose();
|
setNextRequest.dispose();
|
||||||
|
|
||||||
|
let runnerSkipRequest = vm.newFunction('skipRequest', function () {
|
||||||
|
bru?.runner?.skipRequest();
|
||||||
|
});
|
||||||
|
vm.setProp(bruRunnerObject, 'skipRequest', runnerSkipRequest);
|
||||||
|
runnerSkipRequest.dispose();
|
||||||
|
|
||||||
|
let runnerStopExecution = vm.newFunction('stopExecution', function () {
|
||||||
|
bru?.runner?.stopExecution();
|
||||||
|
});
|
||||||
|
vm.setProp(bruRunnerObject, 'stopExecution', runnerStopExecution);
|
||||||
|
runnerStopExecution.dispose();
|
||||||
|
|
||||||
|
let runnerSetNextRequest = vm.newFunction('setNextRequest', function (nextRequest) {
|
||||||
|
bru?.runner?.setNextRequest(vm.dump(nextRequest));
|
||||||
|
});
|
||||||
|
vm.setProp(bruRunnerObject, 'setNextRequest', runnerSetNextRequest);
|
||||||
|
runnerSetNextRequest.dispose();
|
||||||
|
|
||||||
let visualize = vm.newFunction('visualize', function (htmlString) {
|
let visualize = vm.newFunction('visualize', function (htmlString) {
|
||||||
bru.visualize(vm.dump(htmlString));
|
bru.visualize(vm.dump(htmlString));
|
||||||
});
|
});
|
||||||
@@ -123,6 +143,70 @@ const addBruShimToContext = (vm, bru) => {
|
|||||||
vm.setProp(bruObject, 'getCollectionVar', getCollectionVar);
|
vm.setProp(bruObject, 'getCollectionVar', getCollectionVar);
|
||||||
getCollectionVar.dispose();
|
getCollectionVar.dispose();
|
||||||
|
|
||||||
|
let getTestResults = vm.newFunction('getTestResults', () => {
|
||||||
|
const promise = vm.newPromise();
|
||||||
|
bru.getTestResults()
|
||||||
|
.then((results) => {
|
||||||
|
promise.resolve(marshallToVm(cleanJson(results), vm));
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
promise.resolve(
|
||||||
|
marshallToVm(
|
||||||
|
cleanJson({
|
||||||
|
message: err.message
|
||||||
|
}),
|
||||||
|
vm
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
promise.settled.then(vm.runtime.executePendingJobs);
|
||||||
|
return promise.handle;
|
||||||
|
});
|
||||||
|
getTestResults.consume((handle) => vm.setProp(bruObject, 'getTestResults', handle));
|
||||||
|
|
||||||
|
let getAssertionResults = vm.newFunction('getAssertionResults', () => {
|
||||||
|
const promise = vm.newPromise();
|
||||||
|
bru.getAssertionResults()
|
||||||
|
.then((results) => {
|
||||||
|
promise.resolve(marshallToVm(cleanJson(results), vm));
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
promise.resolve(
|
||||||
|
marshallToVm(
|
||||||
|
cleanJson({
|
||||||
|
message: err.message
|
||||||
|
}),
|
||||||
|
vm
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
promise.settled.then(vm.runtime.executePendingJobs);
|
||||||
|
return promise.handle;
|
||||||
|
});
|
||||||
|
getAssertionResults.consume((handle) => vm.setProp(bruObject, 'getAssertionResults', handle));
|
||||||
|
|
||||||
|
let runRequestHandle = vm.newFunction('runRequest', (args) => {
|
||||||
|
const promise = vm.newPromise();
|
||||||
|
bru.runRequest(vm.dump(args))
|
||||||
|
.then((response) => {
|
||||||
|
const { status, headers, data, dataBuffer, size } = response || {};
|
||||||
|
promise.resolve(marshallToVm(cleanJson({ status, headers, data, dataBuffer, size }), vm));
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
promise.resolve(
|
||||||
|
marshallToVm(
|
||||||
|
cleanJson({
|
||||||
|
message: err.message
|
||||||
|
}),
|
||||||
|
vm
|
||||||
|
)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
promise.settled.then(vm.runtime.executePendingJobs);
|
||||||
|
return promise.handle;
|
||||||
|
});
|
||||||
|
runRequestHandle.consume((handle) => vm.setProp(bruObject, 'runRequest', handle));
|
||||||
|
|
||||||
const sleep = vm.newFunction('sleep', (timer) => {
|
const sleep = vm.newFunction('sleep', (timer) => {
|
||||||
const t = vm.getString(timer);
|
const t = vm.getString(timer);
|
||||||
const promise = vm.newPromise();
|
const promise = vm.newPromise();
|
||||||
@@ -134,6 +218,7 @@ const addBruShimToContext = (vm, bru) => {
|
|||||||
});
|
});
|
||||||
sleep.consume((handle) => vm.setProp(bruObject, 'sleep', handle));
|
sleep.consume((handle) => vm.setProp(bruObject, 'sleep', handle));
|
||||||
|
|
||||||
|
vm.setProp(bruObject, 'runner', bruRunnerObject);
|
||||||
vm.setProp(vm.global, 'bru', bruObject);
|
vm.setProp(vm.global, 'bru', bruObject);
|
||||||
bruObject.dispose();
|
bruObject.dispose();
|
||||||
};
|
};
|
||||||
|
@@ -12,5 +12,8 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "3.3.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user