mirror of
https://github.com/usebruno/bruno.git
synced 2025-08-17 22:49:54 +02: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:
147
package-lock.json
generated
147
package-lock.json
generated
@@ -10,6 +10,7 @@
|
|||||||
"packages/bruno-electron",
|
"packages/bruno-electron",
|
||||||
"packages/bruno-cli",
|
"packages/bruno-cli",
|
||||||
"packages/bruno-common",
|
"packages/bruno-common",
|
||||||
|
"packages/bruno-converters",
|
||||||
"packages/bruno-schema",
|
"packages/bruno-schema",
|
||||||
"packages/bruno-query",
|
"packages/bruno-query",
|
||||||
"packages/bruno-js",
|
"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": {
|
"node_modules/@rollup/plugin-commonjs": {
|
||||||
"version": "23.0.7",
|
"version": "23.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.7.tgz",
|
||||||
@@ -7937,6 +7956,10 @@
|
|||||||
"resolved": "packages/bruno-common",
|
"resolved": "packages/bruno-common",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@usebruno/converters": {
|
||||||
|
"resolved": "packages/bruno-converters",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@usebruno/crypto-js": {
|
"node_modules/@usebruno/crypto-js": {
|
||||||
"version": "3.1.9",
|
"version": "3.1.9",
|
||||||
"resolved": "https://registry.npmjs.org/@usebruno/crypto-js/-/crypto-js-3.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@usebruno/crypto-js/-/crypto-js-3.1.9.tgz",
|
||||||
@@ -26274,6 +26297,130 @@
|
|||||||
"typescript": "^4.8.4"
|
"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": {
|
"packages/bruno-electron": {
|
||||||
"name": "bruno",
|
"name": "bruno",
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
"packages/bruno-electron",
|
"packages/bruno-electron",
|
||||||
"packages/bruno-cli",
|
"packages/bruno-cli",
|
||||||
"packages/bruno-common",
|
"packages/bruno-common",
|
||||||
|
"packages/bruno-converters",
|
||||||
"packages/bruno-schema",
|
"packages/bruno-schema",
|
||||||
"packages/bruno-query",
|
"packages/bruno-query",
|
||||||
"packages/bruno-js",
|
"packages/bruno-js",
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
"dev:electron": "npm run dev --workspace=packages/bruno-electron",
|
"dev:electron": "npm run dev --workspace=packages/bruno-electron",
|
||||||
"dev:electron:debug": "npm run debug --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-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:bruno-query": "npm run build --workspace=packages/bruno-query",
|
||||||
"build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs",
|
"build:graphql-docs": "npm run build --workspace=packages/bruno-graphql-docs",
|
||||||
"build:electron": "node ./scripts/build-electron.js",
|
"build:electron": "node ./scripts/build-electron.js",
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import exportBrunoCollection from 'utils/collections/export';
|
import exportBrunoCollection from 'utils/collections/export';
|
||||||
import exportPostmanCollection from 'utils/exporters/postman-collection';
|
import exportPostmanCollection from 'utils/exporters/postman-collection';
|
||||||
import { toastError } from 'utils/common/error';
|
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import Modal from 'components/Modal';
|
import Modal from 'components/Modal';
|
||||||
import { transformCollectionToSaveToExportAsFile } from 'utils/collections/index';
|
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 importBrunoCollection from 'utils/importers/bruno-collection';
|
||||||
import importPostmanCollection from 'utils/importers/postman-collection';
|
import importPostmanCollection from 'utils/importers/postman-collection';
|
||||||
import importInsomniaCollection from 'utils/importers/insomnia-collection';
|
import importInsomniaCollection from 'utils/importers/insomnia-collection';
|
||||||
@@ -7,14 +7,6 @@ import { toastError } from 'utils/common/error';
|
|||||||
import Modal from 'components/Modal';
|
import Modal from 'components/Modal';
|
||||||
|
|
||||||
const ImportCollection = ({ onClose, handleSubmit }) => {
|
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 = () => {
|
const handleImportBrunoCollection = () => {
|
||||||
importBrunoCollection()
|
importBrunoCollection()
|
||||||
.then(({ collection }) => {
|
.then(({ collection }) => {
|
||||||
@@ -24,9 +16,9 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleImportPostmanCollection = () => {
|
const handleImportPostmanCollection = () => {
|
||||||
importPostmanCollection(options)
|
importPostmanCollection()
|
||||||
.then(({ collection, translationLog }) => {
|
.then(({ collection }) => {
|
||||||
handleSubmit({ collection, translationLog });
|
handleSubmit({ collection });
|
||||||
})
|
})
|
||||||
.catch((err) => toastError(err, 'Postman Import collection failed'));
|
.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'));
|
.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 }) => {
|
const CollectionButton = ({ children, className, onClick }) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@@ -77,31 +60,6 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
|
|||||||
<CollectionButton onClick={handleImportInsomniaCollection}>Insomnia Collection</CollectionButton>
|
<CollectionButton onClick={handleImportInsomniaCollection}>Insomnia Collection</CollectionButton>
|
||||||
<CollectionButton onClick={handleImportOpenapiCollection}>OpenAPI V3 Spec</CollectionButton>
|
<CollectionButton onClick={handleImportOpenapiCollection}>OpenAPI V3 Spec</CollectionButton>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@@ -4,105 +4,8 @@ import { useFormik } from 'formik';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions';
|
import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import Modal from 'components/Modal';
|
import Modal from 'components/Modal';
|
||||||
import { IconAlertTriangle, IconArrowRight, IconCaretDown, IconCaretRight, IconCopy } from '@tabler/icons';
|
|
||||||
import toast from 'react-hot-toast';
|
|
||||||
|
|
||||||
const TranslationLog = ({ translationLog }) => {
|
const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) => {
|
||||||
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 inputRef = useRef();
|
const inputRef = useRef();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
@@ -150,9 +53,6 @@ const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName, trans
|
|||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-2">{collectionName}</div>
|
<div className="mt-2">{collectionName}</div>
|
||||||
{translationLog && Object.keys(translationLog).length > 0 && (
|
|
||||||
<TranslationLog translationLog={translationLog} />
|
|
||||||
)}
|
|
||||||
<>
|
<>
|
||||||
<label htmlFor="collectionLocation" className="block font-semibold mt-3">
|
<label htmlFor="collectionLocation" className="block font-semibold mt-3">
|
||||||
Location
|
Location
|
||||||
|
@@ -14,18 +14,14 @@ import StyledWrapper from './StyledWrapper';
|
|||||||
|
|
||||||
const TitleBar = () => {
|
const TitleBar = () => {
|
||||||
const [importedCollection, setImportedCollection] = useState(null);
|
const [importedCollection, setImportedCollection] = useState(null);
|
||||||
const [importedTranslationLog, setImportedTranslationLog] = useState({});
|
|
||||||
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
||||||
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
||||||
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
|
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
|
|
||||||
const handleImportCollection = ({ collection, translationLog }) => {
|
const handleImportCollection = ({ collection }) => {
|
||||||
setImportedCollection(collection);
|
setImportedCollection(collection);
|
||||||
if (translationLog) {
|
|
||||||
setImportedTranslationLog(translationLog);
|
|
||||||
}
|
|
||||||
setImportCollectionModalOpen(false);
|
setImportCollectionModalOpen(false);
|
||||||
setImportCollectionLocationModalOpen(true);
|
setImportCollectionLocationModalOpen(true);
|
||||||
};
|
};
|
||||||
@@ -75,7 +71,6 @@ const TitleBar = () => {
|
|||||||
{importCollectionLocationModalOpen ? (
|
{importCollectionLocationModalOpen ? (
|
||||||
<ImportCollectionLocation
|
<ImportCollectionLocation
|
||||||
collectionName={importedCollection.name}
|
collectionName={importedCollection.name}
|
||||||
translationLog={importedTranslationLog}
|
|
||||||
onClose={() => setImportCollectionLocationModalOpen(false)}
|
onClose={() => setImportCollectionLocationModalOpen(false)}
|
||||||
handleSubmit={handleImportCollectionLocation}
|
handleSubmit={handleImportCollectionLocation}
|
||||||
/>
|
/>
|
||||||
|
@@ -15,7 +15,6 @@ const Welcome = () => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [importedCollection, setImportedCollection] = useState(null);
|
const [importedCollection, setImportedCollection] = useState(null);
|
||||||
const [importedTranslationLog, setImportedTranslationLog] = useState({});
|
|
||||||
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
||||||
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
|
||||||
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = 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')));
|
dispatch(openCollection()).catch((err) => console.log(err) && toast.error(t('WELCOME.COLLECTION_OPEN_ERROR')));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImportCollection = ({ collection, translationLog }) => {
|
const handleImportCollection = ({ collection }) => {
|
||||||
setImportedCollection(collection);
|
setImportedCollection(collection);
|
||||||
if (translationLog) {
|
|
||||||
setImportedTranslationLog(translationLog);
|
|
||||||
}
|
|
||||||
setImportCollectionModalOpen(false);
|
setImportCollectionModalOpen(false);
|
||||||
setImportCollectionLocationModalOpen(true);
|
setImportCollectionLocationModalOpen(true);
|
||||||
};
|
};
|
||||||
@@ -55,7 +51,6 @@ const Welcome = () => {
|
|||||||
) : null}
|
) : null}
|
||||||
{importCollectionLocationModalOpen ? (
|
{importCollectionLocationModalOpen ? (
|
||||||
<ImportCollectionLocation
|
<ImportCollectionLocation
|
||||||
translationLog={importedTranslationLog}
|
|
||||||
collectionName={importedCollection.name}
|
collectionName={importedCollection.name}
|
||||||
onClose={() => setImportCollectionLocationModalOpen(false)}
|
onClose={() => setImportCollectionLocationModalOpen(false)}
|
||||||
handleSubmit={handleImportCollectionLocation}
|
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 each from 'lodash/each';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
import { customAlphabet } from 'nanoid';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
import { uuid, normalizeFileName } from 'utils/common';
|
|
||||||
import { isItemARequest } from 'utils/collections';
|
|
||||||
import { collectionSchema } from '@usebruno/schema';
|
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 = {}) => {
|
export const validateSchema = (collection = {}) => {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
collectionSchema
|
collectionSchema.validateSync(collection);
|
||||||
.validate(collection)
|
return collection;
|
||||||
.then(() => resolve(collection))
|
} catch (err) {
|
||||||
.catch((err) => {
|
throw new Error('The Collection has an invalid schema');
|
||||||
console.log(err);
|
}
|
||||||
reject(new BrunoError('The Collection file is corrupted'));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateUidsInCollection = (_collection) => {
|
export const updateUidsInCollection = (_collection) => {
|
||||||
@@ -117,3 +149,63 @@ export const hydrateSeqInCollection = (collection) => {
|
|||||||
|
|
||||||
return 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 each from 'lodash/each';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import fileDialog from 'file-dialog';
|
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid } from '../common';
|
||||||
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]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseGraphQL = (text) => {
|
const parseGraphQL = (text) => {
|
||||||
try {
|
try {
|
||||||
@@ -187,7 +159,7 @@ const transformInsomniaRequestItem = (request, index, allRequests) => {
|
|||||||
return brunoRequestItem;
|
return brunoRequestItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parseInsomniaCollection = (data) => {
|
const parseInsomniaCollection = (_insomniaCollection) => {
|
||||||
const brunoCollection = {
|
const brunoCollection = {
|
||||||
name: '',
|
name: '',
|
||||||
uid: uuid(),
|
uid: uuid(),
|
||||||
@@ -196,66 +168,61 @@ const parseInsomniaCollection = (data) => {
|
|||||||
environments: []
|
environments: []
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
try {
|
const insomniaExport = _insomniaCollection;
|
||||||
const insomniaExport = data;
|
const insomniaResources = get(insomniaExport, 'resources', []);
|
||||||
const insomniaResources = get(insomniaExport, 'resources', []);
|
const insomniaCollection = insomniaResources.find((resource) => resource._type === 'workspace');
|
||||||
const insomniaCollection = insomniaResources.find((resource) => resource._type === 'workspace');
|
|
||||||
|
|
||||||
if (!insomniaCollection) {
|
if (!insomniaCollection) {
|
||||||
reject(new BrunoError('Collection not found inside Insomnia export'));
|
throw new Error('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'));
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const importCollection = () => {
|
brunoCollection.name = insomniaCollection.name;
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fileDialog({ accept: '.json, .yaml, .yml, application/json, application/yaml, application/x-yaml' })
|
const requestsAndFolders =
|
||||||
.then(readFile)
|
insomniaResources.filter((resource) => resource._type === 'request' || resource._type === 'request_group') ||
|
||||||
.then(parseInsomniaCollection)
|
[];
|
||||||
.then(transformItemsInCollection)
|
|
||||||
.then(hydrateSeqInCollection)
|
function createFolderStructure(resources, parentId = null) {
|
||||||
.then(validateSchema)
|
const requestGroups =
|
||||||
.then((collection) => resolve({ collection }))
|
resources.filter((resource) => resource._type === 'request_group' && resource.parentId === parentId) || [];
|
||||||
.catch((err) => {
|
const requests = resources.filter((resource) => resource._type === 'request' && resource.parentId === parentId);
|
||||||
console.error(err);
|
|
||||||
reject(new BrunoError('Import collection failed: ' + err.message));
|
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 each from 'lodash/each';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import fileDialog from 'file-dialog';
|
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid } from '../common';
|
||||||
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]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const ensureUrl = (url) => {
|
const ensureUrl = (url) => {
|
||||||
// removing multiple slashes after the protocol if it exists, or after the beginning of the string otherwise
|
// 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: [],
|
items: [],
|
||||||
environments: []
|
environments: []
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
try {
|
try {
|
||||||
const collectionData = resolveRefs(data);
|
const collectionData = resolveRefs(data);
|
||||||
if (!collectionData) {
|
if (!collectionData) {
|
||||||
reject(new BrunoError('Invalid OpenAPI collection. Failed to resolve refs.'));
|
throw new Error('Invalid OpenAPI collection. Failed to resolve refs.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,7 +347,7 @@ export const parseOpenApiCollection = (data) => {
|
|||||||
|
|
||||||
// Assumes v3 if not defined. v2 is not supported yet
|
// Assumes v3 if not defined. v2 is not supported yet
|
||||||
if (collectionData.openapi && !collectionData.openapi.startsWith('3')) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -443,28 +413,24 @@ export const parseOpenApiCollection = (data) => {
|
|||||||
let ungroupedItems = ungroupedRequests.map(transformOpenapiRequestItem);
|
let ungroupedItems = ungroupedRequests.map(transformOpenapiRequestItem);
|
||||||
let brunoCollectionItems = brunoFolders.concat(ungroupedItems);
|
let brunoCollectionItems = brunoFolders.concat(ungroupedItems);
|
||||||
brunoCollection.items = brunoCollectionItems;
|
brunoCollection.items = brunoCollectionItems;
|
||||||
resolve(brunoCollection);
|
return brunoCollection;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(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 = () => {
|
export const openApiToBruno = (openApiSpecification) => {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
fileDialog({ accept: '.json, .yaml, .yml, application/json, application/yaml, application/x-yaml' })
|
const collection = parseOpenApiCollection(openApiSpecification);
|
||||||
.then(readFile)
|
const transformedCollection = transformItemsInCollection(collection);
|
||||||
.then(parseOpenApiCollection)
|
const hydratedCollection = hydrateSeqInCollection(transformedCollection);
|
||||||
.then(transformItemsInCollection)
|
const validatedCollection = validateSchema(hydratedCollection);
|
||||||
.then(hydrateSeqInCollection)
|
return validatedCollection
|
||||||
.then(validateSchema)
|
} catch (err) {
|
||||||
.then((collection) => resolve({ collection }))
|
console.error(err);
|
||||||
.catch((err) => {
|
throw new Error('Import collection failed');
|
||||||
console.error(err);
|
}
|
||||||
reject(new BrunoError('Import collection failed: ' + err.message));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default importCollection;
|
export default openApiToBruno;
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import map from 'lodash/map';
|
import map from 'lodash/map';
|
||||||
import * as FileSaver from 'file-saver';
|
import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems } from '../common';
|
||||||
import { deleteSecretsInEnvs, deleteUidsInEnvs, deleteUidsInItems } from '../collections/export';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms a given URL string into an object representing the protocol, host, path, query, and variables.
|
* 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;
|
return sanitizedUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const exportCollection = (collection) => {
|
export const brunoToPostman = (collection) => {
|
||||||
delete collection.uid;
|
delete collection.uid;
|
||||||
delete collection.processEnvVariables;
|
delete collection.processEnvVariables;
|
||||||
deleteUidsInItems(collection.items);
|
deleteUidsInItems(collection.items);
|
||||||
@@ -335,11 +334,7 @@ export const exportCollection = (collection) => {
|
|||||||
collectionToExport.info = generateInfoSection();
|
collectionToExport.info = generateInfoSection();
|
||||||
collectionToExport.item = generateItemSection(collection.items);
|
collectionToExport.item = generateItemSection(collection.items);
|
||||||
collectionToExport.variable = generateCollectionVars(collection);
|
collectionToExport.variable = generateCollectionVars(collection);
|
||||||
|
return collectionToExport;
|
||||||
const fileName = `${collection.name}.json`;
|
|
||||||
const fileBlob = new Blob([JSON.stringify(collectionToExport, null, 2)], { type: 'application/json' });
|
|
||||||
|
|
||||||
FileSaver.saveAs(fileBlob, fileName);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default exportCollection;
|
export default brunoToPostman;
|
||||||
|
@@ -1,16 +1,4 @@
|
|||||||
import each from 'lodash/each';
|
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) => {
|
const isSecret = (type) => {
|
||||||
return type === 'secret';
|
return type === 'secret';
|
||||||
};
|
};
|
||||||
@@ -40,42 +28,13 @@ const importPostmanEnvironment = (environment) => {
|
|||||||
return brunoEnvironment;
|
return brunoEnvironment;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parsePostmanEnvironment = (str) => {
|
export const postmanToBrunoEnvironment = (postmanEnvironment) => {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
try {
|
return importPostmanEnvironment(postmanEnvironment);
|
||||||
let environment = JSON.parse(str);
|
} catch (err) {
|
||||||
return resolve(importPostmanEnvironment(environment));
|
console.log(err);
|
||||||
} catch (err) {
|
throw new Error('Unable to parse the postman environment json file');
|
||||||
console.log(err);
|
}
|
||||||
if (err instanceof BrunoError) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
return reject(new BrunoError('Unable to parse the postman environment json file'));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const importEnvironment = () => {
|
export default postmanToBrunoEnvironment;
|
||||||
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;
|
|
||||||
|
@@ -1,19 +1,7 @@
|
|||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import fileDialog from 'file-dialog';
|
import { validateSchema, transformItemsInCollection, hydrateSeqInCollection, uuid } from '../common';
|
||||||
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 each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
|
import postmanTranslation from './postman-translations';
|
||||||
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 parseGraphQLRequest = (graphqlSource) => {
|
const parseGraphQLRequest = (graphqlSource) => {
|
||||||
try {
|
try {
|
||||||
@@ -95,28 +83,7 @@ const constructUrl = (url) => {
|
|||||||
return '';
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
let translationLog = {};
|
const importScriptsFromEvents = (events, requestObject) => {
|
||||||
|
|
||||||
/* 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) => {
|
|
||||||
events.forEach((event) => {
|
events.forEach((event) => {
|
||||||
if (event.script && event.script.exec) {
|
if (event.script && event.script.exec) {
|
||||||
if (event.listen === 'prerequest') {
|
if (event.listen === 'prerequest') {
|
||||||
@@ -124,22 +91,12 @@ const importScriptsFromEvents = (events, requestObject, options, pushTranslation
|
|||||||
requestObject.script = {};
|
requestObject.script = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(event.script.exec)) {
|
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||||
if (event.script.exec.length > 0) {
|
requestObject.script.req = event.script.exec
|
||||||
requestObject.script.req = event.script.exec
|
.map((line) => postmanTranslation(line))
|
||||||
.map((line, index) =>
|
.join('\n');
|
||||||
options.enablePostmanTranslations.enabled
|
|
||||||
? postmanTranslation(line, () => pushTranslationLog('script', index))
|
|
||||||
: `// ${line}`
|
|
||||||
)
|
|
||||||
.join('\n');
|
|
||||||
} else {
|
|
||||||
requestObject.script.req = '';
|
|
||||||
}
|
|
||||||
} else if (typeof event.script.exec === 'string') {
|
} else if (typeof event.script.exec === 'string') {
|
||||||
requestObject.script.req = options.enablePostmanTranslations.enabled
|
requestObject.script.req = postmanTranslation(event.script.exec);
|
||||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('script', 0))
|
|
||||||
: `// ${event.script.exec}`;
|
|
||||||
} else {
|
} else {
|
||||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
||||||
}
|
}
|
||||||
@@ -150,22 +107,12 @@ const importScriptsFromEvents = (events, requestObject, options, pushTranslation
|
|||||||
requestObject.tests = {};
|
requestObject.tests = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(event.script.exec)) {
|
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||||
if (event.script.exec.length > 0) {
|
requestObject.tests = event.script.exec
|
||||||
requestObject.tests = event.script.exec
|
.map((line) => postmanTranslation(line))
|
||||||
.map((line, index) =>
|
.join('\n');
|
||||||
options.enablePostmanTranslations.enabled
|
|
||||||
? postmanTranslation(line, () => pushTranslationLog('test', index))
|
|
||||||
: `// ${line}`
|
|
||||||
)
|
|
||||||
.join('\n');
|
|
||||||
} else {
|
|
||||||
requestObject.tests = '';
|
|
||||||
}
|
|
||||||
} else if (typeof event.script.exec === 'string') {
|
} else if (typeof event.script.exec === 'string') {
|
||||||
requestObject.tests = options.enablePostmanTranslations.enabled
|
return postmanTranslation(event.script.exec);
|
||||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('test', 0))
|
|
||||||
: `// ${event.script.exec}`;
|
|
||||||
} else {
|
} else {
|
||||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
||||||
}
|
}
|
||||||
@@ -185,7 +132,7 @@ const importCollectionLevelVariables = (variables, requestObject) => {
|
|||||||
requestObject.vars.req = vars;
|
requestObject.vars.req = vars;
|
||||||
};
|
};
|
||||||
|
|
||||||
const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) => {
|
const importPostmanV2CollectionItem = (brunoParent, item, parentAuth) => {
|
||||||
brunoParent.items = brunoParent.items || [];
|
brunoParent.items = brunoParent.items || [];
|
||||||
const folderMap = {};
|
const folderMap = {};
|
||||||
const requestMap = {};
|
const requestMap = {};
|
||||||
@@ -227,11 +174,11 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) =
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (i.item && i.item.length) {
|
if (i.item && i.item.length) {
|
||||||
importPostmanV2CollectionItem(brunoFolderItem, i.item, i.auth ?? parentAuth, options);
|
importPostmanV2CollectionItem(brunoFolderItem, i.item, i.auth ?? parentAuth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i.event) {
|
if (i.event) {
|
||||||
importScriptsFromEvents(i.event, brunoFolderItem.root.request, options, pushTranslationLog);
|
importScriptsFromEvents(i.event, brunoFolderItem.root.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
brunoParent.items.push(brunoFolderItem);
|
brunoParent.items.push(brunoFolderItem);
|
||||||
@@ -288,22 +235,12 @@ const importPostmanV2CollectionItem = (brunoParent, item, parentAuth, options) =
|
|||||||
if (!brunoRequestItem.request.script) {
|
if (!brunoRequestItem.request.script) {
|
||||||
brunoRequestItem.request.script = {};
|
brunoRequestItem.request.script = {};
|
||||||
}
|
}
|
||||||
if (Array.isArray(event.script.exec)) {
|
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||||
if (event.script.exec.length > 0) {
|
brunoRequestItem.request.script.req = event.script.exec
|
||||||
brunoRequestItem.request.script.req = event.script.exec
|
.map((line) => postmanTranslation(line))
|
||||||
.map((line, index) =>
|
.join('\n');
|
||||||
options.enablePostmanTranslations.enabled
|
|
||||||
? postmanTranslation(line, () => pushTranslationLog('script', index))
|
|
||||||
: `// ${line}`
|
|
||||||
)
|
|
||||||
.join('\n');
|
|
||||||
} else {
|
|
||||||
brunoRequestItem.request.script.req = '';
|
|
||||||
}
|
|
||||||
} else if (typeof event.script.exec === 'string') {
|
} else if (typeof event.script.exec === 'string') {
|
||||||
brunoRequestItem.request.script.req = options.enablePostmanTranslations.enabled
|
brunoRequestItem.request.script.req = postmanTranslation(event.script.exec);
|
||||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('script', 0))
|
|
||||||
: `// ${event.script.exec}`;
|
|
||||||
} else {
|
} else {
|
||||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
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) {
|
if (!brunoRequestItem.request.tests) {
|
||||||
brunoRequestItem.request.tests = {};
|
brunoRequestItem.request.tests = {};
|
||||||
}
|
}
|
||||||
if (Array.isArray(event.script.exec)) {
|
if (Array.isArray(event.script.exec) && event.script.exec.length > 0) {
|
||||||
if (event.script.exec.length > 0) {
|
|
||||||
brunoRequestItem.request.tests = event.script.exec
|
brunoRequestItem.request.tests = event.script.exec
|
||||||
.map((line, index) =>
|
.map((line) => postmanTranslation(line))
|
||||||
options.enablePostmanTranslations.enabled
|
|
||||||
? postmanTranslation(line, () => pushTranslationLog('test', index))
|
|
||||||
: `// ${line}`
|
|
||||||
)
|
|
||||||
.join('\n');
|
.join('\n');
|
||||||
} else {
|
|
||||||
brunoRequestItem.request.tests = '';
|
|
||||||
}
|
|
||||||
} else if (typeof event.script.exec === 'string') {
|
} else if (typeof event.script.exec === 'string') {
|
||||||
brunoRequestItem.request.tests = options.enablePostmanTranslations.enabled
|
return postmanTranslation(event.script.exec);
|
||||||
? postmanTranslation(event.script.exec, () => pushTranslationLog('test', 0))
|
|
||||||
: `// ${event.script.exec}`;
|
|
||||||
} else {
|
} else {
|
||||||
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
console.warn('Unexpected event.script.exec type', typeof event.script.exec);
|
||||||
}
|
}
|
||||||
@@ -559,7 +486,7 @@ const searchLanguageByHeader = (headers) => {
|
|||||||
return contentType;
|
return contentType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const importPostmanV2Collection = (collection, options) => {
|
const importPostmanV2Collection = (collection) => {
|
||||||
const brunoCollection = {
|
const brunoCollection = {
|
||||||
name: collection.info.name || 'Untitled Collection',
|
name: collection.info.name || 'Untitled Collection',
|
||||||
uid: uuid(),
|
uid: uuid(),
|
||||||
@@ -587,81 +514,55 @@ const importPostmanV2Collection = (collection, options) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (collection.event) {
|
if (collection.event) {
|
||||||
importScriptsFromEvents(collection.event, brunoCollection.root.request, options, pushTranslationLog);
|
importScriptsFromEvents(collection.event, brunoCollection.root.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collection?.variable){
|
if (collection?.variable){
|
||||||
importCollectionLevelVariables(collection.variable, brunoCollection.root.request);
|
importCollectionLevelVariables(collection.variable, brunoCollection.root.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
importPostmanV2CollectionItem(brunoCollection, collection.item, collection.auth, options);
|
importPostmanV2CollectionItem(brunoCollection, collection.item, collection.auth);
|
||||||
|
|
||||||
return brunoCollection;
|
return brunoCollection;
|
||||||
};
|
};
|
||||||
|
|
||||||
const parsePostmanCollection = (str, options) => {
|
const parsePostmanCollection = (collection) => {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
try {
|
let schema = get(collection, 'info.schema');
|
||||||
let collection = JSON.parse(str);
|
|
||||||
let schema = get(collection, 'info.schema');
|
|
||||||
|
|
||||||
let v2Schemas = [
|
let v2Schemas = [
|
||||||
'https://schema.getpostman.com/json/collection/v2.0.0/collection.json',
|
'https://schema.getpostman.com/json/collection/v2.0.0/collection.json',
|
||||||
'https://schema.getpostman.com/json/collection/v2.1.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.0.0/collection.json',
|
||||||
'https://schema.postman.com/json/collection/v2.1.0/collection.json'
|
'https://schema.postman.com/json/collection/v2.1.0/collection.json'
|
||||||
];
|
];
|
||||||
|
|
||||||
if (v2Schemas.includes(schema)) {
|
if (v2Schemas.includes(schema)) {
|
||||||
return resolve(importPostmanV2Collection(collection, options));
|
return importPostmanV2Collection(collection);
|
||||||
}
|
|
||||||
|
|
||||||
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'));
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const logTranslationDetails = (translationLog) => {
|
throw new Error('Unknown postman schema');
|
||||||
if (Object.keys(translationLog || {}).length > 0) {
|
} catch (err) {
|
||||||
console.warn(
|
console.log(err);
|
||||||
`[Postman Translation Logs]
|
if (err instanceof Error) {
|
||||||
Collections incomplete : ${Object.keys(translationLog || {}).length}` +
|
throw err;
|
||||||
`\nTotal lines incomplete : ${Object.values(translationLog || {}).reduce(
|
}
|
||||||
(acc, curr) => acc + (curr.script?.length || 0) + (curr.test?.length || 0),
|
|
||||||
0
|
throw new Error('Unable to parse the postman collection json file');
|
||||||
)}` +
|
|
||||||
`\nSee details below :`,
|
|
||||||
translationLog
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const importCollection = (options) => {
|
const postmanToBruno = (postmanCollection) => {
|
||||||
return new Promise((resolve, reject) => {
|
try {
|
||||||
fileDialog({ accept: 'application/json' })
|
const parsedPostmanCollection = parsePostmanCollection(postmanCollection);
|
||||||
.then(readFile)
|
const transformedCollection = transformItemsInCollection(parsedPostmanCollection);
|
||||||
.then((str) => parsePostmanCollection(str, options))
|
const hydratedCollection = hydrateSeqInCollection(transformedCollection);
|
||||||
.then(transformItemsInCollection)
|
const validatedCollection = validateSchema(hydratedCollection);
|
||||||
.then(hydrateSeqInCollection)
|
return ({ collection: validatedCollection });
|
||||||
.then(validateSchema)
|
} catch(err) {
|
||||||
.then((collection) => resolve({ collection, translationLog }))
|
console.log(err);
|
||||||
.catch((err) => {
|
throw new Error('Import collection failed');
|
||||||
console.log(err);
|
}
|
||||||
translationLog = {};
|
|
||||||
reject(new BrunoError('Import collection failed'));
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
logTranslationDetails(translationLog);
|
|
||||||
translationLog = {};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default importCollection;
|
export default postmanToBruno;
|
@@ -42,7 +42,7 @@ const compiledReplacements = Object.entries(extendedReplacements).map(([pattern,
|
|||||||
replacement
|
replacement
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const postmanTranslation = (script, logCallback) => {
|
const postmanTranslation = (script) => {
|
||||||
try {
|
try {
|
||||||
let modifiedScript = script;
|
let modifiedScript = script;
|
||||||
let modified = false;
|
let modified = false;
|
||||||
@@ -54,10 +54,11 @@ export const postmanTranslation = (script, logCallback) => {
|
|||||||
}
|
}
|
||||||
if (modifiedScript.includes('pm.') || modifiedScript.includes('postman.')) {
|
if (modifiedScript.includes('pm.') || modifiedScript.includes('postman.')) {
|
||||||
modifiedScript = modifiedScript.replace(/^(.*(pm\.|postman\.).*)$/gm, '// $1');
|
modifiedScript = modifiedScript.replace(/^(.*(pm\.|postman\.).*)$/gm, '// $1');
|
||||||
//logCallback?.();
|
|
||||||
}
|
}
|
||||||
return modifiedScript;
|
return modifiedScript;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return script;
|
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', () => {
|
describe('transformUrl', () => {
|
||||||
it('should handle basic URL with path variables', () => {
|
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', () => {
|
describe('postmanTranslation function', () => {
|
||||||
test('should translate pm commands correctly', () => {
|
test('should translate pm commands correctly', () => {
|
||||||
@@ -11,9 +11,6 @@ describe('postmanTranslation function', () => {
|
|||||||
pm.collectionVariables.set('key', 'value');
|
pm.collectionVariables.set('key', 'value');
|
||||||
const data = pm.response.json();
|
const data = pm.response.json();
|
||||||
pm.expect(pm.environment.has('key')).to.be.true;
|
pm.expect(pm.environment.has('key')).to.be.true;
|
||||||
postman.setEnvironmentVariable('key', 'value');
|
|
||||||
postman.getEnvironmentVariable('key');
|
|
||||||
postman.clearEnvironmentVariable('key');
|
|
||||||
`;
|
`;
|
||||||
const expectedOutput = `
|
const expectedOutput = `
|
||||||
bru.getEnvVar('key');
|
bru.getEnvVar('key');
|
||||||
@@ -24,9 +21,6 @@ describe('postmanTranslation function', () => {
|
|||||||
bru.setVar('key', 'value');
|
bru.setVar('key', 'value');
|
||||||
const data = res.getBody();
|
const data = res.getBody();
|
||||||
expect(bru.getEnvVar('key') !== undefined && bru.getEnvVar('key') !== null).to.be.true;
|
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);
|
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
||||||
});
|
});
|
||||||
@@ -157,13 +151,3 @@ test('should handle response commands', () => {
|
|||||||
`;
|
`;
|
||||||
expect(postmanTranslation(inputScript)).toBe(expectedOutput);
|
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:graphql-docs', 'Building graphql-docs');
|
||||||
execCommand('npm run build:bruno-query', 'Building bruno-query');
|
execCommand('npm run build:bruno-query', 'Building bruno-query');
|
||||||
execCommand('npm run build:bruno-common', 'Building bruno-common');
|
execCommand('npm run build:bruno-common', 'Building bruno-common');
|
||||||
|
execCommand('npm run build:bruno-converters', 'Building bruno-converters');
|
||||||
|
|
||||||
// Bundle JS sandbox libraries
|
// Bundle JS sandbox libraries
|
||||||
execCommand(
|
execCommand(
|
||||||
|
Reference in New Issue
Block a user