Skip to content

Commit

Permalink
Adding Postman Collection support to oas-update functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinswiber committed Apr 4, 2023
1 parent 6b3f426 commit 0589174
Show file tree
Hide file tree
Showing 9 changed files with 4,736 additions and 28 deletions.
2 changes: 2 additions & 0 deletions projects/optic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"@types/log": "^6.3.0",
"@types/node": "^18.0.0",
"@types/picomatch": "^2.3.0",
"@types/postman-collection": "^3.5.7",
"@types/prompts": "^2",
"@types/semver": "^7.3.10",
"@types/slice-ansi": "^4",
Expand Down Expand Up @@ -94,6 +95,7 @@
"picomatch": "^2.3.1",
"pluralize": "8.0.0",
"portfinder": "^1.0.28",
"postman-collection": "^4.1.7",
"prompts": "^2.4.2",
"semver": "^7.3.8",
"slice-ansi": "^4.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,270 @@ exports[`CapturedIntearction.fromHarEntry supports response body encoding for su
}
`;
exports[`CapturedInteraction.fromPostmanEntry can create a CapturedInteraction from a PostmanEntry 1`] = `
{
"request": {
"body": {
"contentType": null,
"size": 0,
"stream": Readable {
"_events": {},
"_eventsCount": 0,
"_maxListeners": undefined,
"_read": [Function],
"_readableState": ReadableState {
"autoDestroy": true,
"awaitDrainWriters": null,
"buffer": BufferList {
"head": null,
"length": 0,
"tail": null,
},
"closeEmitted": false,
"closed": false,
"constructed": true,
"dataEmitted": false,
"decoder": null,
"defaultEncoding": "utf8",
"destroyed": false,
"emitClose": true,
"emittedReadable": false,
"encoding": null,
"endEmitted": false,
"ended": false,
"errorEmitted": false,
"errored": null,
"flowing": null,
"highWaterMark": 16,
"length": 0,
"multiAwaitDrain": false,
"needReadable": false,
"objectMode": true,
"pipes": [],
"readableListening": false,
"reading": false,
"readingMore": false,
"resumeScheduled": false,
"sync": true,
Symbol(kPaused): null,
},
Symbol(kCapture): false,
},
},
"headers": [],
"host": "postman-echo.com",
"method": "get",
"path": "/get",
"query": [
{
"key": "foo1",
"value": "bar1",
},
{
"key": "foo2",
"value": "bar2",
},
],
},
"response": {
"body": {
"contentType": "application/json; charset=utf-8",
"size": 482,
"stream": Any<Readable>,
},
"headers": [
{
"key": "Content-Encoding",
"value": "gzip",
},
{
"key": "Content-Type",
"value": "application/json; charset=utf-8",
},
{
"key": "Date",
"value": "Tue, 11 Jun 2019 10:43:13 GMT",
},
{
"key": "ETag",
"value": "W/"161-aLhNcsGArlgLSKbxPqfBW3viHPI"",
},
{
"key": "Server",
"value": "nginx",
},
{
"key": "set-cookie",
"value": "sails.sid=s%3AGz-wblZgXE8FCDq7aJpx_tUgZUcG3Nsw.LdNEN8L0C7nGWkvGLwvdw6R2s6Syjr%2FzkvyevA8qR0c; Path=/; HttpOnly",
},
{
"key": "Vary",
"value": "Accept-Encoding",
},
{
"key": "Content-Length",
"value": "249",
},
{
"key": "Connection",
"value": "keep-alive",
},
],
"statusCode": "200",
},
}
`;
exports[`CapturedInteraction.fromPostmanEntry includes request bodies 1`] = `
{
"request": {
"body": {
"contentType": "application/json",
"size": 1188,
"stream": Any<Readable>,
},
"headers": [
{
"key": "Content-Type",
"value": "application/json",
},
],
"host": "postman-echo.com",
"method": "post",
"path": "/transform/collection",
"query": [
{
"key": "from",
"value": "1",
},
{
"key": "to",
"value": "2",
},
],
},
"response": {
"body": null,
"headers": [],
"statusCode": "200",
},
}
`;
exports[`CapturedInteraction.fromPostmanEntry includes response bodies 1`] = `
{
"request": {
"body": {
"contentType": null,
"size": 0,
"stream": Readable {
"_events": {},
"_eventsCount": 0,
"_maxListeners": undefined,
"_read": [Function],
"_readableState": ReadableState {
"autoDestroy": true,
"awaitDrainWriters": null,
"buffer": BufferList {
"head": null,
"length": 0,
"tail": null,
},
"closeEmitted": false,
"closed": false,
"constructed": true,
"dataEmitted": false,
"decoder": null,
"defaultEncoding": "utf8",
"destroyed": false,
"emitClose": true,
"emittedReadable": false,
"encoding": null,
"endEmitted": false,
"ended": false,
"errorEmitted": false,
"errored": null,
"flowing": null,
"highWaterMark": 16,
"length": 0,
"multiAwaitDrain": false,
"needReadable": false,
"objectMode": true,
"pipes": [],
"readableListening": false,
"reading": false,
"readingMore": false,
"resumeScheduled": false,
"sync": true,
Symbol(kPaused): null,
},
Symbol(kCapture): false,
},
},
"headers": [],
"host": "postman-echo.com",
"method": "get",
"path": "/get",
"query": [
{
"key": "foo1",
"value": "bar1",
},
{
"key": "foo2",
"value": "bar2",
},
],
},
"response": {
"body": {
"contentType": "application/json; charset=utf-8",
"size": 482,
"stream": Any<Readable>,
},
"headers": [
{
"key": "Content-Encoding",
"value": "gzip",
},
{
"key": "Content-Type",
"value": "application/json; charset=utf-8",
},
{
"key": "Date",
"value": "Tue, 11 Jun 2019 10:43:13 GMT",
},
{
"key": "ETag",
"value": "W/"161-aLhNcsGArlgLSKbxPqfBW3viHPI"",
},
{
"key": "Server",
"value": "nginx",
},
{
"key": "set-cookie",
"value": "sails.sid=s%3AGz-wblZgXE8FCDq7aJpx_tUgZUcG3Nsw.LdNEN8L0C7nGWkvGLwvdw6R2s6Syjr%2FzkvyevA8qR0c; Path=/; HttpOnly",
},
{
"key": "Vary",
"value": "Accept-Encoding",
},
{
"key": "Content-Length",
"value": "249",
},
{
"key": "Connection",
"value": "keep-alive",
},
],
"statusCode": "200",
},
}
`;
exports[`CapturedInteraction.fromProxyInteraction can create a CaturedInteraction from a ProxySource.Interaction 1`] = `
{
"request": {
Expand Down
5 changes: 3 additions & 2 deletions projects/optic/src/commands/oas/captures/getInteractions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ export async function getInteractions(
InputErrors.POSTMAN_FILE_NOT_FOUND
);
}
let harFile = fsSync.createReadStream(absolutePath);
let postmanEntryResults = PostmanCollectionEntries.fromReadable(harFile);
let collectionFile = fsSync.createReadStream(absolutePath);
let postmanEntryResults =
PostmanCollectionEntries.fromReadable(collectionFile);
let postmanEntries = AT.unwrapOr(postmanEntryResults, (err) => {
let message = `Postman collection entry skipped: ${err.message}`;
console.warn(message); // warn, skip and keep going
Expand Down
67 changes: 67 additions & 0 deletions projects/optic/src/commands/oas/captures/interaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { CapturedInteraction } from './interaction';
import { CapturedBody } from './body';
import { HarEntries, HttpArchive } from './streams/sources/har';
import { ProxyInteractions, ProxySource } from './streams/sources/proxy';
import {
PostmanCollectionEntries,
PostmanEntry,
} from './streams/sources/postman';
import { collect, unwrap } from '../lib/async-tools';
import fs from 'fs';
import Path from 'path';
Expand Down Expand Up @@ -156,6 +160,69 @@ describe('CapturedInteraction.fromProxyInteraction', () => {
});
});

describe('CapturedInteraction.fromPostmanEntry', () => {
let testEntries: PostmanEntry[];

beforeAll(async () => {
let source = fs.createReadStream(
Path.join(__dirname, '../tests/inputs/echo.postman_collection.json')
);

testEntries = await collect(
unwrap(PostmanCollectionEntries.fromReadable(source))
);
});

it('can create a CapturedInteraction from a PostmanEntry', () => {
let testEntry = testEntries[1];
let interaction = CapturedInteraction.fromPostmanCollection(testEntry);

expect(interaction).toMatchSnapshot({
response: { body: matchBody() },
});
});

it('includes request bodies', () => {
let testEntry = testEntries.find(
(entry) =>
entry.request.body &&
entry.request.body.raw?.length &&
entry.request.headers
.get('Content-Type')
?.startsWith('application/json')
)!;
expect(testEntry).toBeTruthy();

let interaction = CapturedInteraction.fromPostmanCollection(testEntry);
expect(interaction).toMatchSnapshot({
request: { body: matchBody() },
});

let parsingBody = CapturedBody.json(interaction.request.body);
expect(parsingBody).resolves.toMatchObject({});
});

it('includes response bodies', () => {
let testEntry = testEntries.find(
(entry) =>
entry.response &&
entry.response.body &&
entry.response.headers
.get('Content-Type')
?.startsWith('application/json')
)!;
expect(testEntry).toBeTruthy();

let interaction = CapturedInteraction.fromPostmanCollection(testEntry);
expect(interaction).toMatchSnapshot({
response: { body: matchBody() },
});

let parsingBody = CapturedBody.json(interaction.response.body);
expect(parsingBody).resolves.toMatchObject({});
});
});

function matchBody() {
return { stream: expect.any(Readable) };
}
Expand Down
Loading

0 comments on commit 0589174

Please sign in to comment.