diff --git a/package-lock.json b/package-lock.json
index 01f9bf787..3f0f8ae9c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -50,6 +50,7 @@
},
"node_modules/@ampproject/remapping": {
"version": "2.3.0",
+ "dev": true,
"license": "Apache-2.0",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
@@ -670,6 +671,7 @@
},
"node_modules/@babel/compat-data": {
"version": "7.25.2",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -677,6 +679,7 @@
},
"node_modules/@babel/core": {
"version": "7.25.2",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@ampproject/remapping": "^2.2.0",
@@ -740,6 +743,7 @@
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.25.2",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/compat-data": "^7.25.2",
@@ -754,6 +758,7 @@
},
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
"version": "5.1.1",
+ "dev": true,
"license": "ISC",
"dependencies": {
"yallist": "^3.0.2"
@@ -761,6 +766,7 @@
},
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
"version": "3.1.1",
+ "dev": true,
"license": "ISC"
},
"node_modules/@babel/helper-create-class-features-plugin": {
@@ -839,6 +845,7 @@
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.25.2",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-module-imports": "^7.24.7",
@@ -905,6 +912,7 @@
},
"node_modules/@babel/helper-simple-access": {
"version": "7.24.7",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/traverse": "^7.24.7",
@@ -942,6 +950,7 @@
},
"node_modules/@babel/helper-validator-option": {
"version": "7.24.8",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -962,6 +971,7 @@
},
"node_modules/@babel/helpers": {
"version": "7.25.0",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@babel/template": "^7.25.0",
@@ -3644,37 +3654,6 @@
"node": ">=12"
}
},
- "node_modules/@n8n/vm2": {
- "version": "3.9.25",
- "resolved": "https://registry.npmjs.org/@n8n/vm2/-/vm2-3.9.25.tgz",
- "integrity": "sha512-qoGLFzyHBW7HKpwXkl05QKsIh3GkDw6lOiTOWYlUDnOIQ1b7EgM+O5EMjrMGy7r+kz52+Q7o6GLxBIcxVI8rEg==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "acorn": "^8.7.0",
- "acorn-walk": "^8.2.0"
- },
- "bin": {
- "vm2": "bin/vm2"
- },
- "engines": {
- "node": ">=18.10",
- "pnpm": ">=9.6"
- }
- },
- "node_modules/@n8n/vm2/node_modules/acorn": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
- "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
- "license": "MIT",
- "peer": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
"node_modules/@next/env": {
"version": "12.3.3",
"license": "MIT"
@@ -4751,6 +4730,7 @@
},
"node_modules/@types/linkify-it": {
"version": "5.0.0",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/lodash": {
@@ -4759,6 +4739,7 @@
},
"node_modules/@types/markdown-it": {
"version": "12.2.3",
+ "dev": true,
"license": "MIT",
"dependencies": {
"@types/linkify-it": "*",
@@ -4767,6 +4748,7 @@
},
"node_modules/@types/mdurl": {
"version": "2.0.0",
+ "dev": true,
"license": "MIT"
},
"node_modules/@types/minimatch": {
@@ -6240,6 +6222,7 @@
},
"node_modules/browserslist": {
"version": "4.23.3",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -7238,6 +7221,7 @@
},
"node_modules/convert-source-map": {
"version": "2.0.0",
+ "dev": true,
"license": "MIT"
},
"node_modules/cookie": {
@@ -8477,6 +8461,7 @@
},
"node_modules/electron-to-chromium": {
"version": "1.5.11",
+ "dev": true,
"license": "ISC"
},
"node_modules/electron-util": {
@@ -9438,6 +9423,7 @@
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -13186,6 +13172,7 @@
},
"node_modules/node-releases": {
"version": "2.0.18",
+ "dev": true,
"license": "MIT"
},
"node_modules/node-vault": {
@@ -16201,6 +16188,7 @@
},
"node_modules/semver": {
"version": "6.3.1",
+ "dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -17663,6 +17651,7 @@
},
"node_modules/update-browserslist-db": {
"version": "1.1.0",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -18633,7 +18622,7 @@
},
"packages/bruno-electron": {
"name": "bruno",
- "version": "v1.26.1",
+ "version": "v1.27.0",
"dependencies": {
"@aws-sdk/credential-providers": "3.525.0",
"@usebruno/common": "0.1.0",
diff --git a/packages/bruno-app/src/components/CollectionSettings/Vars/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Vars/StyledWrapper.js
new file mode 100644
index 000000000..44b01b464
--- /dev/null
+++ b/packages/bruno-app/src/components/CollectionSettings/Vars/StyledWrapper.js
@@ -0,0 +1,9 @@
+import styled from 'styled-components';
+
+const StyledWrapper = styled.div`
+ div.title {
+ color: var(--color-tab-inactive);
+ }
+`;
+
+export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/StyledWrapper.js
new file mode 100644
index 000000000..efacc8288
--- /dev/null
+++ b/packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/StyledWrapper.js
@@ -0,0 +1,56 @@
+import styled from 'styled-components';
+
+const Wrapper = styled.div`
+ table {
+ width: 100%;
+ border-collapse: collapse;
+ font-weight: 600;
+ table-layout: fixed;
+
+ thead,
+ td {
+ border: 1px solid ${(props) => props.theme.table.border};
+ }
+
+ thead {
+ color: ${(props) => props.theme.table.thead.color};
+ font-size: 0.8125rem;
+ user-select: none;
+ }
+ td {
+ padding: 6px 10px;
+
+ &:nth-child(1) {
+ width: 30%;
+ }
+
+ &:nth-child(3) {
+ width: 70px;
+ }
+ }
+ }
+
+ .btn-add-var {
+ font-size: 0.8125rem;
+ }
+
+ input[type='text'] {
+ width: 100%;
+ border: solid 1px transparent;
+ outline: none !important;
+ background-color: inherit;
+
+ &:focus {
+ outline: none !important;
+ border: solid 1px transparent;
+ }
+ }
+
+ input[type='checkbox'] {
+ cursor: pointer;
+ position: relative;
+ top: 1px;
+ }
+`;
+
+export default Wrapper;
diff --git a/packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js b/packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js
new file mode 100644
index 000000000..950076b60
--- /dev/null
+++ b/packages/bruno-app/src/components/CollectionSettings/Vars/VarsTable/index.js
@@ -0,0 +1,162 @@
+import React from 'react';
+import cloneDeep from 'lodash/cloneDeep';
+import { IconTrash } from '@tabler/icons';
+import { useDispatch } from 'react-redux';
+import { useTheme } from 'providers/Theme';
+import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
+import SingleLineEditor from 'components/SingleLineEditor';
+import InfoTip from 'components/InfoTip';
+import StyledWrapper from './StyledWrapper';
+import toast from 'react-hot-toast';
+import { variableNameRegex } from 'utils/common/regex';
+import {
+ addCollectionVar,
+ deleteCollectionVar,
+ updateCollectionVar
+} from 'providers/ReduxStore/slices/collections/index';
+
+const VarsTable = ({ collection, vars, varType }) => {
+ const dispatch = useDispatch();
+ const { storedTheme } = useTheme();
+
+ const addVar = () => {
+ dispatch(
+ addCollectionVar({
+ collectionUid: collection.uid,
+ type: varType
+ })
+ );
+ };
+
+ const onSave = () => dispatch(saveCollectionRoot(collection.uid));
+ const handleVarChange = (e, v, type) => {
+ const _var = cloneDeep(v);
+ switch (type) {
+ case 'name': {
+ const value = e.target.value;
+
+ if (variableNameRegex.test(value) === false) {
+ toast.error(
+ 'Variable contains invalid characters! Variables must only contain alpha-numeric characters, "-", "_", "."'
+ );
+ return;
+ }
+
+ _var.name = value;
+ break;
+ }
+ case 'value': {
+ _var.value = e.target.value;
+ break;
+ }
+ case 'enabled': {
+ _var.enabled = e.target.checked;
+ break;
+ }
+ }
+ dispatch(
+ updateCollectionVar({
+ type: varType,
+ var: _var,
+ collectionUid: collection.uid
+ })
+ );
+ };
+
+ const handleRemoveVar = (_var) => {
+ dispatch(
+ deleteCollectionVar({
+ type: varType,
+ varUid: _var.uid,
+ collectionUid: collection.uid
+ })
+ );
+ };
+
+ return (
+
+
+
+
+ );
+};
+export default VarsTable;
diff --git a/packages/bruno-app/src/components/CollectionSettings/Vars/index.js b/packages/bruno-app/src/components/CollectionSettings/Vars/index.js
new file mode 100644
index 000000000..fae3ed613
--- /dev/null
+++ b/packages/bruno-app/src/components/CollectionSettings/Vars/index.js
@@ -0,0 +1,32 @@
+import React from 'react';
+import get from 'lodash/get';
+import VarsTable from './VarsTable';
+import StyledWrapper from './StyledWrapper';
+import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions';
+import { useDispatch } from 'react-redux';
+
+const Vars = ({ collection }) => {
+ const dispatch = useDispatch();
+ const requestVars = get(collection, 'root.request.vars.req', []);
+ const responseVars = get(collection, 'root.request.vars.res', []);
+ const handleSave = () => dispatch(saveCollectionRoot(collection.uid));
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+export default Vars;
diff --git a/packages/bruno-app/src/components/CollectionSettings/index.js b/packages/bruno-app/src/components/CollectionSettings/index.js
index ebf86f724..d7698e26c 100644
--- a/packages/bruno-app/src/components/CollectionSettings/index.js
+++ b/packages/bruno-app/src/components/CollectionSettings/index.js
@@ -16,6 +16,7 @@ import Docs from './Docs';
import Presets from './Presets';
import Info from './Info';
import StyledWrapper from './StyledWrapper';
+import Vars from './Vars/index';
const CollectionSettings = ({ collection }) => {
const dispatch = useDispatch();
@@ -77,6 +78,9 @@ const CollectionSettings = ({ collection }) => {
case 'headers': {
return ;
}
+ case 'vars': {
+ return ;
+ }
case 'auth': {
return ;
}
@@ -123,6 +127,9 @@ const CollectionSettings = ({ collection }) => {
setTab('headers')}>
Headers
+ setTab('vars')}>
+ Vars
+
setTab('auth')}>
Auth
diff --git a/packages/bruno-app/src/components/FolderSettings/Headers/index.js b/packages/bruno-app/src/components/FolderSettings/Headers/index.js
index 550a835c2..0f6e05f1f 100644
--- a/packages/bruno-app/src/components/FolderSettings/Headers/index.js
+++ b/packages/bruno-app/src/components/FolderSettings/Headers/index.js
@@ -116,6 +116,7 @@ const Headers = ({ collection, folder }) => {
)
}
collection={collection}
+ item={folder}
/>
diff --git a/packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js b/packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js
index c3414170e..d0a77de44 100644
--- a/packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js
+++ b/packages/bruno-app/src/components/FolderSettings/Vars/VarsTable/index.js
@@ -130,6 +130,7 @@ const VarsTable = ({ folder, collection, vars, varType }) => {
)
}
collection={collection}
+ item={folder}
/>
|
diff --git a/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js b/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js
index 375fa0ec4..38250f8ea 100644
--- a/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js
+++ b/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js
@@ -191,6 +191,7 @@ const AssertionRow = ({
}
onRun={handleRun}
collection={collection}
+ item={item}
/>
) : (
diff --git a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js
index 1ed01da24..84f040c6e 100644
--- a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js
+++ b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js
@@ -132,6 +132,7 @@ const VarsTable = ({ item, collection, vars, varType }) => {
}
onRun={handleRun}
collection={collection}
+ item={item}
/>
|
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
index ca66ac2ea..63e49360c 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
@@ -1302,6 +1302,71 @@ export const collectionsSlice = createSlice({
set(collection, 'root.request.headers', headers);
}
},
+ addCollectionVar: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+ const type = action.payload.type;
+ if (collection) {
+ if (type === 'request') {
+ const vars = get(collection, 'root.request.vars.req', []);
+ vars.push({
+ uid: uuid(),
+ name: '',
+ value: '',
+ enabled: true
+ });
+ set(collection, 'root.request.vars.req', vars);
+ } else if (type === 'response') {
+ const vars = get(collection, 'root.request.vars.res', []);
+ vars.push({
+ uid: uuid(),
+ name: '',
+ value: '',
+ enabled: true
+ });
+ set(collection, 'root.request.vars.res', vars);
+ }
+ }
+ },
+ updateCollectionVar: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+ const type = action.payload.type;
+ if (type === 'request') {
+ let vars = get(collection, 'root.request.vars.req', []);
+ const _var = find(vars, (h) => h.uid === action.payload.var.uid);
+ if (_var) {
+ _var.name = action.payload.var.name;
+ _var.value = action.payload.var.value;
+ _var.description = action.payload.var.description;
+ _var.enabled = action.payload.var.enabled;
+ }
+ set(collection, 'root.request.vars.req', vars);
+ } else if (type === 'response') {
+ let vars = get(collection, 'root.request.vars.res', []);
+ const _var = find(vars, (h) => h.uid === action.payload.var.uid);
+ if (_var) {
+ _var.name = action.payload.var.name;
+ _var.value = action.payload.var.value;
+ _var.description = action.payload.var.description;
+ _var.enabled = action.payload.var.enabled;
+ }
+ set(collection, 'root.request.vars.res', vars);
+ }
+ },
+ deleteCollectionVar: (state, action) => {
+ const collection = findCollectionByUid(state.collections, action.payload.collectionUid);
+ const type = action.payload.type;
+ if (collection) {
+ if (type === 'request') {
+ let vars = get(collection, 'root.request.vars.req', []);
+ vars = filter(vars, (h) => h.uid !== action.payload.varUid);
+ set(collection, 'root.request.vars.req', vars);
+ } else if (type === 'response') {
+ let vars = get(collection, 'root.request.vars.res', []);
+ vars = filter(vars, (h) => h.uid !== action.payload.varUid);
+ set(collection, 'root.request.vars.res', vars);
+ }
+ }
+ },
collectionAddFileEvent: (state, action) => {
const file = action.payload.file;
const isCollectionRoot = file.meta.collectionRoot ? true : false;
@@ -1694,6 +1759,9 @@ export const {
addCollectionHeader,
updateCollectionHeader,
deleteCollectionHeader,
+ addCollectionVar,
+ updateCollectionVar,
+ deleteCollectionVar,
updateCollectionAuthMode,
updateCollectionAuth,
updateCollectionRequestScript,
diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js
index 7dc9f2e57..d872a6685 100644
--- a/packages/bruno-app/src/utils/collections/index.js
+++ b/packages/bruno-app/src/utils/collections/index.js
@@ -787,24 +787,25 @@ export const getTotalRequestCountInCollection = (collection) => {
};
export const getAllVariables = (collection, item) => {
- const environmentVariables = getEnvironmentVariables(collection);
- let requestVariables = {};
- if (item?.request) {
- const requestTreePath = getTreePathFromCollectionToItem(collection, item);
- requestVariables = mergeFolderLevelVars(item?.request, requestTreePath);
- }
+ const envVariables = getEnvironmentVariables(collection);
+ const requestTreePath = getTreePathFromCollectionToItem(collection, item);
+ let { collectionVariables, folderVariables, requestVariables } = mergeVars(collection, requestTreePath);
const pathParams = getPathParams(item);
+ const { processEnvVariables = {}, runtimeVariables = {} } = collection;
+
return {
- ...environmentVariables,
+ ...collectionVariables,
+ ...envVariables,
+ ...folderVariables,
...requestVariables,
- ...collection.runtimeVariables,
+ ...runtimeVariables,
pathParams: {
...pathParams
},
process: {
env: {
- ...collection.processEnvVariables
+ ...processEnvVariables
}
}
};
@@ -831,14 +832,22 @@ const getTreePathFromCollectionToItem = (collection, _item) => {
return path;
};
-const mergeFolderLevelVars = (request, requestTreePath = []) => {
+const mergeVars = (collection, requestTreePath = []) => {
+ let collectionVariables = {};
+ let folderVariables = {};
let requestVariables = {};
+ let collectionRequestVars = get(collection, 'root.request.vars.req', []);
+ collectionRequestVars.forEach((_var) => {
+ if (_var.enabled) {
+ collectionVariables[_var.name] = _var.value;
+ }
+ });
for (let i of requestTreePath) {
if (i.type === 'folder') {
let vars = get(i, 'root.request.vars.req', []);
vars.forEach((_var) => {
if (_var.enabled) {
- requestVariables[_var.name] = _var.value;
+ folderVariables[_var.name] = _var.value;
}
});
} else {
@@ -850,6 +859,9 @@ const mergeFolderLevelVars = (request, requestTreePath = []) => {
});
}
}
-
- return requestVariables;
+ return {
+ collectionVariables,
+ folderVariables,
+ requestVariables
+ };
};
diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js
index b77c7f61e..b260f6be9 100644
--- a/packages/bruno-cli/src/runner/run-single-request.js
+++ b/packages/bruno-cli/src/runner/run-single-request.js
@@ -60,20 +60,6 @@ const runSingleRequest = async function (
request.data = form;
}
- // run pre-request vars
- const preRequestVars = get(bruJson, 'request.vars.req');
- if (preRequestVars?.length) {
- const varsRuntime = new VarsRuntime({ runtime: scriptingConfig?.runtime });
- varsRuntime.runPreRequestVars(
- preRequestVars,
- request,
- envVariables,
- runtimeVariables,
- collectionPath,
- processEnvVars
- );
- }
-
// run pre request script
const requestScriptFile = compact([
get(collectionRoot, 'request.script.req'),
@@ -276,7 +262,7 @@ const runSingleRequest = async function (
console.log(
chalk.green(stripExtension(filename)) +
- chalk.dim(` (${response.status} ${response.statusText}) - ${responseTime} ms`)
+ chalk.dim(` (${response.status} ${response.statusText}) - ${responseTime} ms`)
);
// run post-response vars
diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js
index 991dc4d06..04bd5b4fd 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -347,10 +347,10 @@ const parseDataFromResponse = (response, disableParsingResponseJson = false) =>
// Filter out ZWNBSP character
// https://gist.github.com/antic183/619f42b559b78028d1fe9e7ae8a1352d
data = data.replace(/^\uFEFF/, '');
- if(!disableParsingResponseJson) {
+ if (!disableParsingResponseJson) {
data = JSON.parse(data);
}
- } catch {}
+ } catch { }
return { data, dataBuffer };
};
@@ -376,20 +376,6 @@ const registerNetworkIpc = (mainWindow) => {
processEnvVars,
scriptingConfig
) => {
- // run pre-request vars
- const preRequestVars = get(request, 'vars.req', []);
- if (preRequestVars?.length) {
- const varsRuntime = new VarsRuntime({ runtime: scriptingConfig?.runtime });
- varsRuntime.runPreRequestVars(
- preRequestVars,
- request,
- envVars,
- runtimeVariables,
- collectionPath,
- processEnvVars
- );
- }
-
// run pre-request script
let scriptResult;
const requestScript = compact([get(collectionRoot, 'request.script.req'), get(request, 'script.req')]).join(os.EOL);
@@ -1217,7 +1203,7 @@ const registerNetworkIpc = (mainWindow) => {
try {
const disposition = contentDispositionParser.parse(contentDisposition);
return disposition && disposition.parameters['filename'];
- } catch (error) {}
+ } catch (error) { }
};
const getFileNameFromUrlPath = () => {
diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
index 899b3d0f2..b6aeaa078 100644
--- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js
+++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
@@ -12,15 +12,17 @@ const getContentType = (headers = {}) => {
return contentType;
};
-const interpolateVars = (request, envVars = {}, runtimeVariables = {}, processEnvVars = {}) => {
+const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, processEnvVars = {}) => {
+ const collectionVariables = request?.collectionVariables || {};
+ const folderVariables = request?.folderVariables || {};
const requestVariables = request?.requestVariables || {};
// we clone envVars because we don't want to modify the original object
- envVars = cloneDeep(envVars);
+ envVariables = cloneDeep(envVariables);
// envVars can inturn have values as {{process.env.VAR_NAME}}
// so we need to interpolate envVars first with processEnvVars
- forOwn(envVars, (value, key) => {
- envVars[key] = interpolate(value, {
+ forOwn(envVariables, (value, key) => {
+ envVariables[key] = interpolate(value, {
process: {
env: {
...processEnvVars
@@ -36,7 +38,9 @@ const interpolateVars = (request, envVars = {}, runtimeVariables = {}, processEn
// runtimeVariables take precedence over envVars
const combinedVars = {
- ...envVars,
+ ...collectionVariables,
+ ...envVariables,
+ ...folderVariables,
...requestVariables,
...runtimeVariables,
process: {
diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js
index 74cb85ac6..38f8f5d3c 100644
--- a/packages/bruno-electron/src/ipc/network/prepare-request.js
+++ b/packages/bruno-electron/src/ipc/network/prepare-request.js
@@ -44,73 +44,75 @@ const mergeFolderLevelHeaders = (request, requestTreePath) => {
request.headers = Array.from(requestHeadersMap, ([name, value]) => ({ name, value, enabled: true }));
};
-const mergeFolderLevelVars = (request, requestTreePath) => {
- let folderReqVars = new Map();
+const mergeVars = (collection, request, requestTreePath) => {
+ let reqVars = new Map();
+ let collectionRequestVars = get(collection, 'root.request.vars.req', []);
+ let collectionVariables = {};
+ collectionRequestVars.forEach((_var) => {
+ if (_var.enabled) {
+ reqVars.set(_var.name, _var.value);
+ collectionVariables[_var.name] = _var.value;
+ }
+ });
+ let folderVariables = {};
+ let requestVariables = {};
for (let i of requestTreePath) {
if (i.type === 'folder') {
let vars = get(i, 'root.request.vars.req', []);
vars.forEach((_var) => {
if (_var.enabled) {
- folderReqVars.set(_var.name, _var.value);
+ reqVars.set(_var.name, _var.value);
+ folderVariables[_var.name] = _var.value;
}
});
- } else if (i.uid === request.uid) {
+ } else {
const vars = i?.draft ? get(i, 'draft.request.vars.req', []) : get(i, 'request.vars.req', []);
vars.forEach((_var) => {
if (_var.enabled) {
- folderReqVars.set(_var.name, _var.value);
+ reqVars.set(_var.name, _var.value);
+ requestVariables[_var.name] = _var.value;
}
});
}
}
- let mergedFolderReqVars = Array.from(folderReqVars, ([name, value]) => ({ name, value, enabled: true }));
- let requestReqVars = request?.vars?.req || [];
- let requestReqVarsMap = new Map();
- for (let _var of requestReqVars) {
- if (_var.enabled) {
- requestReqVarsMap.set(_var.name, _var.value);
- }
- }
- mergedFolderReqVars.forEach((_var) => {
- requestReqVarsMap.set(_var.name, _var.value);
- });
- request.vars.req = Array.from(requestReqVarsMap, ([name, value]) => ({
+
+ request.collectionVariables = collectionVariables;
+ request.folderVariables = folderVariables;
+ request.requestVariables = requestVariables;
+
+ request.vars.req = Array.from(reqVars, ([name, value]) => ({
name,
value,
enabled: true,
type: 'request'
}));
- let folderResVars = new Map();
+ let resVars = new Map();
+ let collectionResponseVars = get(collection, 'root.request.vars.res', []);
+ collectionResponseVars.forEach((_var) => {
+ if (_var.enabled) {
+ resVars.set(_var.name, _var.value);
+ }
+ });
for (let i of requestTreePath) {
if (i.type === 'folder') {
let vars = get(i, 'root.request.vars.res', []);
vars.forEach((_var) => {
if (_var.enabled) {
- folderResVars.set(_var.name, _var.value);
+ resVars.set(_var.name, _var.value);
}
});
- } else if (i.uid === request.uid) {
+ } else {
const vars = i?.draft ? get(i, 'draft.request.vars.res', []) : get(i, 'request.vars.res', []);
vars.forEach((_var) => {
if (_var.enabled) {
- folderResVars.set(_var.name, _var.value);
+ resVars.set(_var.name, _var.value);
}
});
}
}
- let mergedFolderResVars = Array.from(folderResVars, ([name, value]) => ({ name, value, enabled: true }));
- let requestResVars = request?.vars?.res || [];
- let requestResVarsMap = new Map();
- for (let _var of requestResVars) {
- if (_var.enabled) {
- requestResVarsMap.set(_var.name, _var.value);
- }
- }
- mergedFolderResVars.forEach((_var) => {
- requestResVarsMap.set(_var.name, _var.value);
- });
- request.vars.res = Array.from(requestResVarsMap, ([name, value]) => ({
+
+ request.vars.res = Array.from(resVars, ([name, value]) => ({
name,
value,
enabled: true,
@@ -314,7 +316,7 @@ const prepareRequest = (item, collection) => {
if (requestTreePath && requestTreePath.length > 0) {
mergeFolderLevelHeaders(request, requestTreePath);
mergeFolderLevelScripts(request, requestTreePath, scriptFlow);
- mergeFolderLevelVars(request, requestTreePath);
+ mergeVars(collection, request, requestTreePath);
}
each(request.headers, (h) => {
@@ -401,6 +403,9 @@ const prepareRequest = (item, collection) => {
}
axiosRequest.vars = request.vars;
+ axiosRequest.collectionVariables = request.collectionVariables;
+ axiosRequest.folderVariables = request.folderVariables;
+ axiosRequest.requestVariables = request.requestVariables;
axiosRequest.assertions = request.assertions;
return axiosRequest;
diff --git a/packages/bruno-js/src/bru.js b/packages/bruno-js/src/bru.js
index 8dfc69486..7f24cea14 100644
--- a/packages/bruno-js/src/bru.js
+++ b/packages/bruno-js/src/bru.js
@@ -4,10 +4,12 @@ const { interpolate } = require('@usebruno/common');
const variableNameRegex = /^[\w-.]*$/;
class Bru {
- constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, requestVariables) {
+ constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables) {
this.envVariables = envVariables || {};
this.runtimeVariables = runtimeVariables || {};
this.processEnvVars = cloneDeep(processEnvVars || {});
+ this.collectionVariables = collectionVariables || {};
+ this.folderVariables = folderVariables || {};
this.requestVariables = requestVariables || {};
this.collectionPath = collectionPath;
}
@@ -18,7 +20,9 @@ class Bru {
}
const combinedVars = {
+ ...this.collectionVariables,
...this.envVariables,
+ ...this.folderVariables,
...this.requestVariables,
...this.runtimeVariables,
process: {
@@ -71,7 +75,7 @@ class Bru {
if (variableNameRegex.test(key) === false) {
throw new Error(
`Variable name: "${key}" contains invalid characters!` +
- ' Names must only contain alpha-numeric characters, "-", "_", "."'
+ ' Names must only contain alpha-numeric characters, "-", "_", "."'
);
}
@@ -82,7 +86,7 @@ class Bru {
if (variableNameRegex.test(key) === false) {
throw new Error(
`Variable name: "${key}" contains invalid characters!` +
- ' Names must only contain alpha-numeric characters, "-", "_", "."'
+ ' Names must only contain alpha-numeric characters, "-", "_", "."'
);
}
@@ -93,6 +97,14 @@ class Bru {
delete this.runtimeVariables[key];
}
+ getCollectionVar(key) {
+ return this._interpolate(this.collectionVariables[key]);
+ }
+
+ getFolderVar(key) {
+ return this._interpolate(this.folderVariables[key]);
+ }
+
getRequestVar(key) {
return this._interpolate(this.requestVariables[key]);
}
diff --git a/packages/bruno-js/src/interpolate-string.js b/packages/bruno-js/src/interpolate-string.js
index 637b03832..2692641c2 100644
--- a/packages/bruno-js/src/interpolate-string.js
+++ b/packages/bruno-js/src/interpolate-string.js
@@ -2,14 +2,16 @@ const { interpolate } = require('@usebruno/common');
const interpolateString = (
str,
- { envVariables = {}, runtimeVariables = {}, processEnvVars = {}, requestVariables = {} }
+ { envVariables = {}, runtimeVariables = {}, processEnvVars = {}, collectionVariables = {}, folderVariables = {}, requestVariables = {} }
) => {
if (!str || !str.length || typeof str !== 'string') {
return str;
}
const combinedVars = {
+ ...collectionVariables,
...envVariables,
+ ...folderVariables,
...requestVariables,
...runtimeVariables,
process: {
diff --git a/packages/bruno-js/src/runtime/assert-runtime.js b/packages/bruno-js/src/runtime/assert-runtime.js
index 5b904dee4..aafacfe8a 100644
--- a/packages/bruno-js/src/runtime/assert-runtime.js
+++ b/packages/bruno-js/src/runtime/assert-runtime.js
@@ -192,6 +192,8 @@ const evaluateRhsOperand = (rhsOperand, operator, context, runtime) => {
}
const interpolationContext = {
+ collectionVariables: context.bru.collectionVariables,
+ folderVariables: context.bru.folderVariables,
requestVariables: context.bru.requestVariables,
runtimeVariables: context.bru.runtimeVariables,
envVariables: context.bru.envVariables,
@@ -238,13 +240,23 @@ class AssertRuntime {
}
runAssertions(assertions, request, response, envVariables, runtimeVariables, processEnvVars) {
+ const collectionVariables = request?.collectionVariables || {};
+ const folderVariables = request?.folderVariables || {};
const requestVariables = request?.requestVariables || {};
const enabledAssertions = _.filter(assertions, (a) => a.enabled);
if (!enabledAssertions.length) {
return [];
}
- const bru = new Bru(envVariables, runtimeVariables, processEnvVars, undefined, requestVariables);
+ const bru = new Bru(
+ envVariables,
+ runtimeVariables,
+ processEnvVars,
+ undefined,
+ collectionVariables,
+ folderVariables,
+ requestVariables
+ );
const req = new BrunoRequest(request);
const res = createResponseParser(response);
@@ -255,7 +267,9 @@ class AssertRuntime {
};
const context = {
+ ...collectionVariables,
...envVariables,
+ ...folderVariables,
...requestVariables,
...runtimeVariables,
...processEnvVars,
diff --git a/packages/bruno-js/src/runtime/script-runtime.js b/packages/bruno-js/src/runtime/script-runtime.js
index 9a9338c10..9dc47a29d 100644
--- a/packages/bruno-js/src/runtime/script-runtime.js
+++ b/packages/bruno-js/src/runtime/script-runtime.js
@@ -47,8 +47,10 @@ class ScriptRuntime {
processEnvVars,
scriptingConfig
) {
+ const collectionVariables = request?.collectionVariables || {};
+ const folderVariables = request?.folderVariables || {};
const requestVariables = request?.requestVariables || {};
- const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, requestVariables);
+ const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables);
const req = new BrunoRequest(request);
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
const moduleWhitelist = get(scriptingConfig, 'moduleWhitelist', []);
@@ -162,8 +164,10 @@ class ScriptRuntime {
processEnvVars,
scriptingConfig
) {
+ const collectionVariables = request?.collectionVariables || {};
+ const folderVariables = request?.folderVariables || {};
const requestVariables = request?.requestVariables || {};
- const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, requestVariables);
+ const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables);
const req = new BrunoRequest(request);
const res = new BrunoResponse(response);
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
diff --git a/packages/bruno-js/src/runtime/test-runtime.js b/packages/bruno-js/src/runtime/test-runtime.js
index 7fa9941ed..53fab05eb 100644
--- a/packages/bruno-js/src/runtime/test-runtime.js
+++ b/packages/bruno-js/src/runtime/test-runtime.js
@@ -48,8 +48,10 @@ class TestRuntime {
processEnvVars,
scriptingConfig
) {
+ const collectionVariables = request?.collectionVariables || {};
+ const folderVariables = request?.folderVariables || {};
const requestVariables = request?.requestVariables || {};
- const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, requestVariables);
+ const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables);
const req = new BrunoRequest(request);
const res = new BrunoResponse(response);
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
diff --git a/packages/bruno-js/src/runtime/vars-runtime.js b/packages/bruno-js/src/runtime/vars-runtime.js
index 4f4bd3719..1ed806000 100644
--- a/packages/bruno-js/src/runtime/vars-runtime.js
+++ b/packages/bruno-js/src/runtime/vars-runtime.js
@@ -1,22 +1,10 @@
const _ = require('lodash');
const Bru = require('../bru');
const BrunoRequest = require('../bruno-request');
-const { evaluateJsTemplateLiteral, evaluateJsExpression, createResponseParser } = require('../utils');
+const { evaluateJsExpression, createResponseParser } = require('../utils');
const { executeQuickJsVm } = require('../sandbox/quickjs');
-const evaluateJsTemplateLiteralBasedOnRuntime = (literal, context, runtime) => {
- if (runtime === 'quickjs') {
- return executeQuickJsVm({
- script: literal,
- context,
- scriptType: 'template-literal'
- });
- }
-
- return evaluateJsTemplateLiteral(literal, context);
-};
-
const evaluateJsExpressionBasedOnRuntime = (expr, context, runtime, mode) => {
if (runtime === 'quickjs') {
return executeQuickJsVm({
@@ -35,35 +23,6 @@ class VarsRuntime {
this.mode = props?.mode || 'developer';
}
- runPreRequestVars(vars, request, envVariables, runtimeVariables, collectionPath, processEnvVars) {
- if (!request?.requestVariables) {
- request.requestVariables = {};
- }
- const enabledVars = _.filter(vars, (v) => v.enabled);
- if (!enabledVars.length) {
- return;
- }
-
- const bru = new Bru(envVariables, runtimeVariables, processEnvVars);
- const req = new BrunoRequest(request);
-
- const bruContext = {
- bru,
- req
- };
-
- const context = {
- ...envVariables,
- ...runtimeVariables,
- ...bruContext
- };
-
- _.each(enabledVars, (v) => {
- const value = evaluateJsTemplateLiteralBasedOnRuntime(v.value, context, this.runtime);
- request?.requestVariables && (request.requestVariables[v.name] = value);
- });
- }
-
runPostResponseVars(vars, request, response, envVariables, runtimeVariables, collectionPath, processEnvVars) {
const requestVariables = request?.requestVariables || {};
const enabledVars = _.filter(vars, (v) => v.enabled);
diff --git a/packages/bruno-js/src/sandbox/quickjs/shims/bru.js b/packages/bruno-js/src/sandbox/quickjs/shims/bru.js
index ced639893..f045b134b 100644
--- a/packages/bruno-js/src/sandbox/quickjs/shims/bru.js
+++ b/packages/bruno-js/src/sandbox/quickjs/shims/bru.js
@@ -69,6 +69,18 @@ const addBruShimToContext = (vm, bru) => {
vm.setProp(bruObject, 'getRequestVar', getRequestVar);
getRequestVar.dispose();
+ let getFolderVar = vm.newFunction('getFolderVar', function (key) {
+ return marshallToVm(bru.getFolderVar(vm.dump(key)), vm);
+ });
+ vm.setProp(bruObject, 'getFolderVar', getFolderVar);
+ getFolderVar.dispose();
+
+ let getCollectionVar = vm.newFunction('getCollectionVar', function (key) {
+ return marshallToVm(bru.getCollectionVar(vm.dump(key)), vm);
+ });
+ vm.setProp(bruObject, 'getCollectionVar', getCollectionVar);
+ getCollectionVar.dispose();
+
const sleep = vm.newFunction('sleep', (timer) => {
const t = vm.getString(timer);
const promise = vm.newPromise();
diff --git a/packages/bruno-tests/collection/collection.bru b/packages/bruno-tests/collection/collection.bru
index ab9776995..d4b353eb8 100644
--- a/packages/bruno-tests/collection/collection.bru
+++ b/packages/bruno-tests/collection/collection.bru
@@ -1,5 +1,6 @@
headers {
check: again
+ token: {{collection_pre_var_token}}
}
auth {
@@ -10,6 +11,11 @@ auth:bearer {
token: {{bearer_auth_token}}
}
+vars:pre-request {
+ collection_pre_var: collection_pre_var_value
+ collection_pre_var_token: {{request_pre_var_token}}
+}
+
docs {
# bruno-testbench 🐶
diff --git a/packages/bruno-tests/collection/scripting/js/data types - request vars.bru b/packages/bruno-tests/collection/scripting/js/data types - request vars.bru
index d8a8af9f2..a0f7c91a8 100644
--- a/packages/bruno-tests/collection/scripting/js/data types - request vars.bru
+++ b/packages/bruno-tests/collection/scripting/js/data types - request vars.bru
@@ -25,16 +25,6 @@ body:json {
}
}
-vars:pre-request {
- boolean: false
- undefined: undefined
- null: null
- string: foo
- number_1: 1
- number_2: 0
- number_3: -1
-}
-
assert {
req.body.boolean: isBoolean false
req.body.number_1: isNumber 1
@@ -51,35 +41,4 @@ assert {
req.body.number_3: eq -1
req.body.number_2: isNumber
req.body.number_3: isNumber
- boolean: eq false
- undefined: eq undefined
- null: eq null
- string: eq foo
- number_1: eq 1
- number_2: eq 0
- number_3: eq -1
-}
-
-tests {
- test("boolean pre var", function() {
- expect(bru.getRequestVar('boolean')).to.eql(false);
- });
-
- test("number pre var", function() {
- expect(bru.getRequestVar('number_1')).to.eql(1);
- expect(bru.getRequestVar('number_2')).to.eql(0);
- expect(bru.getRequestVar('number_3')).to.eql(-1);
- });
-
- test("null pre var", function() {
- expect(bru.getRequestVar('null')).to.eql(null);
- });
-
- test("undefined pre var", function() {
- expect(bru.getRequestVar('undefined')).to.eql(undefined);
- });
-
- test("string pre var", function() {
- expect(bru.getRequestVar('string')).to.eql('foo');
- });
}
diff --git a/packages/bruno-tests/collection/string interpolation/folder.bru b/packages/bruno-tests/collection/string interpolation/folder.bru
new file mode 100644
index 000000000..8aef24cb2
--- /dev/null
+++ b/packages/bruno-tests/collection/string interpolation/folder.bru
@@ -0,0 +1,8 @@
+meta {
+ name: string interpolation
+}
+
+vars:pre-request {
+ folder_pre_var: folder_pre_var_value
+ folder_pre_var_2: {{env.var1}}
+}
diff --git a/packages/bruno-tests/collection/string interpolation/pre-vars.bru b/packages/bruno-tests/collection/string interpolation/pre-vars.bru
new file mode 100644
index 000000000..9a6d8d8f4
--- /dev/null
+++ b/packages/bruno-tests/collection/string interpolation/pre-vars.bru
@@ -0,0 +1,48 @@
+meta {
+ name: pre-vars
+ type: http
+ seq: 5
+}
+
+get {
+ url: {{host}}/ping
+ body: none
+ auth: none
+}
+
+headers {
+ request_pre_var: {{request_pre_var}}
+}
+
+vars:pre-request {
+ request_pre_var: {{folder_pre_var}}
+ request_pre_var_token: request_pre_var_token_value
+ request_pre_var_1: request_pre_var_1_value
+ request_pre_var_2: {{request_pre_var_1}}
+}
+
+assert {
+ collection_pre_var: eq collection_pre_var_value
+ folder_pre_var: eq folder_pre_var_value
+}
+
+tests {
+ test("collection pre var bru function", function() {
+ expect(bru.getCollectionVar('collection_pre_var')).to.eql('collection_pre_var_value');
+ });
+
+
+ test("folder pre var bru function", function() {
+ expect(bru.getFolderVar('folder_pre_var')).to.eql('folder_pre_var_value');
+ });
+
+
+ test("request pre var bru function", function() {
+ expect(bru.getRequestVar('request_pre_var')).to.eql('folder_pre_var_value');
+ });
+
+ test("request pre var self-interpoaltion", function() {
+ expect(bru.getRequestVar('request_pre_var_2')).to.eql('request_pre_var_1_value');
+ });
+
+}
|