mirror of
https://github.com/usebruno/bruno.git
synced 2025-05-05 15:32:58 +00:00
Feat: Standalone Package to convert to Bruno collection(Part 2)
This contains the bulk of the changes apart from renaming files. This is a continuation of #2341. Co-authored-by: lohit <lohit@usebruno.com> Co-authored-by: pooja-bruno <pooja@usebruno.com>
This commit is contained in:
parent
1a6fa7a799
commit
9845363349
147
package-lock.json
generated
147
package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"packages/bruno-electron",
|
||||
"packages/bruno-cli",
|
||||
"packages/bruno-common",
|
||||
"packages/bruno-converters",
|
||||
"packages/bruno-schema",
|
||||
"packages/bruno-query",
|
||||
"packages/bruno-js",
|
||||
@ -6343,6 +6344,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-alias": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz",
|
||||
"integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"rollup": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-commonjs": {
|
||||
"version": "23.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.7.tgz",
|
||||
@ -7937,6 +7956,10 @@
|
||||
"resolved": "packages/bruno-common",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@usebruno/converters": {
|
||||
"resolved": "packages/bruno-converters",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@usebruno/crypto-js": {
|
||||
"version": "3.1.9",
|
||||
"resolved": "https://registry.npmjs.org/@usebruno/crypto-js/-/crypto-js-3.1.9.tgz",
|
||||
@ -26274,6 +26297,130 @@
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
},
|
||||
"packages/bruno-converters": {
|
||||
"name": "@usebruno/converters",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@usebruno/schema": "^0.7.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"nanoid": "3.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/preset-env": "^7.25.4",
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-commonjs": "^23.0.2",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-typescript": "^9.0.2",
|
||||
"babel-jest": "^29.7.0",
|
||||
"rimraf": "^5.0.7",
|
||||
"rollup": "3.2.5",
|
||||
"rollup-plugin-dts": "^5.0.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"typescript": "^4.8.4"
|
||||
}
|
||||
},
|
||||
"packages/bruno-converters/node_modules/glob": {
|
||||
"version": "10.4.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
|
||||
"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"foreground-child": "^3.1.0",
|
||||
"jackspeak": "^3.1.2",
|
||||
"minimatch": "^9.0.4",
|
||||
"minipass": "^7.1.2",
|
||||
"package-json-from-dist": "^1.0.0",
|
||||
"path-scurry": "^1.11.1"
|
||||
},
|
||||
"bin": {
|
||||
"glob": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"packages/bruno-converters/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"packages/bruno-converters/node_modules/minipass": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
|
||||
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
}
|
||||
},
|
||||
"packages/bruno-converters/node_modules/nanoid": {
|
||||
"version": "3.3.8",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
|
||||
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"packages/bruno-converters/node_modules/rimraf": {
|
||||
"version": "5.0.10",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||
"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"glob": "^10.3.7"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"packages/bruno-converters/node_modules/rollup": {
|
||||
"version": "3.2.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.2.5.tgz",
|
||||
"integrity": "sha512-/Ha7HhVVofduy+RKWOQJrxe4Qb3xyZo+chcpYiD8SoQa4AG7llhupUtyfKSSrdBM2mWJjhM8wZwmbY23NmlIYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"packages/bruno-electron": {
|
||||
"name": "bruno",
|
||||
"version": "2.0.0",
|
||||
|
@ -6,6 +6,7 @@
|
||||
"packages/bruno-electron",
|
||||
"packages/bruno-cli",
|
||||
"packages/bruno-common",
|
||||
"packages/bruno-converters",
|
||||
"packages/bruno-schema",
|
||||
"packages/bruno-query",
|
||||
"packages/bruno-js",
|
||||
@ -38,6 +39,7 @@
|
||||
"dev:electron": "npm run dev --workspace=packages/bruno-electron",
|
||||
"dev:electron:debug": "npm run debug --workspace=packages/bruno-electron",
|
||||
"build:bruno-common": "npm run build --workspace=packages/bruno-common",
|
||||
"build:bruno-converters": "npm run build --workspace=packages/bruno-converters",
|
||||
"build:bruno-query": "npm run build --workspace=packages/bruno-query",
|
||||
"build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs",
|
||||
"build:electron": "node ./scripts/build-electron.js",
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React from 'react';
|
||||
import exportBrunoCollection from 'utils/collections/export';
|
||||
import exportPostmanCollection from 'utils/exporters/postman-collection';
|
||||
import { toastError } from 'utils/common/error';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import Modal from 'components/Modal';
|
||||
import { transformCollectionToSaveToExportAsFile } from 'utils/collections/index';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import importBrunoCollection from 'utils/importers/bruno-collection';
|
||||
import importPostmanCollection from 'utils/importers/postman-collection';
|
||||
import importInsomniaCollection from 'utils/importers/insomnia-collection';
|
||||
@ -7,14 +7,6 @@ import { toastError } from 'utils/common/error';
|
||||
import Modal from 'components/Modal';
|
||||
|
||||
const ImportCollection = ({ onClose, handleSubmit }) => {
|
||||
const [options, setOptions] = useState({
|
||||
enablePostmanTranslations: {
|
||||
enabled: true,
|
||||
label: 'Auto translate postman scripts',
|
||||
subLabel:
|
||||
"When enabled, Bruno will try as best to translate the scripts from the imported collection to Bruno's format."
|
||||
}
|
||||
});
|
||||
const handleImportBrunoCollection = () => {
|
||||
importBrunoCollection()
|
||||
.then(({ collection }) => {
|
||||
@ -24,9 +16,9 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
|
||||
};
|
||||
|
||||
const handleImportPostmanCollection = () => {
|
||||
importPostmanCollection(options)
|
||||
.then(({ collection, translationLog }) => {
|
||||
handleSubmit({ collection, translationLog });
|
||||
importPostmanCollection()
|
||||
.then(({ collection }) => {
|
||||
handleSubmit({ collection });
|
||||
})
|
||||
.catch((err) => toastError(err, 'Postman Import collection failed'));
|
||||
};
|
||||
@ -46,15 +38,6 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
|
||||
})
|
||||
.catch((err) => toastError(err, 'OpenAPI v3 Import collection failed'));
|
||||
};
|
||||
const toggleOptions = (event, optionKey) => {
|
||||
setOptions({
|
||||
...options,
|
||||
[optionKey]: {
|
||||
...options[optionKey],
|
||||
enabled: !options[optionKey].enabled
|
||||
}
|
||||
});
|
||||
};
|
||||
const CollectionButton = ({ children, className, onClick }) => {
|
||||
return (
|
||||
<button
|
||||
@ -77,31 +60,6 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
|
||||
<CollectionButton onClick={handleImportInsomniaCollection}>Insomnia Collection</CollectionButton>
|
||||
<CollectionButton onClick={handleImportOpenapiCollection}>OpenAPI V3 Spec</CollectionButton>
|
||||
</div>
|
||||
<div className="flex justify-start w-full mt-4 max-w-[450px]">
|
||||
{Object.entries(options || {}).map(([key, option]) => (
|
||||
<div key={key} className="relative flex items-start">
|
||||
<div className="flex h-6 items-center">
|
||||
<input
|
||||
id="comments"
|
||||
aria-describedby="comments-description"
|
||||
name="comments"
|
||||
type="checkbox"
|
||||
checked={option.enabled}
|
||||
onChange={(e) => toggleOptions(e, key)}
|
||||
className="h-3.5 w-3.5 rounded border-zinc-300 dark:ring-offset-zinc-800 bg-transparent text-indigo-600 dark:text-indigo-500 focus:ring-indigo-600 dark:focus:ring-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="ml-2 text-sm leading-6">
|
||||
<label htmlFor="comments" className="font-medium text-gray-900 dark:text-zinc-50">
|
||||
{option.label}
|
||||
</label>
|
||||
<p id="comments-description" className="text-zinc-500 text-xs dark:text-zinc-400">
|
||||
{option.subLabel}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
@ -4,105 +4,8 @@ import { useFormik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions';
|
||||
import Modal from 'components/Modal';
|
||||
import { IconAlertTriangle, IconArrowRight, IconCaretDown, IconCaretRight, IconCopy } from '@tabler/icons';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
const TranslationLog = ({ translationLog }) => {
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
const preventSetShowDetails = (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
setShowDetails(!showDetails);
|
||||
};
|
||||
const copyClipboard = (e, value) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
navigator.clipboard.writeText(value);
|
||||
toast.success('Copied to clipboard');
|
||||
};
|
||||
return (
|
||||
<div className="flex flex-col mt-2">
|
||||
<div className="border-l-2 border-amber-500 dark:border-amber-300 bg-amber-50 dark:bg-amber-50/10 p-1.5 rounded-r">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0">
|
||||
<IconAlertTriangle className="h-4 w-4 text-amber-500 dark:text-amber-300" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-2">
|
||||
<p className="text-xs text-amber-700 dark:text-amber-300">
|
||||
<span className="font-semibold">Warning:</span> Some commands were not translated.{' '}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={(e) => preventSetShowDetails(e)}
|
||||
className="flex w-fit items-center rounded px-2.5 py-1 mt-2 text-xs font-semibold ring-1 ring-inset bg-slate-50 dark:bg-slate-400/10 text-slate-700 dark:text-slate-300 ring-slate-600/10 dark:ring-slate-400/20"
|
||||
>
|
||||
See details
|
||||
{showDetails ? <IconCaretDown size={16} className="ml-1" /> : <IconCaretRight size={16} className="ml-1" />}
|
||||
</button>
|
||||
{showDetails && (
|
||||
<div className="flex relative flex-col text-xs max-w-[364px] max-h-[300px] overflow-scroll mt-2 p-2 bg-slate-50 dark:bg-slate-400/10 ring-1 ring-inset rounded text-slate-700 dark:text-slate-300 ring-slate-600/20 dark:ring-slate-400/20">
|
||||
<span className="font-semibold flex items-center">
|
||||
Impacted Collections: {Object.keys(translationLog || {}).length}
|
||||
</span>
|
||||
<span className="font-semibold flex items-center">
|
||||
Impacted Lines:{' '}
|
||||
{Object.values(translationLog || {}).reduce(
|
||||
(acc, curr) => acc + (curr.script?.length || 0) + (curr.test?.length || 0),
|
||||
0
|
||||
)}
|
||||
</span>
|
||||
<span className="my-1">
|
||||
The numbers after 'script' and 'test' indicate the line numbers of incomplete translations.
|
||||
</span>
|
||||
<ul>
|
||||
{Object.entries(translationLog || {}).map(([name, value]) => (
|
||||
<li key={name} className="list-none text-xs font-semibold">
|
||||
<div className="font-semibold flex items-center text-xs whitespace-nowrap">
|
||||
<IconCaretRight className="min-w-4 max-w-4 -ml-1" />
|
||||
{name}
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
{value.script && (
|
||||
<div className="flex items-center text-xs font-light mb-1 flex-wrap">
|
||||
<span className="mr-2">script :</span>
|
||||
{value.script.map((scriptValue, index) => (
|
||||
<span className="flex items-center" key={`script_${name}_${index}`}>
|
||||
<span className="text-xs font-light">{scriptValue}</span>
|
||||
{index < value.script.length - 1 && <> - </>}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{value.test && (
|
||||
<div className="flex items-center text-xs font-light mb-1 flex-wrap">
|
||||
<span className="mr-2">test :</span>
|
||||
{value.test.map((testValue, index) => (
|
||||
<div className="flex items-center" key={`test_${name}_${index}`}>
|
||||
<span className="text-xs font-light">{testValue}</span>
|
||||
{index < value.test.length - 1 && <> - </>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<button
|
||||
className="absolute top-1 right-1 flex w-fit items-center rounded p-2 text-xs font-semibold ring-1 ring-inset bg-slate-50 dark:bg-slate-400/10 text-slate-700 dark:text-slate-300 ring-slate-600/10 dark:ring-slate-400/20"
|
||||
onClick={(e) => copyClipboard(e, JSON.stringify(translationLog))}
|
||||
>
|
||||
<IconCopy size={16} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName, translationLog }) => {
|
||||
const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) => {
|
||||
const inputRef = useRef();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
@ -150,9 +53,6 @@ const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName, trans
|
||||
Name
|
||||
</label>
|
||||
<div className="mt-2">{collectionName}</div>
|
||||
{translationLog && Object.keys(translationLog).length > 0 && (
|
||||
<TranslationLog translationLog={translationLog} />
|
||||
)}
|
||||
<>
|
||||
<label htmlFor="collectionLocation" className="block font-semibold mt-3">
|
||||
Location
|
||||
|
@ -14,18 +14,14 @@ import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const TitleBar = () => {
|
||||
const [importedCollection, setImportedCollection] = useState(null);
|
||||
const [importedTranslationLog, setImportedTranslationLog] = useState({});
|
||||
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
||||
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
||||
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
|
||||
const dispatch = useDispatch();
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
const handleImportCollection = ({ collection, translationLog }) => {
|
||||
const handleImportCollection = ({ collection }) => {
|
||||
setImportedCollection(collection);
|
||||
if (translationLog) {
|
||||
setImportedTranslationLog(translationLog);
|
||||
}
|
||||
setImportCollectionModalOpen(false);
|
||||
setImportCollectionLocationModalOpen(true);
|
||||
};
|
||||
@ -75,7 +71,6 @@ const TitleBar = () => {
|
||||
{importCollectionLocationModalOpen ? (
|
||||
<ImportCollectionLocation
|
||||
collectionName={importedCollection.name}
|
||||
translationLog={importedTranslationLog}
|
||||
onClose={() => setImportCollectionLocationModalOpen(false)}
|
||||
handleSubmit={handleImportCollectionLocation}
|
||||
/>
|
||||
|
@ -15,7 +15,6 @@ const Welcome = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
const [importedCollection, setImportedCollection] = useState(null);
|
||||
const [importedTranslationLog, setImportedTranslationLog] = useState({});
|
||||
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
||||
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
||||
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
|
||||
@ -24,11 +23,8 @@ const Welcome = () => {
|
||||
dispatch(openCollection()).catch((err) => console.log(err) && toast.error(t('WELCOME.COLLECTION_OPEN_ERROR')));
|
||||
};
|
||||
|
||||
const handleImportCollection = ({ collection, translationLog }) => {
|
||||
const handleImportCollection = ({ collection }) => {
|
||||
setImportedCollection(collection);
|
||||
if (translationLog) {
|
||||
setImportedTranslationLog(translationLog);
|
||||
}
|
||||
setImportCollectionModalOpen(false);
|
||||
setImportCollectionLocationModalOpen(true);
|
||||
};
|
||||
@ -55,7 +51,6 @@ const Welcome = () => {
|
||||
) : null}
|
||||
{importCollectionLocationModalOpen ? (
|
||||
<ImportCollectionLocation
|
||||
translationLog={importedTranslationLog}
|
||||
collectionName={importedCollection.name}
|
||||
onClose={() => setImportCollectionLocationModalOpen(false)}
|
||||
handleSubmit={handleImportCollectionLocation}
|
||||
|
15
packages/bruno-app/src/utils/exporters/postman-collection.js
Normal file
15
packages/bruno-app/src/utils/exporters/postman-collection.js
Normal file
@ -0,0 +1,15 @@
|
||||
import * as FileSaver from 'file-saver';
|
||||
import brunoConverters from '@usebruno/converters';
|
||||
const { brunoToPostman } = brunoConverters;
|
||||
|
||||
export const exportCollection = (collection) => {
|
||||
|
||||
const collectionToExport = brunoToPostman(collection);
|
||||
|
||||
const fileName = `${collection.name}.json`;
|
||||
const fileBlob = new Blob([JSON.stringify(collectionToExport, null, 2)], { type: 'application/json' });
|
||||
|
||||
FileSaver.saveAs(fileBlob, fileName);
|
||||
};
|
||||
|
||||
export default exportCollection;
|
119
packages/bruno-app/src/utils/importers/common.js
Normal file
119
packages/bruno-app/src/utils/importers/common.js
Normal file
@ -0,0 +1,119 @@
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { uuid } from 'utils/common';
|
||||
import { isItemARequest } from 'utils/collections';
|
||||
import { collectionSchema } from '@usebruno/schema';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
|
||||
export const validateSchema = (collection = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
collectionSchema
|
||||
.validate(collection)
|
||||
.then(() => resolve(collection))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('The Collection file is corrupted'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const updateUidsInCollection = (_collection) => {
|
||||
const collection = cloneDeep(_collection);
|
||||
|
||||
collection.uid = uuid();
|
||||
|
||||
const updateItemUids = (items = []) => {
|
||||
each(items, (item) => {
|
||||
item.uid = uuid();
|
||||
|
||||
each(get(item, 'request.headers'), (header) => (header.uid = uuid()));
|
||||
each(get(item, 'request.params'), (param) => (param.uid = uuid()));
|
||||
each(get(item, 'request.vars.req'), (v) => (v.uid = uuid()));
|
||||
each(get(item, 'request.vars.res'), (v) => (v.uid = uuid()));
|
||||
each(get(item, 'request.assertions'), (a) => (a.uid = uuid()));
|
||||
each(get(item, 'request.body.multipartForm'), (param) => (param.uid = uuid()));
|
||||
each(get(item, 'request.body.formUrlEncoded'), (param) => (param.uid = uuid()));
|
||||
each(get(item, 'request.body.file'), (param) => (param.uid = uuid()));
|
||||
|
||||
if (item.items && item.items.length) {
|
||||
updateItemUids(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
updateItemUids(collection.items);
|
||||
|
||||
const updateEnvUids = (envs = []) => {
|
||||
each(envs, (env) => {
|
||||
env.uid = uuid();
|
||||
each(env.variables, (variable) => (variable.uid = uuid()));
|
||||
});
|
||||
};
|
||||
updateEnvUids(collection.environments);
|
||||
|
||||
return collection;
|
||||
};
|
||||
|
||||
// todo
|
||||
// need to eventually get rid of supporting old collection app models
|
||||
// 1. start with making request type a constant fetched from a single place
|
||||
// 2. move references of param and replace it with query inside the app
|
||||
export const transformItemsInCollection = (collection) => {
|
||||
const transformItems = (items = []) => {
|
||||
each(items, (item) => {
|
||||
|
||||
if (['http', 'graphql'].includes(item.type)) {
|
||||
item.type = `${item.type}-request`;
|
||||
|
||||
if (item.request.query) {
|
||||
item.request.params = item.request.query.map((queryItem) => ({
|
||||
...queryItem,
|
||||
type: 'query',
|
||||
uid: queryItem.uid || uuid()
|
||||
}));
|
||||
}
|
||||
|
||||
delete item.request.query;
|
||||
|
||||
// from 5 feb 2024, multipartFormData needs to have a type
|
||||
// this was introduced when we added support for file uploads
|
||||
// below logic is to make older collection exports backward compatible
|
||||
let multipartFormData = get(item, 'request.body.multipartForm');
|
||||
if (multipartFormData) {
|
||||
each(multipartFormData, (form) => {
|
||||
if (!form.type) {
|
||||
form.type = 'text';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (item.items && item.items.length) {
|
||||
transformItems(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
transformItems(collection.items);
|
||||
|
||||
return collection;
|
||||
};
|
||||
|
||||
export const hydrateSeqInCollection = (collection) => {
|
||||
const hydrateSeq = (items = []) => {
|
||||
let index = 1;
|
||||
each(items, (item) => {
|
||||
if (isItemARequest(item) && !item.seq) {
|
||||
item.seq = index;
|
||||
index++;
|
||||
}
|
||||
if (item.items && item.items.length) {
|
||||
hydrateSeq(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
hydrateSeq(collection.items);
|
||||
|
||||
return collection;
|
||||
};
|
@ -0,0 +1,44 @@
|
||||
import jsyaml from 'js-yaml';
|
||||
import fileDialog from 'file-dialog';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import brunoConverters from '@usebruno/converters';
|
||||
const { insomniaToBruno } = brunoConverters;
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => {
|
||||
try {
|
||||
// try to load JSON
|
||||
const parsedData = JSON.parse(e.target.result);
|
||||
resolve(parsedData);
|
||||
} catch (jsonError) {
|
||||
// not a valid JSOn, try yaml
|
||||
try {
|
||||
const parsedData = jsyaml.load(e.target.result, { schema: jsyaml.CORE_SCHEMA });
|
||||
resolve(parsedData);
|
||||
} catch (yamlError) {
|
||||
console.error('Error parsing the file :', jsonError, yamlError);
|
||||
reject(new BrunoError('Import collection failed'));
|
||||
}
|
||||
}
|
||||
};
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
|
||||
const importCollection = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: '.json, .yaml, .yml, application/json, application/yaml, application/x-yaml' })
|
||||
.then(readFile)
|
||||
.then((collection) => insomniaToBruno(collection))
|
||||
.then((collection) => resolve({ collection }))
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
reject(new BrunoError('Import collection failed: ' + err.message));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default importCollection;
|
44
packages/bruno-app/src/utils/importers/openapi-collection.js
Normal file
44
packages/bruno-app/src/utils/importers/openapi-collection.js
Normal file
@ -0,0 +1,44 @@
|
||||
import jsyaml from 'js-yaml';
|
||||
import fileDialog from 'file-dialog';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import brunoConverters from '@usebruno/converters';
|
||||
const { openApiToBruno } = brunoConverters;
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => {
|
||||
try {
|
||||
// try to load JSON
|
||||
const parsedData = JSON.parse(e.target.result);
|
||||
resolve(parsedData);
|
||||
} catch (jsonError) {
|
||||
// not a valid JSOn, try yaml
|
||||
try {
|
||||
const parsedData = jsyaml.load(e.target.result);
|
||||
resolve(parsedData);
|
||||
} catch (yamlError) {
|
||||
console.error('Error parsing the file :', jsonError, yamlError);
|
||||
reject(new BrunoError('Import collection failed'));
|
||||
}
|
||||
}
|
||||
};
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
|
||||
const importCollection = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: '.json, .yaml, .yml, application/json, application/yaml, application/x-yaml' })
|
||||
.then(readFile)
|
||||
.then((collection) => openApiToBruno(collection))
|
||||
.then((collection) => resolve({ collection }))
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
reject(new BrunoError('Import collection failed: ' + err.message));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default importCollection;
|
@ -1,67 +0,0 @@
|
||||
import { parseOpenApiCollection } from './openapi-collection';
|
||||
import { uuid } from 'utils/common';
|
||||
|
||||
jest.mock('utils/common');
|
||||
|
||||
describe('openapi importer util functions', () => {
|
||||
afterEach(jest.clearAllMocks);
|
||||
|
||||
it('should convert openapi object to bruno collection correctly', async () => {
|
||||
const input = {
|
||||
openapi: '3.0.3',
|
||||
info: {
|
||||
title: 'Sample API with Multiple Servers',
|
||||
description: 'API spec with multiple servers.',
|
||||
version: '1.0.0'
|
||||
},
|
||||
servers: [
|
||||
{ url: 'https://api.example.com/v1', description: 'Production Server' },
|
||||
{ url: 'https://staging-api.example.com/v1', description: 'Staging Server' },
|
||||
{ url: 'http://localhost:3000/v1', description: 'Local Server' }
|
||||
],
|
||||
paths: {
|
||||
'/users': {
|
||||
get: {
|
||||
summary: 'Get a list of users',
|
||||
parameters: [
|
||||
{ name: 'page', in: 'query', required: false, schema: { type: 'integer' } },
|
||||
{ name: 'limit', in: 'query', required: false, schema: { type: 'integer' } }
|
||||
],
|
||||
responses: {
|
||||
'200': { description: 'A list of users' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const expectedOutput = {
|
||||
name: 'Sample API with Multiple Servers',
|
||||
version: '1',
|
||||
items: [
|
||||
{
|
||||
name: 'Get a list of users',
|
||||
type: 'http-request',
|
||||
request: {
|
||||
url: '{{baseUrl}}/users',
|
||||
method: 'GET',
|
||||
params: [
|
||||
{ name: 'page', value: '', enabled: false, type: 'query' },
|
||||
{ name: 'limit', value: '', enabled: false, type: 'query' }
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
environments: [
|
||||
{ name: 'Production Server', variables: [{ name: 'baseUrl', value: 'https://api.example.com/v1' }] },
|
||||
{ name: 'Staging Server', variables: [{ name: 'baseUrl', value: 'https://staging-api.example.com/v1' }] },
|
||||
{ name: 'Local Server', variables: [{ name: 'baseUrl', value: 'http://localhost:3000/v1' }] }
|
||||
]
|
||||
};
|
||||
|
||||
const result = await parseOpenApiCollection(input);
|
||||
|
||||
expect(result).toMatchObject(expectedOutput);
|
||||
expect(uuid).toHaveBeenCalledTimes(10);
|
||||
});
|
||||
});
|
30
packages/bruno-app/src/utils/importers/postman-collection.js
Normal file
30
packages/bruno-app/src/utils/importers/postman-collection.js
Normal file
@ -0,0 +1,30 @@
|
||||
import fileDialog from 'file-dialog';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import brunoConverters from '@usebruno/converters';
|
||||
import { safeParseJSON } from 'utils/common/index';
|
||||
const { postmanToBruno } = brunoConverters;
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => resolve(safeParseJSON(e.target.result));
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const importCollection = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: 'application/json' })
|
||||
.then(readFile)
|
||||
.then((collection) => postmanToBruno(collection))
|
||||
.then(({ collection }) => resolve({ collection }))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('Import collection failed'));
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export default importCollection;
|
@ -0,0 +1,38 @@
|
||||
import fileDialog from 'file-dialog';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import brunoConverters from '@usebruno/converters';
|
||||
const { postmanToBrunoEnvironment } = brunoConverters;
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => resolve(e.target.result);
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
|
||||
const importEnvironment = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ multiple: true, accept: 'application/json' })
|
||||
.then((files) => {
|
||||
return Promise.all(
|
||||
Object.values(files ?? {}).map((file) =>
|
||||
readFile([file])
|
||||
.then((environment) => postmanToBrunoEnvironment(environment))
|
||||
.catch((err) => {
|
||||
console.error(`Error processing file: ${file.name || 'undefined'}`, err);
|
||||
throw err;
|
||||
})
|
||||
)
|
||||
);
|
||||
})
|
||||
.then((environments) => resolve(environments))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('Import Environment failed'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default importEnvironment;
|
22
packages/bruno-converters/.gitignore
vendored
Normal file
22
packages/bruno-converters/.gitignore
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
# dependencies
|
||||
node_modules
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
coverage
|
||||
|
||||
# production
|
||||
dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
3
packages/bruno-converters/babel.config.js
Normal file
3
packages/bruno-converters/babel.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: [['@babel/preset-env', { targets: { node: 'current' } }]],
|
||||
};
|
13
packages/bruno-converters/jest.config.js
Normal file
13
packages/bruno-converters/jest.config.js
Normal file
@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
transform: {
|
||||
'^.+\\.js$': 'babel-jest',
|
||||
},
|
||||
setupFiles: ['<rootDir>/jest.setup.js'],
|
||||
transformIgnorePatterns: [
|
||||
'node_modules/(?!(nanoid)/)'
|
||||
],
|
||||
testEnvironment: 'node',
|
||||
moduleNameMapper: {
|
||||
'^nanoid(/(.*)|$)': 'nanoid$1'
|
||||
}
|
||||
};
|
11
packages/bruno-converters/jest.setup.js
Normal file
11
packages/bruno-converters/jest.setup.js
Normal file
@ -0,0 +1,11 @@
|
||||
// Mock the uuid function
|
||||
jest.mock('./src/common', () => {
|
||||
// Import the original module to keep other functions intact
|
||||
const originalModule = jest.requireActual('./src/common');
|
||||
|
||||
return {
|
||||
__esModule: true, // Use this property to indicate it's an ES module
|
||||
...originalModule,
|
||||
uuid: jest.fn(() => 'mockeduuidvalue123456'), // Mock uuid to return a fixed value
|
||||
};
|
||||
});
|
21
packages/bruno-converters/license.md
Normal file
21
packages/bruno-converters/license.md
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Anoop M D, Anusree P S and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
45
packages/bruno-converters/package.json
Normal file
45
packages/bruno-converters/package.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@usebruno/converters",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"main": "dist/cjs/index.js",
|
||||
"module": "dist/esm/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
"package.json"
|
||||
],
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"test": "node --experimental-vm-modules $(npx which jest) --colors --collectCoverage",
|
||||
"prebuild": "npm run clean",
|
||||
"build": "rollup -c",
|
||||
"watch": "rollup -c -w",
|
||||
"prepack": "npm run test && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@usebruno/schema": "^0.7.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"nanoid": "3.3.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/preset-env": "^7.25.4",
|
||||
"@rollup/plugin-alias": "^5.1.0",
|
||||
"@rollup/plugin-commonjs": "^23.0.2",
|
||||
"@rollup/plugin-node-resolve": "^15.0.1",
|
||||
"@rollup/plugin-typescript": "^9.0.2",
|
||||
"babel-jest": "^29.7.0",
|
||||
"rimraf": "^5.0.7",
|
||||
"rollup": "3.2.5",
|
||||
"rollup-plugin-dts": "^5.0.0",
|
||||
"rollup-plugin-peer-deps-external": "^2.2.4",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"overrides": {
|
||||
"rollup": "3.2.5"
|
||||
}
|
||||
}
|
45
packages/bruno-converters/readme.md
Normal file
45
packages/bruno-converters/readme.md
Normal file
@ -0,0 +1,45 @@
|
||||
# bruno-converters
|
||||
|
||||
The converters package is responsible for converting collections from one format to a Bruno collection.
|
||||
It can be used as a standalone package or as a part of the Bruno framework.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @usebruno/converters
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Convert Postman collection to Bruno collection
|
||||
|
||||
```javascript
|
||||
const { postmanToBruno } = require('@usebruno/converters');
|
||||
|
||||
// Convert Postman collection to Bruno collection
|
||||
const brunoCollection = postmanToBruno(postmanCollection);
|
||||
```
|
||||
|
||||
### Convert Postman Environment to Bruno Environment
|
||||
|
||||
```javascript
|
||||
const { postmanToBrunoEnvironment } = require('@usebruno/converters');
|
||||
|
||||
const brunoEnvironment = postmanToBrunoEnvironment(postmanEnvironment);
|
||||
```
|
||||
|
||||
### Convert Insomnia collection to Bruno collection
|
||||
|
||||
```javascript
|
||||
import { insomniaToBruno } from '@usebruno/converters';
|
||||
|
||||
const brunoCollection = insomniaToBruno(insomniaCollection);
|
||||
```
|
||||
|
||||
### Convert OpenAPI specification to Bruno collection
|
||||
|
||||
```javascript
|
||||
import { openApiToBruno } from '@usebruno/converters';
|
||||
|
||||
const brunoCollection = openApiToBruno(openApiSpecification);
|
||||
```
|
38
packages/bruno-converters/rollup.config.js
Normal file
38
packages/bruno-converters/rollup.config.js
Normal file
@ -0,0 +1,38 @@
|
||||
const { nodeResolve } = require('@rollup/plugin-node-resolve');
|
||||
const commonjs = require('@rollup/plugin-commonjs');
|
||||
const { terser } = require('rollup-plugin-terser');
|
||||
const peerDepsExternal = require('rollup-plugin-peer-deps-external');
|
||||
|
||||
const packageJson = require('./package.json');
|
||||
const alias = require('@rollup/plugin-alias');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
input: 'src/index.js',
|
||||
output: [
|
||||
{
|
||||
file: packageJson.main,
|
||||
format: 'cjs',
|
||||
sourcemap: true
|
||||
},
|
||||
{
|
||||
file: packageJson.module,
|
||||
format: 'esm',
|
||||
sourcemap: true
|
||||
}
|
||||
],
|
||||
plugins: [
|
||||
peerDepsExternal(),
|
||||
nodeResolve({
|
||||
preferBuiltins: true,
|
||||
extensions: ['.js', '.css'] // Resolve .js files
|
||||
}),
|
||||
commonjs(),
|
||||
terser(),
|
||||
alias({
|
||||
entries: [{ find: 'src', replacement: path.resolve(__dirname, 'src') }]
|
||||
})
|
||||
]
|
||||
}
|
||||
];
|
@ -1,22 +1,54 @@
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import { customAlphabet } from 'nanoid';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { uuid, normalizeFileName } from 'utils/common';
|
||||
import { isItemARequest } from 'utils/collections';
|
||||
import { collectionSchema } from '@usebruno/schema';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
|
||||
export const safeParseJSON = (str) => {
|
||||
if (!str || !str.length || typeof str !== 'string') {
|
||||
return str;
|
||||
}
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch (e) {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
export const safeStringifyJSON = (obj, indent = false) => {
|
||||
if (obj === undefined) {
|
||||
return obj;
|
||||
}
|
||||
try {
|
||||
if (indent) {
|
||||
return JSON.stringify(obj, null, 2);
|
||||
}
|
||||
return JSON.stringify(obj);
|
||||
} catch (e) {
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
export const isItemARequest = (item) => {
|
||||
return item.hasOwnProperty('request') && ['http-request', 'graphql-request'].includes(item.type) && !item.items;
|
||||
};
|
||||
|
||||
// a customized version of nanoid without using _ and -
|
||||
export const uuid = () => {
|
||||
// https://github.com/ai/nanoid/blob/main/url-alphabet/index.js
|
||||
const urlAlphabet = 'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict';
|
||||
const customNanoId = customAlphabet(urlAlphabet, 21);
|
||||
|
||||
return customNanoId();
|
||||
};
|
||||
|
||||
export const validateSchema = (collection = {}) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
collectionSchema
|
||||
.validate(collection)
|
||||
.then(() => resolve(collection))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('The Collection file is corrupted'));
|
||||
});
|
||||
});
|
||||
try {
|
||||
collectionSchema.validateSync(collection);
|
||||
return collection;
|
||||
} catch (err) {
|
||||
throw new Error('The Collection has an invalid schema');
|
||||
}
|
||||
};
|
||||
|
||||
export const updateUidsInCollection = (_collection) => {
|
||||
@ -117,3 +149,63 @@ export const hydrateSeqInCollection = (collection) => {
|
||||
|
||||
return collection;
|
||||
};
|
||||
|
||||
export const deleteUidsInItems = (items) => {
|
||||
each(items, (item) => {
|
||||
delete item.uid;
|
||||
|
||||
if (['http-request', 'graphql-request'].includes(item.type)) {
|
||||
each(get(item, 'request.headers'), (header) => delete header.uid);
|
||||
each(get(item, 'request.params'), (param) => delete param.uid);
|
||||
each(get(item, 'request.vars.req'), (v) => delete v.uid);
|
||||
each(get(item, 'request.vars.res'), (v) => delete v.uid);
|
||||
each(get(item, 'request.vars.assertions'), (a) => delete a.uid);
|
||||
each(get(item, 'request.body.multipartForm'), (param) => delete param.uid);
|
||||
each(get(item, 'request.body.formUrlEncoded'), (param) => delete param.uid);
|
||||
each(get(item, 'request.body.file'), (param) => delete param.uid);
|
||||
}
|
||||
|
||||
if (item.items && item.items.length) {
|
||||
deleteUidsInItems(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Some of the models in the app are not consistent with the Collection Json format
|
||||
* This function is used to transform the models to the Collection Json format
|
||||
*/
|
||||
export const transformItem = (items = []) => {
|
||||
each(items, (item) => {
|
||||
if (['http-request', 'graphql-request'].includes(item.type)) {
|
||||
if (item.type === 'graphql-request') {
|
||||
item.type = 'graphql';
|
||||
}
|
||||
|
||||
if (item.type === 'http-request') {
|
||||
item.type = 'http';
|
||||
}
|
||||
}
|
||||
|
||||
if (item.items && item.items.length) {
|
||||
transformItem(item.items);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteUidsInEnvs = (envs) => {
|
||||
each(envs, (env) => {
|
||||
delete env.uid;
|
||||
each(env.variables, (variable) => delete variable.uid);
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteSecretsInEnvs = (envs) => {
|
||||
each(envs, (env) => {
|
||||
each(env.variables, (variable) => {
|
||||
if (variable.secret) {
|
||||
variable.value = '';
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
16
packages/bruno-converters/src/index.js
Normal file
16
packages/bruno-converters/src/index.js
Normal file
@ -0,0 +1,16 @@
|
||||
import postmanToBruno from './postman/postman-to-bruno.js';
|
||||
import postmanToBrunoEnvironment from './postman/postman-env-to-bruno-env.js';
|
||||
|
||||
import brunoToPostman from './postman/bruno-to-postman.js';
|
||||
|
||||
import openApiToBruno from './openapi/openapi-to-bruno.js';
|
||||
|
||||
import insomniaToBruno from './insomnia/insomnia-to-bruno.js';
|
||||
|
||||
export default {
|
||||
postmanToBruno,
|
||||
postmanToBrunoEnvironment,
|
||||
brunoToPostman,
|
||||
openApiToBruno,
|
||||
insomniaToBruno
|
||||
};
|
@ -1,34 +1,6 @@
|
||||
import jsyaml from 'js-yaml';
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
import fileDialog from 'file-dialog';
|
||||
import { uuid } from 'utils/common';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection } from './common';
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => {
|
||||
try {
|
||||
// try to load JSON
|
||||
const parsedData = JSON.parse(e.target.result);
|
||||
resolve(parsedData);
|
||||
} catch (jsonError) {
|
||||
// not a valid JSOn, try yaml
|
||||
try {
|
||||
const parsedData = jsyaml.load(e.target.result, { schema: jsyaml.CORE_SCHEMA });
|
||||
resolve(parsedData);
|
||||
} catch (yamlError) {
|
||||
console.error('Error parsing the file :', jsonError, yamlError);
|
||||
reject(new BrunoError('Import collection failed'));
|
||||
}
|
||||
}
|
||||
};
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid } from '../common';
|
||||
|
||||
const parseGraphQL = (text) => {
|
||||
try {
|
||||
@ -187,7 +159,7 @@ const transformInsomniaRequestItem = (request, index, allRequests) => {
|
||||
return brunoRequestItem;
|
||||
};
|
||||
|
||||
const parseInsomniaCollection = (data) => {
|
||||
const parseInsomniaCollection = (_insomniaCollection) => {
|
||||
const brunoCollection = {
|
||||
name: '',
|
||||
uid: uuid(),
|
||||
@ -196,66 +168,61 @@ const parseInsomniaCollection = (data) => {
|
||||
environments: []
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const insomniaExport = data;
|
||||
const insomniaResources = get(insomniaExport, 'resources', []);
|
||||
const insomniaCollection = insomniaResources.find((resource) => resource._type === 'workspace');
|
||||
try {
|
||||
const insomniaExport = _insomniaCollection;
|
||||
const insomniaResources = get(insomniaExport, 'resources', []);
|
||||
const insomniaCollection = insomniaResources.find((resource) => resource._type === 'workspace');
|
||||
|
||||
if (!insomniaCollection) {
|
||||
reject(new BrunoError('Collection not found inside Insomnia export'));
|
||||
}
|
||||
|
||||
brunoCollection.name = insomniaCollection.name;
|
||||
|
||||
const requestsAndFolders =
|
||||
insomniaResources.filter((resource) => resource._type === 'request' || resource._type === 'request_group') ||
|
||||
[];
|
||||
|
||||
function createFolderStructure(resources, parentId = null) {
|
||||
const requestGroups =
|
||||
resources.filter((resource) => resource._type === 'request_group' && resource.parentId === parentId) || [];
|
||||
const requests = resources.filter((resource) => resource._type === 'request' && resource.parentId === parentId);
|
||||
|
||||
const folders = requestGroups.map((folder, index, allFolder) => {
|
||||
const name = addSuffixToDuplicateName(folder, index, allFolder);
|
||||
const requests = resources.filter(
|
||||
(resource) => resource._type === 'request' && resource.parentId === folder._id
|
||||
);
|
||||
|
||||
return {
|
||||
uid: uuid(),
|
||||
name,
|
||||
type: 'folder',
|
||||
items: createFolderStructure(resources, folder._id).concat(requests.map(transformInsomniaRequestItem))
|
||||
};
|
||||
});
|
||||
|
||||
return folders.concat(requests.map(transformInsomniaRequestItem));
|
||||
}
|
||||
|
||||
(brunoCollection.items = createFolderStructure(requestsAndFolders, insomniaCollection._id)),
|
||||
resolve(brunoCollection);
|
||||
} catch (err) {
|
||||
reject(new BrunoError('An error occurred while parsing the Insomnia collection'));
|
||||
if (!insomniaCollection) {
|
||||
throw new Error('Collection not found inside Insomnia export');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const importCollection = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: '.json, .yaml, .yml, application/json, application/yaml, application/x-yaml' })
|
||||
.then(readFile)
|
||||
.then(parseInsomniaCollection)
|
||||
.then(transformItemsInCollection)
|
||||
.then(hydrateSeqInCollection)
|
||||
.then(validateSchema)
|
||||
.then((collection) => resolve({ collection }))
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
reject(new BrunoError('Import collection failed: ' + err.message));
|
||||
brunoCollection.name = insomniaCollection.name;
|
||||
|
||||
const requestsAndFolders =
|
||||
insomniaResources.filter((resource) => resource._type === 'request' || resource._type === 'request_group') ||
|
||||
[];
|
||||
|
||||
function createFolderStructure(resources, parentId = null) {
|
||||
const requestGroups =
|
||||
resources.filter((resource) => resource._type === 'request_group' && resource.parentId === parentId) || [];
|
||||
const requests = resources.filter((resource) => resource._type === 'request' && resource.parentId === parentId);
|
||||
|
||||
const folders = requestGroups.map((folder, index, allFolder) => {
|
||||
const name = addSuffixToDuplicateName(folder, index, allFolder);
|
||||
const requests = resources.filter(
|
||||
(resource) => resource._type === 'request' && resource.parentId === folder._id
|
||||
);
|
||||
|
||||
return {
|
||||
uid: uuid(),
|
||||
name,
|
||||
type: 'folder',
|
||||
items: createFolderStructure(resources, folder._id).concat(requests.map(transformInsomniaRequestItem))
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
return folders.concat(requests.map(transformInsomniaRequestItem));
|
||||
}
|
||||
|
||||
brunoCollection.items = createFolderStructure(requestsAndFolders, insomniaCollection._id);
|
||||
return brunoCollection;
|
||||
} catch (err) {
|
||||
throw new Error('An error occurred while parsing the Insomnia collection');
|
||||
}
|
||||
};
|
||||
|
||||
export default importCollection;
|
||||
export const insomniaToBruno = (insomniaCollection) => {
|
||||
try {
|
||||
const collection = parseInsomniaCollection(insomniaCollection);
|
||||
const transformedCollection = transformItemsInCollection(collection);
|
||||
const hydratedCollection = hydrateSeqInCollection(transformedCollection);
|
||||
const validatedCollection = validateSchema(hydratedCollection);
|
||||
return validatedCollection;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw new Error('Import collection failed');
|
||||
}
|
||||
};
|
||||
|
||||
export default insomniaToBruno;
|
||||
|
@ -1,34 +1,6 @@
|
||||
import jsyaml from 'js-yaml';
|
||||
import each from 'lodash/each';
|
||||
import get from 'lodash/get';
|
||||
import fileDialog from 'file-dialog';
|
||||
import { uuid } from 'utils/common';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection } from './common';
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => {
|
||||
try {
|
||||
// try to load JSON
|
||||
const parsedData = JSON.parse(e.target.result);
|
||||
resolve(parsedData);
|
||||
} catch (jsonError) {
|
||||
// not a valid JSOn, try yaml
|
||||
try {
|
||||
const parsedData = jsyaml.load(e.target.result);
|
||||
resolve(parsedData);
|
||||
} catch (yamlError) {
|
||||
console.error('Error parsing the file :', jsonError, yamlError);
|
||||
reject(new BrunoError('Import collection failed'));
|
||||
}
|
||||
}
|
||||
};
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid } from '../common';
|
||||
|
||||
const ensureUrl = (url) => {
|
||||
// removing multiple slashes after the protocol if it exists, or after the beginning of the string otherwise
|
||||
@ -363,12 +335,10 @@ export const parseOpenApiCollection = (data) => {
|
||||
items: [],
|
||||
environments: []
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const collectionData = resolveRefs(data);
|
||||
if (!collectionData) {
|
||||
reject(new BrunoError('Invalid OpenAPI collection. Failed to resolve refs.'));
|
||||
throw new Error('Invalid OpenAPI collection. Failed to resolve refs.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -377,7 +347,7 @@ export const parseOpenApiCollection = (data) => {
|
||||
|
||||
// Assumes v3 if not defined. v2 is not supported yet
|
||||
if (collectionData.openapi && !collectionData.openapi.startsWith('3')) {
|
||||
reject(new BrunoError('Only OpenAPI v3 is supported currently.'));
|
||||
throw new Error('Only OpenAPI v3 is supported currently.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -443,28 +413,24 @@ export const parseOpenApiCollection = (data) => {
|
||||
let ungroupedItems = ungroupedRequests.map(transformOpenapiRequestItem);
|
||||
let brunoCollectionItems = brunoFolders.concat(ungroupedItems);
|
||||
brunoCollection.items = brunoCollectionItems;
|
||||
resolve(brunoCollection);
|
||||
return brunoCollection;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
reject(new BrunoError('An error occurred while parsing the OpenAPI collection'));
|
||||
throw new Error('An error occurred while parsing the OpenAPI collection');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const importCollection = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: '.json, .yaml, .yml, application/json, application/yaml, application/x-yaml' })
|
||||
.then(readFile)
|
||||
.then(parseOpenApiCollection)
|
||||
.then(transformItemsInCollection)
|
||||
.then(hydrateSeqInCollection)
|
||||
.then(validateSchema)
|
||||
.then((collection) => resolve({ collection }))
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
reject(new BrunoError('Import collection failed: ' + err.message));
|
||||
});
|
||||
});
|
||||
export const openApiToBruno = (openApiSpecification) => {
|
||||
try {
|
||||
const collection = parseOpenApiCollection(openApiSpecification);
|
||||
const transformedCollection = transformItemsInCollection(collection);
|
||||
const hydratedCollection = hydrateSeqInCollection(transformedCollection);
|
||||
const validatedCollection = validateSchema(hydratedCollection);
|
||||
return validatedCollection
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw new Error('Import collection failed');
|
||||
}
|
||||
};
|
||||
|
||||
export default importCollection;
|
||||
export default openApiToBruno;
|
||||
|
@ -1,6 +1,5 @@
|
||||
import map from 'lodash/map';
|
||||
import * as FileSaver from 'file-saver';
|
||||
import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems } from '../collections/export';
|
||||
import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems } from '../common';
|
||||
|
||||
/**
|
||||
* Transforms a given URL string into an object representing the protocol, host, path, query, and variables.
|
||||
@ -102,7 +101,7 @@ export const sanitizeUrl = (url) => {
|
||||
return sanitizedUrl;
|
||||
};
|
||||
|
||||
export const exportCollection = (collection) => {
|
||||
export const brunoToPostman = (collection) => {
|
||||
delete collection.uid;
|
||||
delete collection.processEnvVariables;
|
||||
deleteUidsInItems(collection.items);
|
||||
@ -335,11 +334,7 @@ export const exportCollection = (collection) => {
|
||||
collectionToExport.info = generateInfoSection();
|
||||
collectionToExport.item = generateItemSection(collection.items);
|
||||
collectionToExport.variable = generateCollectionVars(collection);
|
||||
|
||||
const fileName = `${collection.name}.json`;
|
||||
const fileBlob = new Blob([JSON.stringify(collectionToExport, null, 2)], { type: 'application/json' });
|
||||
|
||||
FileSaver.saveAs(fileBlob, fileName);
|
||||
return collectionToExport;
|
||||
};
|
||||
|
||||
export default exportCollection;
|
||||
export default brunoToPostman;
|
||||
|
@ -1,16 +1,4 @@
|
||||
import each from 'lodash/each';
|
||||
import fileDialog from 'file-dialog';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => resolve(e.target.result);
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
|
||||
const isSecret = (type) => {
|
||||
return type === 'secret';
|
||||
};
|
||||
@ -40,42 +28,13 @@ const importPostmanEnvironment = (environment) => {
|
||||
return brunoEnvironment;
|
||||
};
|
||||
|
||||
const parsePostmanEnvironment = (str) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let environment = JSON.parse(str);
|
||||
return resolve(importPostmanEnvironment(environment));
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
if (err instanceof BrunoError) {
|
||||
return reject(err);
|
||||
}
|
||||
return reject(new BrunoError('Unable to parse the postman environment json file'));
|
||||
}
|
||||
});
|
||||
export const postmanToBrunoEnvironment = (postmanEnvironment) => {
|
||||
try {
|
||||
return importPostmanEnvironment(postmanEnvironment);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
throw new Error('Unable to parse the postman environment json file');
|
||||
}
|
||||
};
|
||||
|
||||
const importEnvironment = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ multiple: true, accept: 'application/json' })
|
||||
.then((files) => {
|
||||
return Promise.all(
|
||||
Object.values(files ?? {}).map((file) =>
|
||||
readFile([file])
|
||||
.then(parsePostmanEnvironment)
|
||||
.catch((err) => {
|
||||
console.error(`Error processing file: ${file.name || 'undefined'}`, err);
|
||||
throw err;
|
||||
})
|
||||
)
|
||||
);
|
||||
})
|
||||
.then((environments) => resolve(environments))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
reject(new BrunoError('Import Environment failed'));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export default importEnvironment;
|
||||
export default postmanToBrunoEnvironment;
|
||||
|
@ -1,19 +1,7 @@
|
||||
import get from 'lodash/get';
|
||||
import fileDialog from 'file-dialog';
|
||||
import { uuid } from 'utils/common';
|
||||
import { BrunoError } from 'utils/common/error';
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection } from './common';
|
||||
import { postmanTranslation } from 'utils/importers/translators/postman_translation';
|
||||
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid } from '../common';
|
||||
import each from 'lodash/each';
|
||||
|
||||
const readFile = (files) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
fileReader.onload = (e) => resolve(e.target.result);
|
||||
fileReader.onerror = (err) => reject(err);
|
||||
fileReader.readAsText(files[0]);
|
||||
});
|
||||
};
|
||||
import postmanTranslation from './postman-translations';
|
||||
|
||||
const parseGraphQLRequest = (graphqlSource) => {
|
||||
try {
|
||||
@ -95,28 +83,7 @@ const constructUrl = (url) => {
|
||||
return '';
|
||||
};
|
||||
|
||||
let translationLog = {};
|
||||
|
||||
/* struct of translation log
|
||||
{
|
||||
[collectionName]: {
|
||||
script: [index1, index2],
|
||||
test: [index1, index2]
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
const pushTranslationLog = (type, index) => {
|
||||
if (!translationLog[i.name]) {
|
||||
translationLog[i.name] = {};
|
||||
}
|
||||
if (!translationLog[i.name][type]) {
|
||||
translationLog[i.name][type] = [];
|
||||
}
|
||||
translationLog[i.name][type].push(index + 1);
|
||||
};
|
||||
|
||||
const importScriptsFromEvents = (events, requestObject, options, pushTranslationLog) => {
|
||||
const importScriptsFromEvents = (events, requestObject) => {
|
||||
events.forEach((event) => {
|
||||
if (event.script && event.script.exec) {
|
||||
if (event.listen === 'prerequest') {
|
||||
@ -124,22 +91,12 @@ const importScriptsFromEvents = (events, requestObject, options, pushTranslation
|
||||
requestObject.script = {};
|
||||
}
|
||||
|
||||
if (Array.isArray(event.script.exec)) {
|
||||
if (event.script.exec.length > 0) {
|
||||
requestObject.script.req = event.script.exec
|
||||
.map((line, index) =>
|
||||
options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(line, () => pushTranslationLog('script', index))
|
||||
: `// ${line}`
|
||||
)
|
||||
.join('\n');
|
||||
} else {
|
||||
requestObject.script.req = '';
|
||||
}
|
||||
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||
requestObject.script.req = event.script.exec
|
||||
.map((line) => postmanTranslation(line))
|
||||
.join('\n');
|
||||
} else if (typeof event.script.exec === 'string') {
|
||||
requestObject.script.req = options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('script', 0))
|
||||
: `// ${event.script.exec}`;
|
||||
requestObject.script.req = postmanTranslation(event.script.exec);
|
||||
} else {
|
||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
||||
}
|
||||
@ -150,22 +107,12 @@ const importScriptsFromEvents = (events, requestObject, options, pushTranslation
|
||||
requestObject.tests = {};
|
||||
}
|
||||
|
||||
if (Array.isArray(event.script.exec)) {
|
||||
if (event.script.exec.length > 0) {
|
||||
requestObject.tests = event.script.exec
|
||||
.map((line, index) =>
|
||||
options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(line, () => pushTranslationLog('test', index))
|
||||
: `// ${line}`
|
||||
)
|
||||
.join('\n');
|
||||
} else {
|
||||
requestObject.tests = '';
|
||||
}
|
||||
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||
requestObject.tests = event.script.exec
|
||||
.map((line) => postmanTranslation(line))
|
||||
.join('\n');
|
||||
} else if (typeof event.script.exec === 'string') {
|
||||
requestObject.tests = options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('test', 0))
|
||||
: `// ${event.script.exec}`;
|
||||
return postmanTranslation(event.script.exec);
|
||||
} else {
|
||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
||||
}
|
||||
@ -185,7 +132,7 @@ const importCollectionLevelVariables = (variables, requestObject) => {
|
||||
requestObject.vars.req = vars;
|
||||
};
|
||||
|
||||
const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) => {
|
||||
const importPostmanV2CollectionItem = (brunoParent, item, parentAuth) => {
|
||||
brunoParent.items = brunoParent.items || [];
|
||||
const folderMap = {};
|
||||
const requestMap = {};
|
||||
@ -227,11 +174,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) =
|
||||
}
|
||||
};
|
||||
if (i.item && i.item.length) {
|
||||
importPostmanV2CollectionItem(brunoFolderItem, i.item, i.auth ?? parentAuth, options);
|
||||
importPostmanV2CollectionItem(brunoFolderItem, i.item, i.auth ?? parentAuth);
|
||||
}
|
||||
|
||||
if (i.event) {
|
||||
importScriptsFromEvents(i.event, brunoFolderItem.root.request, options, pushTranslationLog);
|
||||
importScriptsFromEvents(i.event, brunoFolderItem.root.request);
|
||||
}
|
||||
|
||||
brunoParent.items.push(brunoFolderItem);
|
||||
@ -288,22 +235,12 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) =
|
||||
if (!brunoRequestItem.request.script) {
|
||||
brunoRequestItem.request.script = {};
|
||||
}
|
||||
if (Array.isArray(event.script.exec)) {
|
||||
if (event.script.exec.length > 0) {
|
||||
brunoRequestItem.request.script.req = event.script.exec
|
||||
.map((line, index) =>
|
||||
options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(line, () => pushTranslationLog('script', index))
|
||||
: `// ${line}`
|
||||
)
|
||||
.join('\n');
|
||||
} else {
|
||||
brunoRequestItem.request.script.req = '';
|
||||
}
|
||||
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||
brunoRequestItem.request.script.req = event.script.exec
|
||||
.map((line) => postmanTranslation(line))
|
||||
.join('\n');
|
||||
} else if (typeof event.script.exec === 'string') {
|
||||
brunoRequestItem.request.script.req = options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('script', 0))
|
||||
: `// ${event.script.exec}`;
|
||||
brunoRequestItem.request.script.req = postmanTranslation(event.script.exec);
|
||||
} else {
|
||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
||||
}
|
||||
@ -312,22 +249,12 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) =
|
||||
if (!brunoRequestItem.request.tests) {
|
||||
brunoRequestItem.request.tests = {};
|
||||
}
|
||||
if (Array.isArray(event.script.exec)) {
|
||||
if (event.script.exec.length > 0) {
|
||||
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||
brunoRequestItem.request.tests = event.script.exec
|
||||
.map((line, index) =>
|
||||
options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(line, () => pushTranslationLog('test', index))
|
||||
: `// ${line}`
|
||||
)
|
||||
.map((line) => postmanTranslation(line))
|
||||
.join('\n');
|
||||
} else {
|
||||
brunoRequestItem.request.tests = '';
|
||||
}
|
||||
} else if (typeof event.script.exec === 'string') {
|
||||
brunoRequestItem.request.tests = options.enablePostmanTranslations.enabled
|
||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('test', 0))
|
||||
: `// ${event.script.exec}`;
|
||||
return postmanTranslation(event.script.exec);
|
||||
} else {
|
||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
||||
}
|
||||
@ -559,7 +486,7 @@ const searchLanguageByHeader = (headers) => {
|
||||
return contentType;
|
||||
};
|
||||
|
||||
const importPostmanV2Collection = (collection, options) => {
|
||||
const importPostmanV2Collection = (collection) => {
|
||||
const brunoCollection = {
|
||||
name: collection.info.name || 'Untitled Collection',
|
||||
uid: uuid(),
|
||||
@ -587,81 +514,55 @@ const importPostmanV2Collection = (collection, options) => {
|
||||
};
|
||||
|
||||
if (collection.event) {
|
||||
importScriptsFromEvents(collection.event, brunoCollection.root.request, options, pushTranslationLog);
|
||||
importScriptsFromEvents(collection.event, brunoCollection.root.request);
|
||||
}
|
||||
|
||||
if (collection?.variable){
|
||||
importCollectionLevelVariables(collection.variable, brunoCollection.root.request);
|
||||
}
|
||||
|
||||
importPostmanV2CollectionItem(brunoCollection, collection.item, collection.auth, options);
|
||||
importPostmanV2CollectionItem(brunoCollection, collection.item, collection.auth);
|
||||
|
||||
return brunoCollection;
|
||||
};
|
||||
|
||||
const parsePostmanCollection = (str, options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
let collection = JSON.parse(str);
|
||||
let schema = get(collection, 'info.schema');
|
||||
const parsePostmanCollection = (collection) => {
|
||||
try {
|
||||
let schema = get(collection, 'info.schema');
|
||||
|
||||
let v2Schemas = [
|
||||
'https://schema.getpostman.com/json/collection/v2.0.0/collection.json',
|
||||
'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
|
||||
'https://schema.postman.com/json/collection/v2.0.0/collection.json',
|
||||
'https://schema.postman.com/json/collection/v2.1.0/collection.json'
|
||||
];
|
||||
let v2Schemas = [
|
||||
'https://schema.getpostman.com/json/collection/v2.0.0/collection.json',
|
||||
'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
|
||||
'https://schema.postman.com/json/collection/v2.0.0/collection.json',
|
||||
'https://schema.postman.com/json/collection/v2.1.0/collection.json'
|
||||
];
|
||||
|
||||
if (v2Schemas.includes(schema)) {
|
||||
return resolve(importPostmanV2Collection(collection, options));
|
||||
}
|
||||
|
||||
throw new BrunoError('Unknown postman schema');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
if (err instanceof BrunoError) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return reject(new BrunoError('Unable to parse the postman collection json file'));
|
||||
if (v2Schemas.includes(schema)) {
|
||||
return importPostmanV2Collection(collection);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const logTranslationDetails = (translationLog) => {
|
||||
if (Object.keys(translationLog || {}).length > 0) {
|
||||
console.warn(
|
||||
`[Postman Translation Logs]
|
||||
Collections incomplete : ${Object.keys(translationLog || {}).length}` +
|
||||
`\nTotal lines incomplete : ${Object.values(translationLog || {}).reduce(
|
||||
(acc, curr) => acc + (curr.script?.length || 0) + (curr.test?.length || 0),
|
||||
0
|
||||
)}` +
|
||||
`\nSee details below :`,
|
||||
translationLog
|
||||
);
|
||||
throw new Error('Unknown postman schema');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
if (err instanceof Error) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
throw new Error('Unable to parse the postman collection json file');
|
||||
}
|
||||
};
|
||||
|
||||
const importCollection = (options) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
fileDialog({ accept: 'application/json' })
|
||||
.then(readFile)
|
||||
.then((str) => parsePostmanCollection(str, options))
|
||||
.then(transformItemsInCollection)
|
||||
.then(hydrateSeqInCollection)
|
||||
.then(validateSchema)
|
||||
.then((collection) => resolve({ collection, translationLog }))
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
translationLog = {};
|
||||
reject(new BrunoError('Import collection failed'));
|
||||
})
|
||||
.then(() => {
|
||||
logTranslationDetails(translationLog);
|
||||
translationLog = {};
|
||||
});
|
||||
});
|
||||
const postmanToBruno = (postmanCollection) => {
|
||||
try {
|
||||
const parsedPostmanCollection = parsePostmanCollection(postmanCollection);
|
||||
const transformedCollection = transformItemsInCollection(parsedPostmanCollection);
|
||||
const hydratedCollection = hydrateSeqInCollection(transformedCollection);
|
||||
const validatedCollection = validateSchema(hydratedCollection);
|
||||
return ({ collection: validatedCollection });
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
throw new Error('Import collection failed');
|
||||
}
|
||||
};
|
||||
|
||||
export default importCollection;
|
||||
export default postmanToBruno;
|
@ -42,7 +42,7 @@ const compiledReplacements = Object.entries(extendedReplacements).map(([pattern,
|
||||
replacement
|
||||
}));
|
||||
|
||||
export const postmanTranslation = (script, logCallback) => {
|
||||
const postmanTranslation = (script) => {
|
||||
try {
|
||||
let modifiedScript = script;
|
||||
let modified = false;
|
||||
@ -54,10 +54,11 @@ export const postmanTranslation = (script, logCallback) => {
|
||||
}
|
||||
if (modifiedScript.includes('pm.') || modifiedScript.includes('postman.')) {
|
||||
modifiedScript = modifiedScript.replace(/^(.*(pm\.|postman\.).*)$/gm, '// $1');
|
||||
//logCallback?.();
|
||||
}
|
||||
return modifiedScript;
|
||||
} catch (e) {
|
||||
return script;
|
||||
}
|
||||
};
|
||||
|
||||
export default postmanTranslation;
|
@ -0,0 +1,190 @@
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import insomniaToBruno from '../../src/insomnia/insomnia-to-bruno';
|
||||
|
||||
describe('insomnia-collection', () => {
|
||||
it('should correctly import a valid Insomnia collection file', async () => {
|
||||
const brunoCollection = insomniaToBruno(insomniaCollection);
|
||||
|
||||
expect(brunoCollection).toMatchObject(expectedOutput)
|
||||
});
|
||||
});
|
||||
|
||||
const insomniaCollection = {
|
||||
"_type": "export",
|
||||
"__export_format": 4,
|
||||
"__export_date": "2024-05-20T10:02:44.123Z",
|
||||
"__export_source": "insomnia.desktop.app:v2021.5.2",
|
||||
"resources": [
|
||||
{
|
||||
"_id": "req_1",
|
||||
"_type": "request",
|
||||
"parentId": "fld_1",
|
||||
"name": "Request1",
|
||||
"method": "GET",
|
||||
"url": "https://httpbin.org/get",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"_id": "req_2",
|
||||
"_type": "request",
|
||||
"parentId": "fld_2",
|
||||
"name": "Request2",
|
||||
"method": "GET",
|
||||
"url": "https://httpbin.org/get",
|
||||
"parameters": []
|
||||
},
|
||||
{
|
||||
"_id": "fld_1",
|
||||
"_type": "request_group",
|
||||
"parentId": "wrk_1",
|
||||
"name": "Folder1"
|
||||
},
|
||||
{
|
||||
"_id": "fld_2",
|
||||
"_type": "request_group",
|
||||
"parentId": "wrk_1",
|
||||
"name": "Folder2"
|
||||
},
|
||||
{
|
||||
"_id": "wrk_1",
|
||||
"_type": "workspace",
|
||||
"name": "Hello World Workspace Insomnia"
|
||||
},
|
||||
{
|
||||
"_id": "env_1",
|
||||
"_type": "environment",
|
||||
"parentId": "wrk_1",
|
||||
"data": {
|
||||
"var1": "value1",
|
||||
"var2": "value2"
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const expectedOutput = {
|
||||
"environments": [],
|
||||
"items": [
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"name": "Request1",
|
||||
"request": {
|
||||
"auth": {
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"digest": null,
|
||||
"mode": "none",
|
||||
},
|
||||
"body": {
|
||||
"formUrlEncoded": [],
|
||||
"json": null,
|
||||
"mode": "none",
|
||||
"multipartForm": [],
|
||||
"text": null,
|
||||
"xml": null,
|
||||
},
|
||||
"headers": [],
|
||||
"method": "GET",
|
||||
"params": [],
|
||||
"url": "https://httpbin.org/get",
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "http-request",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
{
|
||||
"name": "Request1",
|
||||
"request": {
|
||||
"auth": {
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"digest": null,
|
||||
"mode": "none",
|
||||
},
|
||||
"body": {
|
||||
"formUrlEncoded": [],
|
||||
"json": null,
|
||||
"mode": "none",
|
||||
"multipartForm": [],
|
||||
"text": null,
|
||||
"xml": null,
|
||||
},
|
||||
"headers": [],
|
||||
"method": "GET",
|
||||
"params": [],
|
||||
"url": "https://httpbin.org/get",
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "http-request",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
],
|
||||
"name": "Folder1",
|
||||
"type": "folder",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"name": "Request2",
|
||||
"request": {
|
||||
"auth": {
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"digest": null,
|
||||
"mode": "none",
|
||||
},
|
||||
"body": {
|
||||
"formUrlEncoded": [],
|
||||
"json": null,
|
||||
"mode": "none",
|
||||
"multipartForm": [],
|
||||
"text": null,
|
||||
"xml": null,
|
||||
},
|
||||
"headers": [],
|
||||
"method": "GET",
|
||||
"params": [],
|
||||
"url": "https://httpbin.org/get",
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "http-request",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
{
|
||||
"name": "Request2",
|
||||
"request": {
|
||||
"auth": {
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"digest": null,
|
||||
"mode": "none",
|
||||
},
|
||||
"body": {
|
||||
"formUrlEncoded": [],
|
||||
"json": null,
|
||||
"mode": "none",
|
||||
"multipartForm": [],
|
||||
"text": null,
|
||||
"xml": null,
|
||||
},
|
||||
"headers": [],
|
||||
"method": "GET",
|
||||
"params": [],
|
||||
"url": "https://httpbin.org/get",
|
||||
},
|
||||
"seq": 2,
|
||||
"type": "http-request",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
],
|
||||
"name": "Folder2",
|
||||
"type": "folder",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
],
|
||||
"name": "Hello World Workspace Insomnia",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"version": "1",
|
||||
};
|
108
packages/bruno-converters/tests/openapi/openapi-to-bruno.spec.js
Normal file
108
packages/bruno-converters/tests/openapi/openapi-to-bruno.spec.js
Normal file
@ -0,0 +1,108 @@
|
||||
import jsyaml from 'js-yaml';
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import openApiToBruno from '../../src/openapi/openapi-to-bruno';
|
||||
|
||||
describe('openapi-collection', () => {
|
||||
it('should correctly import a valid OpenAPI file', async () => {
|
||||
const openApiSpecification = jsyaml.load(openApiCollectionString);
|
||||
const brunoCollection = openApiToBruno(openApiSpecification);
|
||||
|
||||
expect(brunoCollection).toMatchObject(expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
const openApiCollectionString = `
|
||||
openapi: "3.0.0"
|
||||
info:
|
||||
version: "1.0.0"
|
||||
title: "Hello World OpenAPI"
|
||||
paths:
|
||||
/get:
|
||||
get:
|
||||
tags:
|
||||
- Folder1
|
||||
- Folder2
|
||||
summary: "Request1 and Request2"
|
||||
operationId: "getRequests"
|
||||
responses:
|
||||
'200':
|
||||
description: "Successful response"
|
||||
components:
|
||||
parameters:
|
||||
var1:
|
||||
in: "query"
|
||||
name: "var1"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
default: "value1"
|
||||
var2:
|
||||
in: "query"
|
||||
name: "var2"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
default: "value2"
|
||||
servers:
|
||||
- url: "https://httpbin.org"
|
||||
`;
|
||||
|
||||
const expectedOutput = {
|
||||
"environments": [
|
||||
{
|
||||
"name": "Environment 1",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"variables": [
|
||||
{
|
||||
"enabled": true,
|
||||
"name": "baseUrl",
|
||||
"secret": false,
|
||||
"type": "text",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"value": "https://httpbin.org",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"items": [
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"name": "Request1 and Request2",
|
||||
"request": {
|
||||
"auth": {
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"digest": null,
|
||||
"mode": "none",
|
||||
},
|
||||
"body": {
|
||||
"formUrlEncoded": [],
|
||||
"json": null,
|
||||
"mode": "none",
|
||||
"multipartForm": [],
|
||||
"text": null,
|
||||
"xml": null,
|
||||
},
|
||||
"headers": [],
|
||||
"method": "GET",
|
||||
"params": [],
|
||||
"script": {
|
||||
"res": null,
|
||||
},
|
||||
"url": "{{baseUrl}}/get",
|
||||
},
|
||||
"seq": 1,
|
||||
"type": "http-request",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
],
|
||||
"name": "Folder1",
|
||||
"type": "folder",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
},
|
||||
],
|
||||
"name": "Hello World OpenAPI",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"version": "1",
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
const { sanitizeUrl, transformUrl } = require('./postman-collection');
|
||||
import { sanitizeUrl, transformUrl } from "../../src/postman/bruno-to-postman";
|
||||
|
||||
describe('transformUrl', () => {
|
||||
it('should handle basic URL with path variables', () => {
|
||||
|
@ -0,0 +1,67 @@
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import postmanToBrunoEnvironment from '../../src/postman/postman-env-to-bruno-env';
|
||||
|
||||
describe('postmanToBrunoEnvironment Function', () => {
|
||||
it('should correctly import a valid Postman environment file', async () => {
|
||||
const postmanEnvironment = {
|
||||
"id": "some-id",
|
||||
"name": "My Environment",
|
||||
"values": [
|
||||
{
|
||||
"key": "var1",
|
||||
"value": "value1",
|
||||
"enabled": true,
|
||||
"type": "text"
|
||||
},
|
||||
{
|
||||
"key": "var2",
|
||||
"value": "value2",
|
||||
"enabled": false,
|
||||
"type": "secret"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const brunoEnvironment = await postmanToBrunoEnvironment(postmanEnvironment);
|
||||
|
||||
const expectedEnvironment = {
|
||||
name: 'My Environment',
|
||||
variables: [
|
||||
{
|
||||
name: 'var1',
|
||||
value: 'value1',
|
||||
enabled: true,
|
||||
secret: false,
|
||||
},
|
||||
{
|
||||
name: 'var2',
|
||||
value: 'value2',
|
||||
enabled: false,
|
||||
secret: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(brunoEnvironment).toEqual(expectedEnvironment);
|
||||
});
|
||||
|
||||
it.skip('should throw Error when JSON parsing fails', async () => {
|
||||
const invalidBrunoEnvironment = {
|
||||
"id": "some-id",
|
||||
"name": "My Environment",
|
||||
"values": [
|
||||
{
|
||||
"key": "var1",
|
||||
"value": "value1",
|
||||
"enabled": true,
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
await expect(postmanToBrunoEnvironment(invalidBrunoEnvironment)).rejects.toThrow(Error);
|
||||
await expect(postmanToBrunoEnvironment(invalidBrunoEnvironment)).rejects.toThrow(
|
||||
'Unable to parse the postman environment json file'
|
||||
);
|
||||
});
|
||||
});
|
726
packages/bruno-converters/tests/postman/postman-to-bruno.spec.js
Normal file
726
packages/bruno-converters/tests/postman/postman-to-bruno.spec.js
Normal file
@ -0,0 +1,726 @@
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
import postmanToBruno from '../../src/postman/postman-to-bruno';
|
||||
|
||||
describe('postman-collection', () => {
|
||||
it('should correctly import a valid Postman collection file', async () => {
|
||||
const brunoCollection = postmanToBruno(postmanCollection);
|
||||
expect(brunoCollection).toMatchObject(expectedOutput);
|
||||
});
|
||||
});
|
||||
|
||||
const postmanCollection = {
|
||||
"info": {
|
||||
"_postman_id": "0596d399-cfd2-4f8f-9869-65238eb40a45",
|
||||
"name": "CRUD",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json",
|
||||
"_exporter_id": "32111649",
|
||||
"_collection_link": "https://www.postman.com/fudzi9/workspace/nodejs/collection/16541095-0596d399-cfd2-4f8f-9869-65238eb40a45?action=share&source=collection_link&creator=32111649"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "GET",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "1.GET",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "2"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"2-l9Fw4VUO7kr8CvBlt4zaMCqXZ0w\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 21:30:45 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "[]"
|
||||
},
|
||||
{
|
||||
"name": "3.GET",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "96"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"60-ixboSJswZpL0hV7rJrY1IE5nQlM\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 21:58:32 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "[\n {\n \"id\": 1,\n \"title\": \"first\",\n \"content\": \"some text\",\n \"createdAt\": \"some date\",\n \"updatedAt\": \"some date\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"name": "5.GET",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "192"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"c0-rg+VAYKuV+nAzdAnddMXRNSM3tg\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 22:01:36 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "[\n {\n \"id\": 1,\n \"title\": \"first\",\n \"content\": \"some text\",\n \"createdAt\": \"some date\",\n \"updatedAt\": \"some date\"\n },\n {\n \"id\": 2,\n \"title\": \"second\",\n \"content\": \"some text\",\n \"createdAt\": \"some date\",\n \"updatedAt\": \"some date\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"name": "7.GET",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "199"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"c7-SBFGBh+BSdmKqSUIW4VDODIOnaI\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 22:38:51 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "[\n {\n \"id\": 2,\n \"title\": \"second\",\n \"content\": \"some text\",\n \"createdAt\": \"some date\",\n \"updatedAt\": \"some date\"\n },\n {\n \"id\": 1,\n \"title\": \"first changed\",\n \"content\": \"new text\",\n \"createdAt\": \"some date\",\n \"updatedAt\": \"some date\"\n }\n]"
|
||||
},
|
||||
{
|
||||
"name": "9.GET",
|
||||
"originalRequest": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "103"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"67-aR9NxSbB5ab73lSksdIWZNuQyq8\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 22:40:55 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "[\n {\n \"id\": 1,\n \"title\": \"first changed\",\n \"content\": \"new text\",\n \"createdAt\": \"some date\",\n \"updatedAt\": \"some date\"\n }\n]"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "POST",
|
||||
"event": [
|
||||
{
|
||||
"listen": "prerequest",
|
||||
"script": {
|
||||
"exec": [
|
||||
""
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
},
|
||||
{
|
||||
"listen": "test",
|
||||
"script": {
|
||||
"exec": [
|
||||
""
|
||||
],
|
||||
"type": "text/javascript"
|
||||
}
|
||||
}
|
||||
],
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"id\": 1, \"title\": \"first\", \"content\": \"some text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "2.POST",
|
||||
"originalRequest": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"id\": 1, \"title\": \"first\", \"content\": \"some text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "123"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"7b-Zs+ZSZvDSG55ZK90aBqfAjoxdAg\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 21:58:17 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "\"{\\\"id\\\": 1, \\\"title\\\": \\\"first\\\", \\\"content\\\": \\\"some text\\\", \\\"createdAt\\\": \\\"some date\\\", \\\"updatedAt\\\": \\\"some date\\\"}\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "POST",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"id\": 2, \"title\": \"second\", \"content\": \"some text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "4.POST",
|
||||
"originalRequest": {
|
||||
"method": "POST",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"id\": 2, \"title\": \"second\", \"content\": \"some text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "124"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"7c-vtAEN2HlKwhD6OkasvICg9Ni+g0\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 22:00:49 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "\"{\\\"id\\\": 2, \\\"title\\\": \\\"second\\\", \\\"content\\\": \\\"some text\\\", \\\"createdAt\\\": \\\"some date\\\", \\\"updatedAt\\\": \\\"some date\\\"}\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PUT",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"id\": 1, \"title\": \"first changed\", \"content\": \"new text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/1"
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "6.PUT",
|
||||
"originalRequest": {
|
||||
"method": "PUT",
|
||||
"header": [],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\"id\": 1, \"title\": \"first changed\", \"content\": \"new text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"options": {
|
||||
"raw": {
|
||||
"language": "json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/1"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "130"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"82-QdzTirfdP1+K+iNOkslStk0OPpg\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 22:03:36 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "\"{\\\"id\\\": 1, \\\"title\\\": \\\"first changed\\\", \\\"content\\\": \\\"new text\\\", \\\"createdAt\\\": \\\"some date\\\", \\\"updatedAt\\\": \\\"some date\\\"}\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DELETE",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/2"
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "8.DELETE",
|
||||
"originalRequest": {
|
||||
"method": "DELETE",
|
||||
"header": [],
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/2"
|
||||
},
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"_postman_previewlanguage": "json",
|
||||
"header": [
|
||||
{
|
||||
"key": "Server",
|
||||
"value": "Cowboy"
|
||||
},
|
||||
{
|
||||
"key": "Connection",
|
||||
"value": "keep-alive"
|
||||
},
|
||||
{
|
||||
"key": "X-Powered-By",
|
||||
"value": "Express"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json; charset=utf-8"
|
||||
},
|
||||
{
|
||||
"key": "Content-Length",
|
||||
"value": "23"
|
||||
},
|
||||
{
|
||||
"key": "Etag",
|
||||
"value": "W/\"17-bCXlhEBJSVIeQ+m1i+6p7+rrNak\""
|
||||
},
|
||||
{
|
||||
"key": "Date",
|
||||
"value": "Tue, 06 Jul 2021 22:40:08 GMT"
|
||||
},
|
||||
{
|
||||
"key": "Via",
|
||||
"value": "1.1 vegur"
|
||||
}
|
||||
],
|
||||
"cookie": [],
|
||||
"body": "{\n \"success\": true,\n \"id\": 2\n}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const expectedOutput = {
|
||||
"collection": {
|
||||
"name": "CRUD",
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"version": "1",
|
||||
"items": [
|
||||
{
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"name": "GET",
|
||||
"type": "http-request",
|
||||
"request": {
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/",
|
||||
"method": "GET",
|
||||
"auth": {
|
||||
"mode": "none",
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"awsv4": null
|
||||
},
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"body": {
|
||||
"mode": "none",
|
||||
"json": null,
|
||||
"text": null,
|
||||
"xml": null,
|
||||
"formUrlEncoded": [],
|
||||
"multipartForm": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"name": "POST",
|
||||
"type": "http-request",
|
||||
"request": {
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/",
|
||||
"method": "POST",
|
||||
"auth": {
|
||||
"mode": "none",
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"awsv4": null
|
||||
},
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"body": {
|
||||
"mode": "json",
|
||||
"json": "{\"id\": 1, \"title\": \"first\", \"content\": \"some text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"text": null,
|
||||
"xml": null,
|
||||
"formUrlEncoded": [],
|
||||
"multipartForm": []
|
||||
},
|
||||
"script": {
|
||||
"req": ""
|
||||
},
|
||||
"tests": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"name": "POST_1",
|
||||
"type": "http-request",
|
||||
"request": {
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/",
|
||||
"method": "POST",
|
||||
"auth": {
|
||||
"mode": "none",
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"awsv4": null
|
||||
},
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"body": {
|
||||
"mode": "json",
|
||||
"json": "{\"id\": 2, \"title\": \"second\", \"content\": \"some text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"text": null,
|
||||
"xml": null,
|
||||
"formUrlEncoded": [],
|
||||
"multipartForm": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"name": "PUT",
|
||||
"type": "http-request",
|
||||
"request": {
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/1",
|
||||
"method": "PUT",
|
||||
"auth": {
|
||||
"mode": "none",
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"awsv4": null
|
||||
},
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"body": {
|
||||
"mode": "json",
|
||||
"json": "{\"id\": 1, \"title\": \"first changed\", \"content\": \"new text\", \"createdAt\": \"some date\", \"updatedAt\": \"some date\"}",
|
||||
"text": null,
|
||||
"xml": null,
|
||||
"formUrlEncoded": [],
|
||||
"multipartForm": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "mockeduuidvalue123456",
|
||||
"name": "DELETE",
|
||||
"type": "http-request",
|
||||
"request": {
|
||||
"url": "https://node-task2.herokuapp.com/api/notes/2",
|
||||
"method": "DELETE",
|
||||
"auth": {
|
||||
"mode": "none",
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"awsv4": null
|
||||
},
|
||||
"headers": [],
|
||||
"params": [],
|
||||
"body": {
|
||||
"mode": "none",
|
||||
"json": null,
|
||||
"text": null,
|
||||
"xml": null,
|
||||
"formUrlEncoded": [],
|
||||
"multipartForm": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"environments": [],
|
||||
"root": {
|
||||
"docs": "",
|
||||
"meta": {
|
||||
"name": "CRUD"
|
||||
},
|
||||
"request": {
|
||||
"auth": {
|
||||
"mode": "none",
|
||||
"basic": null,
|
||||
"bearer": null,
|
||||
"awsv4": null
|
||||
},
|
||||
"headers": [],
|
||||
"script": {},
|
||||
"tests": "",
|
||||
"vars": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
const { postmanTranslation } = require('./postman_translation'); // Adjust path as needed
|
||||
const { default: postmanTranslation } = require("../../src/postman/postman-translations");
|
||||
|
||||
describe('postmanTranslation function', () => {
|
||||
test('should translate pm commands correctly', () => {
|
||||
@ -11,9 +11,6 @@ describe('postmanTranslation function', () => {
|
||||
pm.collectionVariables.set('key', 'value');
|
||||
const data = pm.response.json();
|
||||
pm.expect(pm.environment.has('key')).to.be.true;
|
||||
postman.setEnvironmentVariable('key', 'value');
|
||||
postman.getEnvironmentVariable('key');
|
||||
postman.clearEnvironmentVariable('key');
|
||||
`;
|
||||
const expectedOutput = `
|
||||
bru.getEnvVar('key');
|
||||
@ -24,9 +21,6 @@ describe('postmanTranslation function', () => {
|
||||
bru.setVar('key', 'value');
|
||||
const data = res.getBody();
|
||||
expect(bru.getEnvVar('key') !== undefined && bru.getEnvVar('key') !== null).to.be.true;
|
||||
bru.setEnvVar('key', 'value');
|
||||
bru.getEnvVar('key');
|
||||
bru.deleteEnvVar('key');
|
||||
`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
@ -53,7 +47,7 @@ describe('postmanTranslation function', () => {
|
||||
test('should handle multiple pm commands on the same line', () => {
|
||||
const inputScript = "pm.environment.get('key'); pm.environment.set('key', 'value');";
|
||||
const expectedOutput = "bru.getEnvVar('key'); bru.setEnvVar('key', 'value');";
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
test('should handle comments and other JavaScript code', () => {
|
||||
const inputScript = `
|
||||
@ -157,13 +151,3 @@ test('should handle response commands', () => {
|
||||
`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
||||
test('should handle tests object', () => {
|
||||
const inputScript = `
|
||||
tests['Status code is 200'] = responseCode.code === 200;
|
||||
`;
|
||||
const expectedOutput = `
|
||||
test("Status code is 200", function() { expect(Boolean(responseCode.code === 200)).to.be.true; });
|
||||
`;
|
||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||
});
|
||||
|
19
packages/bruno-converters/tsconfig.json
Normal file
19
packages/bruno-converters/tsconfig.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"esModuleInterop": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"jsx": "react",
|
||||
"module": "ESNext",
|
||||
"declaration": true,
|
||||
"declarationDir": "types",
|
||||
"sourceMap": true,
|
||||
"outDir": "dist",
|
||||
"moduleResolution": "node",
|
||||
"emitDeclarationOnly": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"exclude": ["dist", "node_modules", "tests"]
|
||||
}
|
6
packages/bruno-converters/types/common.d.ts
vendored
Normal file
6
packages/bruno-converters/types/common.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export declare const uuid: () => string;
|
||||
export declare const normalizeFileName: (name: string) => string;
|
||||
export declare const validateSchema: (collection?: {}) => Promise<unknown>;
|
||||
export declare const updateUidsInCollection: (_collection: any) => any;
|
||||
export declare const transformItemsInCollection: (collection: any) => any;
|
||||
export declare const hydrateSeqInCollection: (collection: any) => any;
|
@ -74,6 +74,7 @@ async function setup() {
|
||||
execCommand('npm run build:graphql-docs', 'Building graphql-docs');
|
||||
execCommand('npm run build:bruno-query', 'Building bruno-query');
|
||||
execCommand('npm run build:bruno-common', 'Building bruno-common');
|
||||
execCommand('npm run build:bruno-converters', 'Building bruno-converters');
|
||||
|
||||
// Bundle JS sandbox libraries
|
||||
execCommand(
|
||||
|
Loading…
x
Reference in New Issue
Block a user