From 147331570aa37d4b70c06e12dac3039cfdccc4b1 Mon Sep 17 00:00:00 2001 From: Kiko Ruiz Lloret Date: Tue, 31 May 2022 17:45:38 +0200 Subject: [PATCH 1/3] feat: add query to request in the pact file --- examples/react/src/api.js | 3 ++- src/convertMswMatchToPact.msw.spec.ts | 3 ++- src/convertMswMatchToPact.ts | 3 ++- src/pactFromMswServer.msw.spec.ts | 23 +++++++++++++++++++++++ src/pactMswAdapter.ts | 1 + 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/examples/react/src/api.js b/examples/react/src/api.js index fa85d4b..45d72a5 100644 --- a/examples/react/src/api.js +++ b/examples/react/src/api.js @@ -35,8 +35,9 @@ export class API { .then(r => r.data); } - async getProduct(id) { + async getProduct(id, params) { return axios.get(this.withPath("/product/" + id), { + params, headers: { "Authorization": this.generateAuthToken() } diff --git a/src/convertMswMatchToPact.msw.spec.ts b/src/convertMswMatchToPact.msw.spec.ts index e64a8c9..b70763d 100644 --- a/src/convertMswMatchToPact.msw.spec.ts +++ b/src/convertMswMatchToPact.msw.spec.ts @@ -17,6 +17,7 @@ const generatedPact:PactFile = { accept: "application/json, text/plain, */*", authorization: "Bearer 2022-03-01T19:36:18.277Z", }, + query: 'sort=asc' }, response: { status: 200, @@ -32,7 +33,7 @@ const sampleMatch: MswMatch[] = [ { request: { id: 'de5eefb0-c451-4ae2-9695-e02626f00ca7', - url: new URL('http://localhost:8081/products'), + url: new URL('http://localhost:8081/products?sort=asc'), method: 'GET', body: undefined, headers: new Headers({ diff --git a/src/convertMswMatchToPact.ts b/src/convertMswMatchToPact.ts index e1516c9..709171c 100644 --- a/src/convertMswMatchToPact.ts +++ b/src/convertMswMatchToPact.ts @@ -24,7 +24,8 @@ export const convertMswMatchToPact = ({ headers: headers?.excludeHeaders ? omit(match.request.headers['_headers'], headers.excludeHeaders) : match.request.headers['_headers'], - body: match.request.body || undefined + body: match.request.body || undefined, + query: match.request.url.search ? match.request.url.search.split('?')[1] : undefined }, response: { status: match.response.status, diff --git a/src/pactFromMswServer.msw.spec.ts b/src/pactFromMswServer.msw.spec.ts index bef8908..0f6a4a8 100644 --- a/src/pactFromMswServer.msw.spec.ts +++ b/src/pactFromMswServer.msw.spec.ts @@ -88,6 +88,29 @@ describe("API - With MSW mock generating a pact", () => { expect(respProduct).toEqual(product); }); + test("get product ID 10 with visibility hidden", async () => { + const product = { + id: "10", + type: "CREDIT_CARD", + name: "28 Degrees" + }; + const hiddenVisibilityProduct = { + ...product, + visibility: "hidden" + }; + server.use( + rest.get(API.url + "/product/10", (req, res, ctx) => { + const visibility = req.url.searchParams.get('visibility'); + const response = visibility === 'hidden' ? hiddenVisibilityProduct : product; + + return res(ctx.status(200), ctx.json(response)); + }) + ); + + const respProduct = await API.getProduct("10", {visibility: "hidden"}); + expect(respProduct).toEqual(hiddenVisibilityProduct); + }); + test("unhandled route", async () => { await expect(API.getProduct("11")).rejects.toThrow( /^connect ECONNREFUSED (127.0.0.1|::1):8081$/ diff --git a/src/pactMswAdapter.ts b/src/pactMswAdapter.ts index d2fa887..55a0804 100644 --- a/src/pactMswAdapter.ts +++ b/src/pactMswAdapter.ts @@ -376,6 +376,7 @@ export interface PactInteraction { path: string; headers: any; body: DefaultRequestBody; + query: any; }; response: { status: number; From 1cfd27921fd770a5e098255724d015eccad5b70b Mon Sep 17 00:00:00 2001 From: Kiko Ruiz Lloret Date: Wed, 1 Jun 2022 15:22:44 +0200 Subject: [PATCH 2/3] fix: change type --- src/pactMswAdapter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pactMswAdapter.ts b/src/pactMswAdapter.ts index 55a0804..f027d24 100644 --- a/src/pactMswAdapter.ts +++ b/src/pactMswAdapter.ts @@ -376,7 +376,7 @@ export interface PactInteraction { path: string; headers: any; body: DefaultRequestBody; - query: any; + query?: string; }; response: { status: number; From 864d9f44fa7b8987557830c95ef2874786ba1f9b Mon Sep 17 00:00:00 2001 From: Kiko Ruiz Lloret Date: Wed, 1 Jun 2022 15:26:04 +0200 Subject: [PATCH 3/3] test: add more tests --- src/convertMswMatchToPact.msw.spec.ts | 60 ++++++++++++++++++++++++++- src/convertMswMatchToPact.ts | 59 +++++++++++++------------- 2 files changed, 87 insertions(+), 32 deletions(-) diff --git a/src/convertMswMatchToPact.msw.spec.ts b/src/convertMswMatchToPact.msw.spec.ts index b70763d..ecff32e 100644 --- a/src/convertMswMatchToPact.msw.spec.ts +++ b/src/convertMswMatchToPact.msw.spec.ts @@ -2,13 +2,31 @@ import { convertMswMatchToPact } from "./convertMswMatchToPact"; import { MswMatch, PactFile } from "./pactMswAdapter"; import { Headers } from 'headers-utils'; -const generatedPact:PactFile = { +const generatedPact: PactFile = { consumer: { name: "interaction.consumer.name" }, provider: { name: "interaction.provider.name" }, interactions: [ { description: "de5eefb0-c451-4ae2-9695-e02626f00ca7", providerState: "", + request: { + method: "GET", + path: "/products", + body: undefined, + headers: { + accept: "application/json, text/plain, */*", + authorization: "Bearer 2022-03-01T19:36:18.277Z", + } + }, + response: { + status: 200, + body: [{ id: "09", type: "CREDIT_CARD", name: "Gem Visa" }], + headers: { "x-powered-by": "msw", "content-type": "application/json" }, + }, + }, + { + description: "073d6de0-e1ac-11ec-8fea-0242ac120002", + providerState: "", request: { method: "GET", path: "/products", @@ -33,6 +51,44 @@ const sampleMatch: MswMatch[] = [ { request: { id: 'de5eefb0-c451-4ae2-9695-e02626f00ca7', + url: new URL('http://localhost:8081/products'), + method: 'GET', + body: undefined, + headers: new Headers({ + accept: 'application/json, text/plain, */*', + authorization: 'Bearer 2022-03-01T19:36:18.277Z', + 'user-agent': 'axios/0.21.1', + host: 'localhost:8081', + 'content-type': 'application/json' + }), + cookies: {}, + redirect: 'manual', + referrer: '', + keepalive: false, + cache: 'default', + mode: 'cors', + referrerPolicy: 'no-referrer', + integrity: '', + destination: 'document', + bodyUsed: false, + credentials: 'same-origin' + }, + response: { + status: 200, + statusText: 'OK', + headers: new Headers({ + 'x-powered-by': 'msw', + 'content-type': 'application/json' + }), + body: JSON.stringify([ + { id: '09', type: 'CREDIT_CARD', name: 'Gem Visa' } + ]) + }, + body: JSON.stringify([{ id: '09', type: 'CREDIT_CARD', name: 'Gem Visa' }]) + }, + { + request: { + id: '073d6de0-e1ac-11ec-8fea-0242ac120002', url: new URL('http://localhost:8081/products?sort=asc'), method: 'GET', body: undefined, @@ -69,6 +125,7 @@ const sampleMatch: MswMatch[] = [ body: JSON.stringify([{ id: '09', type: 'CREDIT_CARD', name: 'Gem Visa' }]) } ]; + describe("writes an msw req/res to a pact", () => { it("should convert an msw server match to a pact", async () => { expect( @@ -80,4 +137,3 @@ describe("writes an msw req/res to a pact", () => { ).toMatchObject(generatedPact); }); }); - diff --git a/src/convertMswMatchToPact.ts b/src/convertMswMatchToPact.ts index 709171c..0bf3612 100644 --- a/src/convertMswMatchToPact.ts +++ b/src/convertMswMatchToPact.ts @@ -1,6 +1,6 @@ import { PactFile, MswMatch } from "./pactMswAdapter"; import { omit } from "lodash"; -export const convertMswMatchToPact = ({ +export const convertMswMatchToPact = ({ consumer, provider, matches, @@ -14,40 +14,39 @@ export const convertMswMatchToPact = ({ const pactFile: PactFile = { consumer: { name: consumer }, provider: { name: provider }, - interactions: matches.map( (match) => { - return { - description: match.request.id, - providerState: '', - request: { - method: match.request.method, - path: match.request.url.pathname, - headers: headers?.excludeHeaders - ? omit(match.request.headers['_headers'], headers.excludeHeaders) - : match.request.headers['_headers'], - body: match.request.body || undefined, - query: match.request.url.search ? match.request.url.search.split('?')[1] : undefined - }, - response: { - status: match.response.status, - headers: headers?.excludeHeaders - ? omit( - Object.fromEntries(match.response.headers.entries()), - headers.excludeHeaders - ) - : Object.fromEntries(match.response.headers.entries()), - body: match.body - ? match.response.headers.get('content-type')?.includes('json') - ? JSON.parse(match.body) - : match.body - : undefined - } - }; - }), + interactions: matches.map(match => ({ + description: match.request.id, + providerState: '', + request: { + method: match.request.method, + path: match.request.url.pathname, + headers: headers?.excludeHeaders + ? omit(match.request.headers['_headers'], headers.excludeHeaders) + : match.request.headers['_headers'], + body: match.request.body || undefined, + query: match.request.url.search ? match.request.url.search.split('?')[1] : undefined + }, + response: { + status: match.response.status, + headers: headers?.excludeHeaders + ? omit( + Object.fromEntries(match.response.headers.entries()), + headers.excludeHeaders + ) + : Object.fromEntries(match.response.headers.entries()), + body: match.body + ? match.response.headers.get('content-type')?.includes('json') + ? JSON.parse(match.body) + : match.body + : undefined + } + })), metadata: { pactSpecification: { version: "2.0.0", }, }, }; + return pactFile; };