From 92ac91733ea2aa647504db70dee42d7495d870cc Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Tue, 17 Sep 2024 05:58:21 -0700 Subject: [PATCH] Handle Postman URL query and variable fields --- plugins/importer-postman/src/index.ts | 46 ++++-- .../{nested.json => nested.input.json} | 0 .../tests/fixtures/nested.output.json | 77 ++++++++++ .../tests/fixtures/params.input.json | 136 ++++++++++++++++++ .../tests/fixtures/params.output.json | 90 ++++++++++++ plugins/importer-postman/tests/index.test.ts | 73 ++-------- .../package-lock.json | 7 +- 7 files changed, 356 insertions(+), 73 deletions(-) rename plugins/importer-postman/tests/fixtures/{nested.json => nested.input.json} (100%) create mode 100644 plugins/importer-postman/tests/fixtures/nested.output.json create mode 100644 plugins/importer-postman/tests/fixtures/params.input.json create mode 100644 plugins/importer-postman/tests/fixtures/params.output.json diff --git a/plugins/importer-postman/src/index.ts b/plugins/importer-postman/src/index.ts index 3ab59a55..229901d0 100644 --- a/plugins/importer-postman/src/index.ts +++ b/plugins/importer-postman/src/index.ts @@ -1,4 +1,13 @@ -import { Environment, Folder, HttpRequest, HttpRequestHeader, Model, Workspace, Context } from '@yaakapp/api'; +import { + Environment, + Folder, + HttpRequest, + HttpRequestHeader, + Model, + Workspace, + Context, + HttpUrlParameter, +} from '@yaakapp/api'; const POSTMAN_2_1_0_SCHEMA = 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'; const POSTMAN_2_0_0_SCHEMA = 'https://schema.getpostman.com/json/collection/v2.0.0/collection.json'; @@ -84,6 +93,8 @@ export function pluginHookImport( headers.push(bodyPatchHeader); } + const { url, urlParameters } = convertUrl(r.url); + const request: ExportResources['httpRequests'][0] = { model: 'http_request', id: generateId('http_request'), @@ -91,7 +102,8 @@ export function pluginHookImport( folderId, name: v.name, method: r.method || 'GET', - url: typeof r.url === 'string' ? r.url : convertUrl(toRecord(r.url)), + url, + urlParameters, body: bodyPatch.body, bodyType: bodyPatch.bodyType, authentication: authPatch.authentication, @@ -111,11 +123,13 @@ export function pluginHookImport( return { resources: convertTemplateSyntax(exportResources) }; } -function convertUrl(url: Record) { - if ('raw' in url) { - return url.raw; +function convertUrl(url: string | any): Pick { + if (typeof url === 'string') { + return { url, urlParameters: [] }; } + url = toRecord(url); + let v = ''; if ('protocol' in url && typeof url.protocol === 'string') { @@ -134,9 +148,25 @@ function convertUrl(url: Record) { v += `/${Array.isArray(url.path) ? url.path.join('/') : url.path}`; } + const params: HttpUrlParameter[] = []; if ('query' in url && Array.isArray(url.query) && url.query.length > 0) { - const qs = url.query.map(q => `${q.key ?? ''}=${q.value ?? ''}`).join('&'); - v += `?${qs}`; + for (const query of url.query) { + params.push({ + name: query.key ?? '', + value: query.value ?? '', + enabled: !query.disabled, + }); + } + } + + if ('variable' in url && Array.isArray(url.variable) && url.variable.length > 0) { + for (const v of url.variable) { + params.push({ + name: ':' + (v.key ?? ''), + value: v.value ?? '', + enabled: !v.disabled, + }); + } } if ('hash' in url && typeof url.hash === 'string') { @@ -145,7 +175,7 @@ function convertUrl(url: Record) { // TODO: Implement url.variables (path variables) - return v; + return { url: v, urlParameters: params }; } function importAuth( diff --git a/plugins/importer-postman/tests/fixtures/nested.json b/plugins/importer-postman/tests/fixtures/nested.input.json similarity index 100% rename from plugins/importer-postman/tests/fixtures/nested.json rename to plugins/importer-postman/tests/fixtures/nested.input.json diff --git a/plugins/importer-postman/tests/fixtures/nested.output.json b/plugins/importer-postman/tests/fixtures/nested.output.json new file mode 100644 index 00000000..9b7cc2c5 --- /dev/null +++ b/plugins/importer-postman/tests/fixtures/nested.output.json @@ -0,0 +1,77 @@ +{ + "resources": { + "workspaces": [ + { + "model": "workspace", + "id": "GENERATE_ID::WORKSPACE_0", + "name": "New Collection", + "description": "", + "variables": [] + } + ], + "environments": [], + "httpRequests": [ + { + "model": "http_request", + "id": "GENERATE_ID::HTTP_REQUEST_0", + "workspaceId": "GENERATE_ID::WORKSPACE_0", + "folderId": "GENERATE_ID::FOLDER_1", + "name": "Request 1", + "method": "GET", + "url": "", + "urlParameters": [], + "body": {}, + "bodyType": null, + "authentication": {}, + "authenticationType": null, + "headers": [] + }, + { + "model": "http_request", + "id": "GENERATE_ID::HTTP_REQUEST_1", + "workspaceId": "GENERATE_ID::WORKSPACE_0", + "folderId": "GENERATE_ID::FOLDER_0", + "name": "Request 2", + "method": "GET", + "url": "", + "urlParameters": [], + "body": {}, + "bodyType": null, + "authentication": {}, + "authenticationType": null, + "headers": [] + }, + { + "model": "http_request", + "id": "GENERATE_ID::HTTP_REQUEST_2", + "workspaceId": "GENERATE_ID::WORKSPACE_0", + "folderId": null, + "name": "Request 3", + "method": "GET", + "url": "", + "urlParameters": [], + "body": {}, + "bodyType": null, + "authentication": {}, + "authenticationType": null, + "headers": [] + } + ], + "folders": [ + { + "model": "folder", + "workspaceId": "GENERATE_ID::WORKSPACE_0", + "id": "GENERATE_ID::FOLDER_0", + "name": "Top Folder", + "folderId": null + }, + { + "model": "folder", + "workspaceId": "GENERATE_ID::WORKSPACE_0", + "id": "GENERATE_ID::FOLDER_1", + "name": "Nested Folder", + "folderId": "GENERATE_ID::FOLDER_0" + } + ] + } +} diff --git a/plugins/importer-postman/tests/fixtures/params.input.json b/plugins/importer-postman/tests/fixtures/params.input.json new file mode 100644 index 00000000..f2969d24 --- /dev/null +++ b/plugins/importer-postman/tests/fixtures/params.input.json @@ -0,0 +1,136 @@ +{ + "info": { + "_postman_id": "9e6dfada-256c-49ea-a38f-7d1b05b7ca2d", + "name": "New Collection", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "18798" + }, + "item": [ + { + "name": "Form URL", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "baeare", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "X-foo", + "value": "bar", + "description": "description" + }, + { + "key": "Disabled", + "value": "tnroant", + "description": "ntisorantosra", + "disabled": true + } + ], + "body": { + "mode": "formdata", + "formdata": [ + { + "key": "Key", + "contentType": "Custom/COntent", + "description": "DEscription", + "type": "file", + "src": "/Users/gschier/Desktop/Screenshot 2024-05-31 at 12.05.11 PM.png" + } + ] + }, + "url": { + "raw": "example.com/:foo/:bar?q=qqq&", + "host": [ + "example", + "com" + ], + "path": [ + ":foo", + ":bar" + ], + "query": [ + { + "key": "disabled", + "value": "secondvalue", + "description": "this is disabled", + "disabled": true + }, + { + "key": "q", + "value": "qqq", + "description": "hello" + }, + { + "key": "", + "value": null + } + ], + "variable": [ + { + "key": "foo", + "value": "fff", + "description": "Description" + }, + { + "key": "bar", + "value": "bbb", + "description": "bbb description" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "globalpass", + "type": "string" + }, + { + "key": "username", + "value": "globaluser", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "COLLECTION VARIABLE", + "value": "collection variable", + "type": "string" + } + ] +} diff --git a/plugins/importer-postman/tests/fixtures/params.output.json b/plugins/importer-postman/tests/fixtures/params.output.json new file mode 100644 index 00000000..2ad692ae --- /dev/null +++ b/plugins/importer-postman/tests/fixtures/params.output.json @@ -0,0 +1,90 @@ +{ + "resources": { + "workspaces": [ + { + "model": "workspace", + "id": "GENERATE_ID::WORKSPACE_1", + "name": "New Collection", + "description": "", + "variables": [ + { + "name": "COLLECTION VARIABLE", + "value": "collection variable" + } + ] + } + ], + "environments": [], + "httpRequests": [ + { + "model": "http_request", + "id": "GENERATE_ID::HTTP_REQUEST_3", + "workspaceId": "GENERATE_ID::WORKSPACE_1", + "folderId": null, + "name": "Form URL", + "method": "POST", + "url": "example.com/:foo/:bar", + "urlParameters": [ + { + "name": "disabled", + "value": "secondvalue", + "enabled": false + }, + { + "name": "q", + "value": "qqq", + "enabled": true + }, + { + "name": "", + "value": "", + "enabled": true + }, + { + "name": ":foo", + "value": "fff", + "enabled": true + }, + { + "name": ":bar", + "value": "bbb", + "enabled": true + } + ], + "body": { + "form": [ + { + "enabled": true, + "contentType": "Custom/COntent", + "name": "Key", + "file": "/Users/gschier/Desktop/Screenshot 2024-05-31 at 12.05.11 PM.png" + } + ] + }, + "bodyType": "multipart/form-data", + "authentication": { + "token": "" + }, + "authenticationType": "bearer", + "headers": [ + { + "name": "X-foo", + "value": "bar", + "enabled": true + }, + { + "name": "Disabled", + "value": "tnroant", + "enabled": false + }, + { + "name": "Content-Type", + "value": "multipart/form-data", + "enabled": true + } + ] + } + ], + "folders": [] + } +} diff --git a/plugins/importer-postman/tests/index.test.ts b/plugins/importer-postman/tests/index.test.ts index 0ab87673..35066269 100644 --- a/plugins/importer-postman/tests/index.test.ts +++ b/plugins/importer-postman/tests/index.test.ts @@ -1,4 +1,4 @@ -import { Context, Model } from '@yaakapp/api'; +import { Context } from '@yaakapp/api'; import * as fs from 'node:fs'; import * as path from 'node:path'; import { describe, expect, test } from 'vitest'; @@ -11,71 +11,16 @@ describe('importer-postman', () => { const fixtures = fs.readdirSync(p); for (const fixture of fixtures) { + if (fixture.includes('.output')) { + continue; + } + test('Imports ' + fixture, () => { const contents = fs.readFileSync(path.join(p, fixture), 'utf-8'); - const imported = pluginHookImport(ctx, contents); - const folder0 = newId('folder'); - const folder1 = newId('folder'); - expect(imported).toEqual({ - resources: expect.objectContaining({ - workspaces: [ - expect.objectContaining({ - id: newId('workspace'), - model: 'workspace', - name: 'New Collection', - }), - ], - folders: expect.arrayContaining([ - expect.objectContaining({ - id: folder0, - model: 'folder', - workspaceId: existingId('workspace'), - name: 'Top Folder', - }), - expect.objectContaining({ - folderId: folder0, - id: folder1, - model: 'folder', - workspaceId: existingId('workspace'), - name: 'Nested Folder', - }), - ]), - httpRequests: expect.arrayContaining([ - expect.objectContaining({ - id: newId('http_request'), - model: 'http_request', - name: 'Request 1', - workspaceId: existingId('workspace'), - folderId: folder1, - }), - expect.objectContaining({ - id: newId('http_request'), - model: 'http_request', - name: 'Request 2', - workspaceId: existingId('workspace'), - folderId: folder0, - }), - expect.objectContaining({ - id: newId('http_request'), - model: 'http_request', - name: 'Request 3', - workspaceId: existingId('workspace'), - folderId: null, - }), - ]), - }), - }); + const expected = fs.readFileSync(path.join(p, fixture.replace('.input', '.output')), 'utf-8'); + const result = pluginHookImport(ctx, contents); + // console.log(JSON.stringify(result, null, 2)) + expect(result).toEqual(JSON.parse(expected)); }); } }); - -const idCount: Partial> = {}; - -function newId(model: Model['model']): string { - idCount[model] = (idCount[model] ?? -1) + 1; - return `GENERATE_ID::${model.toUpperCase()}_${idCount[model]}`; -} - -function existingId(model: Model['model']): string { - return `GENERATE_ID::${model.toUpperCase()}_${idCount[model] ?? 0}`; -} diff --git a/plugins/template-function-response/package-lock.json b/plugins/template-function-response/package-lock.json index a72e2c38..b0871814 100644 --- a/plugins/template-function-response/package-lock.json +++ b/plugins/template-function-response/package-lock.json @@ -10,13 +10,13 @@ "dependencies": { "@xmldom/xmldom": "^0.8.10", "@yaakapp/api": "^0.1.14", - "@yaakapp/cli": "^0.0.42", "jsonpath-plus": "^9.0.0", "xpath": "^0.0.34" }, "devDependencies": { "@types/jsonpath": "^0.2.4", "@types/node": "^20.14.9", + "@yaakapp/cli": "^0.0.42", "typescript": "^5.5.2", "vitest": "^1.4.0" } @@ -766,6 +766,7 @@ "version": "0.0.42", "resolved": "https://registry.npmjs.org/@yaakapp/cli/-/cli-0.0.42.tgz", "integrity": "sha512-HFkg49sksZNQQpnOgZGfyh8pmHbxtkgSNCeEMlaSFezq42YZPHxOPlqTEGxk3JqX6Asz0YO2xJDfUADQCyKNYA==", + "dev": true, "hasInstallScript": true, "bin": { "yaakcli": "bin/cli.js" @@ -781,6 +782,7 @@ "version": "0.0.42", "resolved": "https://registry.npmjs.org/@yaakapp/cli-darwin-arm64/-/cli-darwin-arm64-0.0.42.tgz", "integrity": "sha512-l8+N/9jwvAYlMQBPfGzNkVoQsYeBtwM3/7ix5b6mT+3zcwrNIDW9HQTEZ2ZTNdo1H548U1F6ppvhAyOdOtIyLg==", + "dev": true, "optional": true, "os": [ "darwin" @@ -790,6 +792,7 @@ "version": "0.0.42", "resolved": "https://registry.npmjs.org/@yaakapp/cli-darwin-x64/-/cli-darwin-x64-0.0.42.tgz", "integrity": "sha512-grm9UOVCNIpHO3XsEzvvoic43cYCxmuvrUFP/8MZLQgZeQ5L6EBTAlCTtXD2hUGW60+kNNwcgPrDVVrP7Wn2YQ==", + "dev": true, "optional": true, "os": [ "darwin" @@ -799,6 +802,7 @@ "version": "0.0.42", "resolved": "https://registry.npmjs.org/@yaakapp/cli-linux-x64/-/cli-linux-x64-0.0.42.tgz", "integrity": "sha512-O4ly25zR0BVIN0KxUcc7hmmcdNiRq4tQACuYNMIQ2ppFJYCguSMmGFdeJuyCfvcC/SwJIK6/Kzkr8EAmaTjDOA==", + "dev": true, "optional": true, "os": [ "linux" @@ -808,6 +812,7 @@ "version": "0.0.42", "resolved": "https://registry.npmjs.org/@yaakapp/cli-win32-x64/-/cli-win32-x64-0.0.42.tgz", "integrity": "sha512-40BTVcOBIP8VYwD1wfrr6tXG6NQuGz+XDA/ean4AWQWHi1P7BWHC9/uqHlMTLhFvbjcHjtwAl7bzVrXr37E0YQ==", + "dev": true, "optional": true, "os": [ "win32"