mirror of
https://github.com/usebruno/bruno.git
synced 2025-08-09 22:08:39 +02:00
feat: updates
This commit is contained in:
@ -59,7 +59,7 @@ export default function RunnerResults({ collection }) {
|
||||
pathname: info.pathname,
|
||||
relativePath: getRelativePath(collection.pathname, info.pathname)
|
||||
};
|
||||
if (newItem.status !== 'error') {
|
||||
if (newItem.status !== 'error' && newItem.status !== 'skipped') {
|
||||
if (newItem.testResults) {
|
||||
const failed = newItem.testResults.filter((result) => result.status === 'fail');
|
||||
newItem.testStatus = failed.length ? 'fail' : 'pass';
|
||||
@ -169,18 +169,18 @@ export default function RunnerResults({ collection }) {
|
||||
<div className="item-path mt-2">
|
||||
<div className="flex items-center">
|
||||
<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} />
|
||||
) : (
|
||||
<IconCircleX className="test-failure" size={20} strokeWidth={1.5} />
|
||||
)}
|
||||
</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}
|
||||
</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} />
|
||||
) : item.responseReceived?.status ? (
|
||||
<span className="text-xs link cursor-pointer" onClick={() => setSelectedItem(item)}>
|
||||
|
@ -1712,6 +1712,12 @@ export const collectionsSlice = createSlice({
|
||||
item.responseReceived = action.payload.responseReceived;
|
||||
item.status = 'error';
|
||||
}
|
||||
|
||||
if (type === 'request-skipped') {
|
||||
const item = collection.runnerResult.items.findLast((i) => i.uid === request.uid);
|
||||
item.status = 'skipped';
|
||||
item.responseReceived = action.payload.responseReceived;
|
||||
}
|
||||
}
|
||||
},
|
||||
resetCollectionRunner: (state, action) => {
|
||||
|
@ -39,6 +39,7 @@ const Oauth2Store = require('../../store/oauth2');
|
||||
const iconv = require('iconv-lite');
|
||||
const FormData = require('form-data');
|
||||
const { createFormData } = require('../../utils/form-data');
|
||||
const { findItemInCollectionByPathname } = require('../../utils/collection');
|
||||
|
||||
const safeStringifyJSON = (data) => {
|
||||
try {
|
||||
@ -393,7 +394,8 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid,
|
||||
runtimeVariables,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
) => {
|
||||
// run pre-request script
|
||||
let scriptResult;
|
||||
@ -408,7 +410,8 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionPath,
|
||||
onConsoleLog,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
);
|
||||
|
||||
mainWindow.webContents.send('main:script-environment-update', {
|
||||
@ -458,7 +461,8 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid,
|
||||
runtimeVariables,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
) => {
|
||||
// run post-response vars
|
||||
const postResponseVars = get(request, 'vars.res', []);
|
||||
@ -506,7 +510,8 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionPath,
|
||||
onConsoleLog,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
);
|
||||
|
||||
mainWindow.webContents.send('main:script-environment-update', {
|
||||
@ -523,14 +528,24 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
return scriptResult;
|
||||
};
|
||||
|
||||
// handler for sending http request
|
||||
ipcMain.handle('send-http-request', async (event, item, collection, environment, runtimeVariables) => {
|
||||
const runRequest = async ({ item, collection, environment, runtimeVariables, runInBackground = false }) => {
|
||||
const collectionUid = collection.uid;
|
||||
const collectionPath = collection.pathname;
|
||||
const cancelTokenUid = uuid();
|
||||
const requestUid = uuid();
|
||||
|
||||
mainWindow.webContents.send('main:run-request-event', {
|
||||
const runRequestByItemPathname = async ({ itemPathname }) => {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
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',
|
||||
requestUid,
|
||||
collectionUid,
|
||||
@ -561,7 +576,8 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid,
|
||||
runtimeVariables,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
);
|
||||
|
||||
const axiosInstance = await configureRequest(
|
||||
@ -573,7 +589,7 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionPath
|
||||
);
|
||||
|
||||
mainWindow.webContents.send('main:run-request-event', {
|
||||
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||
type: 'request-sent',
|
||||
requestSent: {
|
||||
url: request.url,
|
||||
@ -645,7 +661,8 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionUid,
|
||||
runtimeVariables,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
);
|
||||
|
||||
// run assertions
|
||||
@ -661,7 +678,7 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
processEnvVars
|
||||
);
|
||||
|
||||
mainWindow.webContents.send('main:run-request-event', {
|
||||
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||
type: 'assertion-results',
|
||||
results: results,
|
||||
itemUid: item.uid,
|
||||
@ -682,10 +699,11 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
collectionPath,
|
||||
onConsoleLog,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
);
|
||||
|
||||
mainWindow.webContents.send('main:run-request-event', {
|
||||
!runInBackground && mainWindow.webContents.send('main:run-request-event', {
|
||||
type: 'test-results',
|
||||
results: testResults.results,
|
||||
itemUid: item.uid,
|
||||
@ -719,6 +737,11 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
|
||||
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) => {
|
||||
@ -996,6 +1019,41 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
nextRequestName = preRequestScriptResult.nextRequestName;
|
||||
}
|
||||
|
||||
if (preRequestScriptResult?.stopExecution) {
|
||||
deleteCancelToken(cancelTokenUid);
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'response-received',
|
||||
error: 'Request has been stopped from pre-request script',
|
||||
responseReceived: {
|
||||
status: 'terminated',
|
||||
statusText: 'Request execution stopped!',
|
||||
data: null
|
||||
},
|
||||
...eventData
|
||||
});
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'testrun-ended',
|
||||
collectionUid,
|
||||
folderUid
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (preRequestScriptResult?.skipRequest) {
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: '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:
|
||||
// i have no clue why electron can't send the request object
|
||||
// without safeParseJSON(safeStringifyJSON(request.data))
|
||||
@ -1114,6 +1172,41 @@ const registerNetworkIpc = (mainWindow) => {
|
||||
nextRequestName = postRequestScriptResult.nextRequestName;
|
||||
}
|
||||
|
||||
if (postRequestScriptResult?.stopExecution) {
|
||||
deleteCancelToken(cancelTokenUid);
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'response-received',
|
||||
error: 'Request has been stopped from post-response script',
|
||||
responseReceived: {
|
||||
status: 'terminated',
|
||||
statusText: 'Request execution stopped!',
|
||||
data: null
|
||||
},
|
||||
...eventData
|
||||
});
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'testrun-ended',
|
||||
collectionUid,
|
||||
folderUid
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (postRequestScriptResult?.skipRequest) {
|
||||
mainWindow.webContents.send('main:run-folder-event', {
|
||||
type: 'request-skipped',
|
||||
error: 'Request has been skipped from post-response script',
|
||||
responseReceived: {
|
||||
status: 'skipped',
|
||||
statusText: 'request skipped via post-response script',
|
||||
data: null
|
||||
},
|
||||
...eventData
|
||||
});
|
||||
currentRequestIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// run assertions
|
||||
const assertions = get(item, 'request.assertions');
|
||||
if (assertions) {
|
||||
|
@ -203,9 +203,31 @@ const getTreePathFromCollectionToItem = (collection, _item) => {
|
||||
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 = {
|
||||
mergeHeaders,
|
||||
mergeVars,
|
||||
mergeScripts,
|
||||
getTreePathFromCollectionToItem
|
||||
getTreePathFromCollectionToItem,
|
||||
slash,
|
||||
findItemByPathname,
|
||||
findItemInCollectionByPathname
|
||||
}
|
@ -13,6 +13,14 @@ class Bru {
|
||||
this.requestVariables = requestVariables || {};
|
||||
this.globalEnvironmentVariables = globalEnvironmentVariables || {};
|
||||
this.collectionPath = collectionPath;
|
||||
this.runner = {
|
||||
skipRequest: () => {
|
||||
this.skipRequest = true;
|
||||
},
|
||||
stopExecution: () => {
|
||||
this.stopExecution = true;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
_interpolate = (str) => {
|
||||
|
@ -408,6 +408,8 @@ class AssertRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
request.assertionResults = assertionResults;
|
||||
|
||||
return assertionResults;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,8 @@ class ScriptRuntime {
|
||||
collectionPath,
|
||||
onConsoleLog,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
) {
|
||||
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
||||
const collectionVariables = request?.collectionVariables || {};
|
||||
@ -92,6 +93,10 @@ class ScriptRuntime {
|
||||
};
|
||||
}
|
||||
|
||||
if(runRequestByItemPathname) {
|
||||
context.bru.runRequest = runRequestByItemPathname;
|
||||
}
|
||||
|
||||
if (this.runtime === 'quickjs') {
|
||||
await executeQuickJsVmAsync({
|
||||
script: script,
|
||||
@ -104,7 +109,9 @@ class ScriptRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution
|
||||
};
|
||||
}
|
||||
|
||||
@ -152,7 +159,9 @@ class ScriptRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution
|
||||
};
|
||||
}
|
||||
|
||||
@ -165,7 +174,8 @@ class ScriptRuntime {
|
||||
collectionPath,
|
||||
onConsoleLog,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
) {
|
||||
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
||||
const collectionVariables = request?.collectionVariables || {};
|
||||
@ -209,6 +219,10 @@ class ScriptRuntime {
|
||||
};
|
||||
}
|
||||
|
||||
if(runRequestByItemPathname) {
|
||||
context.bru.runRequest = runRequestByItemPathname;
|
||||
}
|
||||
|
||||
if (this.runtime === 'quickjs') {
|
||||
await executeQuickJsVmAsync({
|
||||
script: script,
|
||||
@ -221,7 +235,9 @@ class ScriptRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution
|
||||
};
|
||||
}
|
||||
|
||||
@ -269,7 +285,9 @@ class ScriptRuntime {
|
||||
envVariables: cleanJson(envVariables),
|
||||
runtimeVariables: cleanJson(runtimeVariables),
|
||||
globalEnvironmentVariables: cleanJson(globalEnvironmentVariables),
|
||||
nextRequestName: bru.nextRequest
|
||||
nextRequestName: bru.nextRequest,
|
||||
skipRequest: bru.skipRequest,
|
||||
stopExecution: bru.stopExecution
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -46,12 +46,14 @@ class TestRuntime {
|
||||
collectionPath,
|
||||
onConsoleLog,
|
||||
processEnvVars,
|
||||
scriptingConfig
|
||||
scriptingConfig,
|
||||
runRequestByItemPathname
|
||||
) {
|
||||
const globalEnvironmentVariables = request?.globalEnvironmentVariables || {};
|
||||
const collectionVariables = request?.collectionVariables || {};
|
||||
const folderVariables = request?.folderVariables || {};
|
||||
const requestVariables = request?.requestVariables || {};
|
||||
const assertionResults = request?.assertionResults || [];
|
||||
const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables);
|
||||
const req = new BrunoRequest(request);
|
||||
const res = new BrunoResponse(response);
|
||||
@ -75,6 +77,7 @@ class TestRuntime {
|
||||
}
|
||||
|
||||
const __brunoTestResults = new TestResults();
|
||||
|
||||
const test = Test(__brunoTestResults, chai);
|
||||
|
||||
if (!testsFile || !testsFile.length) {
|
||||
@ -88,6 +91,14 @@ class TestRuntime {
|
||||
};
|
||||
}
|
||||
|
||||
bru.getTestResults = async () => {
|
||||
let results = __brunoTestResults.getResults();
|
||||
return results;
|
||||
}
|
||||
bru.getAssertionResults = async () => {
|
||||
return assertionResults
|
||||
}
|
||||
|
||||
const context = {
|
||||
test,
|
||||
bru,
|
||||
@ -113,6 +124,10 @@ class TestRuntime {
|
||||
};
|
||||
}
|
||||
|
||||
if(runRequestByItemPathname) {
|
||||
context.bru.runRequest = runRequestByItemPathname;
|
||||
}
|
||||
|
||||
if (this.runtime === 'quickjs') {
|
||||
await executeQuickJsVmAsync({
|
||||
script: testsFile,
|
||||
|
@ -1,3 +1,4 @@
|
||||
const { cleanJson } = require('../../../utils');
|
||||
const { marshallToVm } = require('../utils');
|
||||
|
||||
const addBruShimToContext = (vm, bru) => {
|
||||
@ -123,6 +124,70 @@ const addBruShimToContext = (vm, bru) => {
|
||||
vm.setProp(bruObject, 'getCollectionVar', getCollectionVar);
|
||||
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 t = vm.getString(timer);
|
||||
const promise = vm.newPromise();
|
||||
|
Reference in New Issue
Block a user