mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-07 08:34:15 +01:00
Collection Variables Support (#2963)
* Update package.json * Update package.json * Update package.json * Update package.json * draft: collection varaibles * reverted jest command * precedence update * feat: updates * feat: updates * feat: updates * feat: pre-vars values as strings * feat: updates --------- Co-authored-by: lohit <lohit.jiddimani@gmail.com> Co-authored-by: lohit <lohxt.space@gmail.com>
This commit is contained in:
parent
93080de2a8
commit
5713e19c23
53
package-lock.json
generated
53
package-lock.json
generated
@ -50,6 +50,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
@ -670,6 +671,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.25.2",
|
"version": "7.25.2",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@ -677,6 +679,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/core": {
|
"node_modules/@babel/core": {
|
||||||
"version": "7.25.2",
|
"version": "7.25.2",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.2.0",
|
"@ampproject/remapping": "^2.2.0",
|
||||||
@ -740,6 +743,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets": {
|
"node_modules/@babel/helper-compilation-targets": {
|
||||||
"version": "7.25.2",
|
"version": "7.25.2",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.25.2",
|
"@babel/compat-data": "^7.25.2",
|
||||||
@ -754,6 +758,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
|
"node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
@ -761,6 +766,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
|
"node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-create-class-features-plugin": {
|
"node_modules/@babel/helper-create-class-features-plugin": {
|
||||||
@ -839,6 +845,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-transforms": {
|
"node_modules/@babel/helper-module-transforms": {
|
||||||
"version": "7.25.2",
|
"version": "7.25.2",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-module-imports": "^7.24.7",
|
"@babel/helper-module-imports": "^7.24.7",
|
||||||
@ -905,6 +912,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/helper-simple-access": {
|
"node_modules/@babel/helper-simple-access": {
|
||||||
"version": "7.24.7",
|
"version": "7.24.7",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/traverse": "^7.24.7",
|
"@babel/traverse": "^7.24.7",
|
||||||
@ -942,6 +950,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-option": {
|
"node_modules/@babel/helper-validator-option": {
|
||||||
"version": "7.24.8",
|
"version": "7.24.8",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@ -962,6 +971,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@babel/helpers": {
|
"node_modules/@babel/helpers": {
|
||||||
"version": "7.25.0",
|
"version": "7.25.0",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.25.0",
|
"@babel/template": "^7.25.0",
|
||||||
@ -3644,37 +3654,6 @@
|
|||||||
"node": ">=12"
|
"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": {
|
"node_modules/@next/env": {
|
||||||
"version": "12.3.3",
|
"version": "12.3.3",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
@ -4751,6 +4730,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@types/linkify-it": {
|
"node_modules/@types/linkify-it": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
@ -4759,6 +4739,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@types/markdown-it": {
|
"node_modules/@types/markdown-it": {
|
||||||
"version": "12.2.3",
|
"version": "12.2.3",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/linkify-it": "*",
|
"@types/linkify-it": "*",
|
||||||
@ -4767,6 +4748,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/@types/mdurl": {
|
"node_modules/@types/mdurl": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/minimatch": {
|
"node_modules/@types/minimatch": {
|
||||||
@ -6240,6 +6222,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.23.3",
|
"version": "4.23.3",
|
||||||
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -7238,6 +7221,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/convert-source-map": {
|
"node_modules/convert-source-map": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cookie": {
|
"node_modules/cookie": {
|
||||||
@ -8477,6 +8461,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.11",
|
"version": "1.5.11",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/electron-util": {
|
"node_modules/electron-util": {
|
||||||
@ -9438,6 +9423,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/gensync": {
|
"node_modules/gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
@ -13186,6 +13172,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/node-releases": {
|
"node_modules/node-releases": {
|
||||||
"version": "2.0.18",
|
"version": "2.0.18",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/node-vault": {
|
"node_modules/node-vault": {
|
||||||
@ -16201,6 +16188,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "6.3.1",
|
"version": "6.3.1",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
@ -17663,6 +17651,7 @@
|
|||||||
},
|
},
|
||||||
"node_modules/update-browserslist-db": {
|
"node_modules/update-browserslist-db": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
@ -18633,7 +18622,7 @@
|
|||||||
},
|
},
|
||||||
"packages/bruno-electron": {
|
"packages/bruno-electron": {
|
||||||
"name": "bruno",
|
"name": "bruno",
|
||||||
"version": "v1.26.1",
|
"version": "v1.27.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/credential-providers": "3.525.0",
|
"@aws-sdk/credential-providers": "3.525.0",
|
||||||
"@usebruno/common": "0.1.0",
|
"@usebruno/common": "0.1.0",
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const StyledWrapper = styled.div`
|
||||||
|
div.title {
|
||||||
|
color: var(--color-tab-inactive);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default StyledWrapper;
|
@ -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;
|
@ -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 (
|
||||||
|
<StyledWrapper className="w-full">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>Name</td>
|
||||||
|
{varType === 'request' ? (
|
||||||
|
<td>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<span>Value</span>
|
||||||
|
<InfoTip text="You can write any valid JS Template Literal here" infotipId="request-var" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
) : (
|
||||||
|
<td>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<span>Expr</span>
|
||||||
|
<InfoTip text="You can write any valid JS Template Literal here" infotipId="request-var" />
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
)}
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{vars && vars.length
|
||||||
|
? vars.map((_var) => {
|
||||||
|
return (
|
||||||
|
<tr key={_var.uid}>
|
||||||
|
<td>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
autoComplete="off"
|
||||||
|
autoCorrect="off"
|
||||||
|
autoCapitalize="off"
|
||||||
|
spellCheck="false"
|
||||||
|
value={_var.name}
|
||||||
|
className="mousetrap"
|
||||||
|
onChange={(e) => handleVarChange(e, _var, 'name')}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<SingleLineEditor
|
||||||
|
value={_var.value}
|
||||||
|
theme={storedTheme}
|
||||||
|
onSave={onSave}
|
||||||
|
onChange={(newValue) =>
|
||||||
|
handleVarChange(
|
||||||
|
{
|
||||||
|
target: {
|
||||||
|
value: newValue
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_var,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
collection={collection}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={_var.enabled}
|
||||||
|
tabIndex="-1"
|
||||||
|
className="mr-3 mousetrap"
|
||||||
|
onChange={(e) => handleVarChange(e, _var, 'enabled')}
|
||||||
|
/>
|
||||||
|
<button tabIndex="-1" onClick={() => handleRemoveVar(_var)}>
|
||||||
|
<IconTrash strokeWidth={1.5} size={20} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<button className="btn-add-var text-link pr-2 py-3 mt-2 select-none" onClick={addVar}>
|
||||||
|
+ Add
|
||||||
|
</button>
|
||||||
|
</StyledWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export default VarsTable;
|
@ -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 (
|
||||||
|
<StyledWrapper className="w-full flex flex-col">
|
||||||
|
<div className="flex-1 mt-2">
|
||||||
|
<div className="mb-1 title text-xs">Pre Request</div>
|
||||||
|
<VarsTable collection={collection} vars={requestVars} varType="request" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="mt-1 mb-1 title text-xs">Post Response</div>
|
||||||
|
<VarsTable collection={collection} vars={responseVars} varType="response" />
|
||||||
|
</div>
|
||||||
|
<div className="mt-6">
|
||||||
|
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</StyledWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Vars;
|
@ -16,6 +16,7 @@ import Docs from './Docs';
|
|||||||
import Presets from './Presets';
|
import Presets from './Presets';
|
||||||
import Info from './Info';
|
import Info from './Info';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
import Vars from './Vars/index';
|
||||||
|
|
||||||
const CollectionSettings = ({ collection }) => {
|
const CollectionSettings = ({ collection }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -77,6 +78,9 @@ const CollectionSettings = ({ collection }) => {
|
|||||||
case 'headers': {
|
case 'headers': {
|
||||||
return <Headers collection={collection} />;
|
return <Headers collection={collection} />;
|
||||||
}
|
}
|
||||||
|
case 'vars': {
|
||||||
|
return <Vars collection={collection} />;
|
||||||
|
}
|
||||||
case 'auth': {
|
case 'auth': {
|
||||||
return <Auth collection={collection} />;
|
return <Auth collection={collection} />;
|
||||||
}
|
}
|
||||||
@ -123,6 +127,9 @@ const CollectionSettings = ({ collection }) => {
|
|||||||
<div className={getTabClassname('headers')} role="tab" onClick={() => setTab('headers')}>
|
<div className={getTabClassname('headers')} role="tab" onClick={() => setTab('headers')}>
|
||||||
Headers
|
Headers
|
||||||
</div>
|
</div>
|
||||||
|
<div className={getTabClassname('vars')} role="tab" onClick={() => setTab('vars')}>
|
||||||
|
Vars
|
||||||
|
</div>
|
||||||
<div className={getTabClassname('auth')} role="tab" onClick={() => setTab('auth')}>
|
<div className={getTabClassname('auth')} role="tab" onClick={() => setTab('auth')}>
|
||||||
Auth
|
Auth
|
||||||
</div>
|
</div>
|
||||||
|
@ -116,6 +116,7 @@ const Headers = ({ collection, folder }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
|
item={folder}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -130,6 +130,7 @@ const VarsTable = ({ folder, collection, vars, varType }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
|
item={folder}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -191,6 +191,7 @@ const AssertionRow = ({
|
|||||||
}
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
|
item={item}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<input type="text" className="cursor-default" disabled />
|
<input type="text" className="cursor-default" disabled />
|
||||||
|
@ -132,6 +132,7 @@ const VarsTable = ({ item, collection, vars, varType }) => {
|
|||||||
}
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
|
item={item}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1302,6 +1302,71 @@ export const collectionsSlice = createSlice({
|
|||||||
set(collection, 'root.request.headers', headers);
|
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) => {
|
collectionAddFileEvent: (state, action) => {
|
||||||
const file = action.payload.file;
|
const file = action.payload.file;
|
||||||
const isCollectionRoot = file.meta.collectionRoot ? true : false;
|
const isCollectionRoot = file.meta.collectionRoot ? true : false;
|
||||||
@ -1694,6 +1759,9 @@ export const {
|
|||||||
addCollectionHeader,
|
addCollectionHeader,
|
||||||
updateCollectionHeader,
|
updateCollectionHeader,
|
||||||
deleteCollectionHeader,
|
deleteCollectionHeader,
|
||||||
|
addCollectionVar,
|
||||||
|
updateCollectionVar,
|
||||||
|
deleteCollectionVar,
|
||||||
updateCollectionAuthMode,
|
updateCollectionAuthMode,
|
||||||
updateCollectionAuth,
|
updateCollectionAuth,
|
||||||
updateCollectionRequestScript,
|
updateCollectionRequestScript,
|
||||||
|
@ -787,24 +787,25 @@ export const getTotalRequestCountInCollection = (collection) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getAllVariables = (collection, item) => {
|
export const getAllVariables = (collection, item) => {
|
||||||
const environmentVariables = getEnvironmentVariables(collection);
|
const envVariables = getEnvironmentVariables(collection);
|
||||||
let requestVariables = {};
|
const requestTreePath = getTreePathFromCollectionToItem(collection, item);
|
||||||
if (item?.request) {
|
let { collectionVariables, folderVariables, requestVariables } = mergeVars(collection, requestTreePath);
|
||||||
const requestTreePath = getTreePathFromCollectionToItem(collection, item);
|
|
||||||
requestVariables = mergeFolderLevelVars(item?.request, requestTreePath);
|
|
||||||
}
|
|
||||||
const pathParams = getPathParams(item);
|
const pathParams = getPathParams(item);
|
||||||
|
|
||||||
|
const { processEnvVariables = {}, runtimeVariables = {} } = collection;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...environmentVariables,
|
...collectionVariables,
|
||||||
|
...envVariables,
|
||||||
|
...folderVariables,
|
||||||
...requestVariables,
|
...requestVariables,
|
||||||
...collection.runtimeVariables,
|
...runtimeVariables,
|
||||||
pathParams: {
|
pathParams: {
|
||||||
...pathParams
|
...pathParams
|
||||||
},
|
},
|
||||||
process: {
|
process: {
|
||||||
env: {
|
env: {
|
||||||
...collection.processEnvVariables
|
...processEnvVariables
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -831,14 +832,22 @@ const getTreePathFromCollectionToItem = (collection, _item) => {
|
|||||||
return path;
|
return path;
|
||||||
};
|
};
|
||||||
|
|
||||||
const mergeFolderLevelVars = (request, requestTreePath = []) => {
|
const mergeVars = (collection, requestTreePath = []) => {
|
||||||
|
let collectionVariables = {};
|
||||||
|
let folderVariables = {};
|
||||||
let requestVariables = {};
|
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) {
|
for (let i of requestTreePath) {
|
||||||
if (i.type === 'folder') {
|
if (i.type === 'folder') {
|
||||||
let vars = get(i, 'root.request.vars.req', []);
|
let vars = get(i, 'root.request.vars.req', []);
|
||||||
vars.forEach((_var) => {
|
vars.forEach((_var) => {
|
||||||
if (_var.enabled) {
|
if (_var.enabled) {
|
||||||
requestVariables[_var.name] = _var.value;
|
folderVariables[_var.name] = _var.value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -850,6 +859,9 @@ const mergeFolderLevelVars = (request, requestTreePath = []) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
return requestVariables;
|
collectionVariables,
|
||||||
|
folderVariables,
|
||||||
|
requestVariables
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
@ -60,20 +60,6 @@ const runSingleRequest = async function (
|
|||||||
request.data = form;
|
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
|
// run pre request script
|
||||||
const requestScriptFile = compact([
|
const requestScriptFile = compact([
|
||||||
get(collectionRoot, 'request.script.req'),
|
get(collectionRoot, 'request.script.req'),
|
||||||
@ -276,7 +262,7 @@ const runSingleRequest = async function (
|
|||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
chalk.green(stripExtension(filename)) +
|
chalk.green(stripExtension(filename)) +
|
||||||
chalk.dim(` (${response.status} ${response.statusText}) - ${responseTime} ms`)
|
chalk.dim(` (${response.status} ${response.statusText}) - ${responseTime} ms`)
|
||||||
);
|
);
|
||||||
|
|
||||||
// run post-response vars
|
// run post-response vars
|
||||||
|
@ -290,10 +290,10 @@ const parseDataFromResponse = (response, disableParsingResponseJson = false) =>
|
|||||||
// Filter out ZWNBSP character
|
// Filter out ZWNBSP character
|
||||||
// https://gist.github.com/antic183/619f42b559b78028d1fe9e7ae8a1352d
|
// https://gist.github.com/antic183/619f42b559b78028d1fe9e7ae8a1352d
|
||||||
data = data.replace(/^\uFEFF/, '');
|
data = data.replace(/^\uFEFF/, '');
|
||||||
if(!disableParsingResponseJson) {
|
if (!disableParsingResponseJson) {
|
||||||
data = JSON.parse(data);
|
data = JSON.parse(data);
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch { }
|
||||||
|
|
||||||
return { data, dataBuffer };
|
return { data, dataBuffer };
|
||||||
};
|
};
|
||||||
@ -319,20 +319,6 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
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
|
// run pre-request script
|
||||||
let scriptResult;
|
let scriptResult;
|
||||||
const requestScript = compact([get(collectionRoot, 'request.script.req'), get(request, 'script.req')]).join(os.EOL);
|
const requestScript = compact([get(collectionRoot, 'request.script.req'), get(request, 'script.req')]).join(os.EOL);
|
||||||
@ -1160,7 +1146,7 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
try {
|
try {
|
||||||
const disposition = contentDispositionParser.parse(contentDisposition);
|
const disposition = contentDispositionParser.parse(contentDisposition);
|
||||||
return disposition && disposition.parameters['filename'];
|
return disposition && disposition.parameters['filename'];
|
||||||
} catch (error) {}
|
} catch (error) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
const getFileNameFromUrlPath = () => {
|
const getFileNameFromUrlPath = () => {
|
||||||
|
@ -12,15 +12,17 @@ const getContentType = (headers = {}) => {
|
|||||||
return contentType;
|
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 || {};
|
const requestVariables = request?.requestVariables || {};
|
||||||
// we clone envVars because we don't want to modify the original object
|
// 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}}
|
// envVars can inturn have values as {{process.env.VAR_NAME}}
|
||||||
// so we need to interpolate envVars first with processEnvVars
|
// so we need to interpolate envVars first with processEnvVars
|
||||||
forOwn(envVars, (value, key) => {
|
forOwn(envVariables, (value, key) => {
|
||||||
envVars[key] = interpolate(value, {
|
envVariables[key] = interpolate(value, {
|
||||||
process: {
|
process: {
|
||||||
env: {
|
env: {
|
||||||
...processEnvVars
|
...processEnvVars
|
||||||
@ -36,7 +38,9 @@ const interpolateVars = (request, envVars = {}, runtimeVariables = {}, processEn
|
|||||||
|
|
||||||
// runtimeVariables take precedence over envVars
|
// runtimeVariables take precedence over envVars
|
||||||
const combinedVars = {
|
const combinedVars = {
|
||||||
...envVars,
|
...collectionVariables,
|
||||||
|
...envVariables,
|
||||||
|
...folderVariables,
|
||||||
...requestVariables,
|
...requestVariables,
|
||||||
...runtimeVariables,
|
...runtimeVariables,
|
||||||
process: {
|
process: {
|
||||||
|
@ -44,73 +44,75 @@ const mergeFolderLevelHeaders = (request, requestTreePath) => {
|
|||||||
request.headers = Array.from(requestHeadersMap, ([name, value]) => ({ name, value, enabled: true }));
|
request.headers = Array.from(requestHeadersMap, ([name, value]) => ({ name, value, enabled: true }));
|
||||||
};
|
};
|
||||||
|
|
||||||
const mergeFolderLevelVars = (request, requestTreePath) => {
|
const mergeVars = (collection, request, requestTreePath) => {
|
||||||
let folderReqVars = new Map();
|
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) {
|
for (let i of requestTreePath) {
|
||||||
if (i.type === 'folder') {
|
if (i.type === 'folder') {
|
||||||
let vars = get(i, 'root.request.vars.req', []);
|
let vars = get(i, 'root.request.vars.req', []);
|
||||||
vars.forEach((_var) => {
|
vars.forEach((_var) => {
|
||||||
if (_var.enabled) {
|
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', []);
|
const vars = i?.draft ? get(i, 'draft.request.vars.req', []) : get(i, 'request.vars.req', []);
|
||||||
vars.forEach((_var) => {
|
vars.forEach((_var) => {
|
||||||
if (_var.enabled) {
|
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 || [];
|
request.collectionVariables = collectionVariables;
|
||||||
let requestReqVarsMap = new Map();
|
request.folderVariables = folderVariables;
|
||||||
for (let _var of requestReqVars) {
|
request.requestVariables = requestVariables;
|
||||||
if (_var.enabled) {
|
|
||||||
requestReqVarsMap.set(_var.name, _var.value);
|
request.vars.req = Array.from(reqVars, ([name, value]) => ({
|
||||||
}
|
|
||||||
}
|
|
||||||
mergedFolderReqVars.forEach((_var) => {
|
|
||||||
requestReqVarsMap.set(_var.name, _var.value);
|
|
||||||
});
|
|
||||||
request.vars.req = Array.from(requestReqVarsMap, ([name, value]) => ({
|
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
type: 'request'
|
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) {
|
for (let i of requestTreePath) {
|
||||||
if (i.type === 'folder') {
|
if (i.type === 'folder') {
|
||||||
let vars = get(i, 'root.request.vars.res', []);
|
let vars = get(i, 'root.request.vars.res', []);
|
||||||
vars.forEach((_var) => {
|
vars.forEach((_var) => {
|
||||||
if (_var.enabled) {
|
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', []);
|
const vars = i?.draft ? get(i, 'draft.request.vars.res', []) : get(i, 'request.vars.res', []);
|
||||||
vars.forEach((_var) => {
|
vars.forEach((_var) => {
|
||||||
if (_var.enabled) {
|
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 || [];
|
request.vars.res = Array.from(resVars, ([name, value]) => ({
|
||||||
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]) => ({
|
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -314,7 +316,7 @@ const prepareRequest = (item, collection) => {
|
|||||||
if (requestTreePath && requestTreePath.length > 0) {
|
if (requestTreePath && requestTreePath.length > 0) {
|
||||||
mergeFolderLevelHeaders(request, requestTreePath);
|
mergeFolderLevelHeaders(request, requestTreePath);
|
||||||
mergeFolderLevelScripts(request, requestTreePath, scriptFlow);
|
mergeFolderLevelScripts(request, requestTreePath, scriptFlow);
|
||||||
mergeFolderLevelVars(request, requestTreePath);
|
mergeVars(collection, request, requestTreePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
each(request.headers, (h) => {
|
each(request.headers, (h) => {
|
||||||
@ -401,6 +403,9 @@ const prepareRequest = (item, collection) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
axiosRequest.vars = request.vars;
|
axiosRequest.vars = request.vars;
|
||||||
|
axiosRequest.collectionVariables = request.collectionVariables;
|
||||||
|
axiosRequest.folderVariables = request.folderVariables;
|
||||||
|
axiosRequest.requestVariables = request.requestVariables;
|
||||||
axiosRequest.assertions = request.assertions;
|
axiosRequest.assertions = request.assertions;
|
||||||
|
|
||||||
return axiosRequest;
|
return axiosRequest;
|
||||||
|
@ -4,10 +4,12 @@ const { interpolate } = require('@usebruno/common');
|
|||||||
const variableNameRegex = /^[\w-.]*$/;
|
const variableNameRegex = /^[\w-.]*$/;
|
||||||
|
|
||||||
class Bru {
|
class Bru {
|
||||||
constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, requestVariables) {
|
constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables) {
|
||||||
this.envVariables = envVariables || {};
|
this.envVariables = envVariables || {};
|
||||||
this.runtimeVariables = runtimeVariables || {};
|
this.runtimeVariables = runtimeVariables || {};
|
||||||
this.processEnvVars = cloneDeep(processEnvVars || {});
|
this.processEnvVars = cloneDeep(processEnvVars || {});
|
||||||
|
this.collectionVariables = collectionVariables || {};
|
||||||
|
this.folderVariables = folderVariables || {};
|
||||||
this.requestVariables = requestVariables || {};
|
this.requestVariables = requestVariables || {};
|
||||||
this.collectionPath = collectionPath;
|
this.collectionPath = collectionPath;
|
||||||
}
|
}
|
||||||
@ -18,7 +20,9 @@ class Bru {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const combinedVars = {
|
const combinedVars = {
|
||||||
|
...this.collectionVariables,
|
||||||
...this.envVariables,
|
...this.envVariables,
|
||||||
|
...this.folderVariables,
|
||||||
...this.requestVariables,
|
...this.requestVariables,
|
||||||
...this.runtimeVariables,
|
...this.runtimeVariables,
|
||||||
process: {
|
process: {
|
||||||
@ -71,7 +75,7 @@ class Bru {
|
|||||||
if (variableNameRegex.test(key) === false) {
|
if (variableNameRegex.test(key) === false) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Variable name: "${key}" contains invalid characters!` +
|
`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) {
|
if (variableNameRegex.test(key) === false) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Variable name: "${key}" contains invalid characters!` +
|
`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];
|
delete this.runtimeVariables[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCollectionVar(key) {
|
||||||
|
return this._interpolate(this.collectionVariables[key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFolderVar(key) {
|
||||||
|
return this._interpolate(this.folderVariables[key]);
|
||||||
|
}
|
||||||
|
|
||||||
getRequestVar(key) {
|
getRequestVar(key) {
|
||||||
return this._interpolate(this.requestVariables[key]);
|
return this._interpolate(this.requestVariables[key]);
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,16 @@ const { interpolate } = require('@usebruno/common');
|
|||||||
|
|
||||||
const interpolateString = (
|
const interpolateString = (
|
||||||
str,
|
str,
|
||||||
{ envVariables = {}, runtimeVariables = {}, processEnvVars = {}, requestVariables = {} }
|
{ envVariables = {}, runtimeVariables = {}, processEnvVars = {}, collectionVariables = {}, folderVariables = {}, requestVariables = {} }
|
||||||
) => {
|
) => {
|
||||||
if (!str || !str.length || typeof str !== 'string') {
|
if (!str || !str.length || typeof str !== 'string') {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
const combinedVars = {
|
const combinedVars = {
|
||||||
|
...collectionVariables,
|
||||||
...envVariables,
|
...envVariables,
|
||||||
|
...folderVariables,
|
||||||
...requestVariables,
|
...requestVariables,
|
||||||
...runtimeVariables,
|
...runtimeVariables,
|
||||||
process: {
|
process: {
|
||||||
|
@ -192,6 +192,8 @@ const evaluateRhsOperand = (rhsOperand, operator, context, runtime) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const interpolationContext = {
|
const interpolationContext = {
|
||||||
|
collectionVariables: context.bru.collectionVariables,
|
||||||
|
folderVariables: context.bru.folderVariables,
|
||||||
requestVariables: context.bru.requestVariables,
|
requestVariables: context.bru.requestVariables,
|
||||||
runtimeVariables: context.bru.runtimeVariables,
|
runtimeVariables: context.bru.runtimeVariables,
|
||||||
envVariables: context.bru.envVariables,
|
envVariables: context.bru.envVariables,
|
||||||
@ -238,13 +240,23 @@ class AssertRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
runAssertions(assertions, request, response, envVariables, runtimeVariables, processEnvVars) {
|
runAssertions(assertions, request, response, envVariables, runtimeVariables, processEnvVars) {
|
||||||
|
const collectionVariables = request?.collectionVariables || {};
|
||||||
|
const folderVariables = request?.folderVariables || {};
|
||||||
const requestVariables = request?.requestVariables || {};
|
const requestVariables = request?.requestVariables || {};
|
||||||
const enabledAssertions = _.filter(assertions, (a) => a.enabled);
|
const enabledAssertions = _.filter(assertions, (a) => a.enabled);
|
||||||
if (!enabledAssertions.length) {
|
if (!enabledAssertions.length) {
|
||||||
return [];
|
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 req = new BrunoRequest(request);
|
||||||
const res = createResponseParser(response);
|
const res = createResponseParser(response);
|
||||||
|
|
||||||
@ -255,7 +267,9 @@ class AssertRuntime {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const context = {
|
const context = {
|
||||||
|
...collectionVariables,
|
||||||
...envVariables,
|
...envVariables,
|
||||||
|
...folderVariables,
|
||||||
...requestVariables,
|
...requestVariables,
|
||||||
...runtimeVariables,
|
...runtimeVariables,
|
||||||
...processEnvVars,
|
...processEnvVars,
|
||||||
|
@ -47,8 +47,10 @@ class ScriptRuntime {
|
|||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig
|
||||||
) {
|
) {
|
||||||
|
const collectionVariables = request?.collectionVariables || {};
|
||||||
|
const folderVariables = request?.folderVariables || {};
|
||||||
const requestVariables = request?.requestVariables || {};
|
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 req = new BrunoRequest(request);
|
||||||
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
||||||
const moduleWhitelist = get(scriptingConfig, 'moduleWhitelist', []);
|
const moduleWhitelist = get(scriptingConfig, 'moduleWhitelist', []);
|
||||||
@ -162,8 +164,10 @@ class ScriptRuntime {
|
|||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig
|
||||||
) {
|
) {
|
||||||
|
const collectionVariables = request?.collectionVariables || {};
|
||||||
|
const folderVariables = request?.folderVariables || {};
|
||||||
const requestVariables = request?.requestVariables || {};
|
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 req = new BrunoRequest(request);
|
||||||
const res = new BrunoResponse(response);
|
const res = new BrunoResponse(response);
|
||||||
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
||||||
|
@ -48,8 +48,10 @@ class TestRuntime {
|
|||||||
processEnvVars,
|
processEnvVars,
|
||||||
scriptingConfig
|
scriptingConfig
|
||||||
) {
|
) {
|
||||||
|
const collectionVariables = request?.collectionVariables || {};
|
||||||
|
const folderVariables = request?.folderVariables || {};
|
||||||
const requestVariables = request?.requestVariables || {};
|
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 req = new BrunoRequest(request);
|
||||||
const res = new BrunoResponse(response);
|
const res = new BrunoResponse(response);
|
||||||
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);
|
||||||
|
@ -1,22 +1,10 @@
|
|||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const Bru = require('../bru');
|
const Bru = require('../bru');
|
||||||
const BrunoRequest = require('../bruno-request');
|
const BrunoRequest = require('../bruno-request');
|
||||||
const { evaluateJsTemplateLiteral, evaluateJsExpression, createResponseParser } = require('../utils');
|
const { evaluateJsExpression, createResponseParser } = require('../utils');
|
||||||
|
|
||||||
const { executeQuickJsVm } = require('../sandbox/quickjs');
|
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) => {
|
const evaluateJsExpressionBasedOnRuntime = (expr, context, runtime, mode) => {
|
||||||
if (runtime === 'quickjs') {
|
if (runtime === 'quickjs') {
|
||||||
return executeQuickJsVm({
|
return executeQuickJsVm({
|
||||||
@ -35,35 +23,6 @@ class VarsRuntime {
|
|||||||
this.mode = props?.mode || 'developer';
|
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) {
|
runPostResponseVars(vars, request, response, envVariables, runtimeVariables, collectionPath, processEnvVars) {
|
||||||
const requestVariables = request?.requestVariables || {};
|
const requestVariables = request?.requestVariables || {};
|
||||||
const enabledVars = _.filter(vars, (v) => v.enabled);
|
const enabledVars = _.filter(vars, (v) => v.enabled);
|
||||||
|
@ -69,6 +69,18 @@ const addBruShimToContext = (vm, bru) => {
|
|||||||
vm.setProp(bruObject, 'getRequestVar', getRequestVar);
|
vm.setProp(bruObject, 'getRequestVar', getRequestVar);
|
||||||
getRequestVar.dispose();
|
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 sleep = vm.newFunction('sleep', (timer) => {
|
||||||
const t = vm.getString(timer);
|
const t = vm.getString(timer);
|
||||||
const promise = vm.newPromise();
|
const promise = vm.newPromise();
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
headers {
|
headers {
|
||||||
check: again
|
check: again
|
||||||
|
token: {{collection_pre_var_token}}
|
||||||
}
|
}
|
||||||
|
|
||||||
auth {
|
auth {
|
||||||
@ -10,6 +11,11 @@ auth:bearer {
|
|||||||
token: {{bearer_auth_token}}
|
token: {{bearer_auth_token}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vars:pre-request {
|
||||||
|
collection_pre_var: collection_pre_var_value
|
||||||
|
collection_pre_var_token: {{request_pre_var_token}}
|
||||||
|
}
|
||||||
|
|
||||||
docs {
|
docs {
|
||||||
# bruno-testbench 🐶
|
# bruno-testbench 🐶
|
||||||
|
|
||||||
|
@ -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 {
|
assert {
|
||||||
req.body.boolean: isBoolean false
|
req.body.boolean: isBoolean false
|
||||||
req.body.number_1: isNumber 1
|
req.body.number_1: isNumber 1
|
||||||
@ -51,35 +41,4 @@ assert {
|
|||||||
req.body.number_3: eq -1
|
req.body.number_3: eq -1
|
||||||
req.body.number_2: isNumber
|
req.body.number_2: isNumber
|
||||||
req.body.number_3: 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');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
meta {
|
||||||
|
name: string interpolation
|
||||||
|
}
|
||||||
|
|
||||||
|
vars:pre-request {
|
||||||
|
folder_pre_var: folder_pre_var_value
|
||||||
|
folder_pre_var_2: {{env.var1}}
|
||||||
|
}
|
@ -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');
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user