From 47a450a92e461a5a1c2b11ccf2c89286226428d7 Mon Sep 17 00:00:00 2001 From: David Watrous <509299+dpwatrous@users.noreply.github.com> Date: Sat, 23 Sep 2023 13:40:19 -0400 Subject: [PATCH 1/2] Add support for mocking URLSearchParams bodies --- .../http/__tests__/mock-http-client.spec.ts | 41 +++++++++++++++++++ .../bonito-core/src/http/mock-http-client.ts | 30 +++++++++----- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts b/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts index 56231e85e9..7e425f88ed 100644 --- a/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts +++ b/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts @@ -222,4 +222,45 @@ describe("MockHttpClient", () => { await (await client.put("/some/url", { body: "two" })).text() ).toBe("response two"); }); + + test("supports sending string bodies", async () => { + const client = new MockHttpClient(); + client.addExpected( + new MockHttpResponse("/some/url", { + status: 200, + }), + { + method: "PUT", + body: "this is a string", + } + ); + const response = await client.put("/some/url", { + body: "this is a string", + }); + expect(response.status).toBe(200); + }); + + test("supports sending URLSearchParams bodies", async () => { + const client = new MockHttpClient(); + + const body = new URLSearchParams({ + color: "red", + shape: "triangle", + }); + expect(client.serializeBody(body)).toBe("color=red&shape=triangle"); + + client.addExpected( + new MockHttpResponse("/some/url", { + status: 200, + }), + { + method: "PUT", + body, + } + ); + const response = await client.put("/some/url", { + body, + }); + expect(response.status).toBe(200); + }); }); diff --git a/packages/bonito-core/src/http/mock-http-client.ts b/packages/bonito-core/src/http/mock-http-client.ts index a40f55ffae..712832a722 100644 --- a/packages/bonito-core/src/http/mock-http-client.ts +++ b/packages/bonito-core/src/http/mock-http-client.ts @@ -101,16 +101,11 @@ export class MockHttpClient extends AbstractHttpClient { const method = requestProps.method ?? HttpRequestMethod.Get; let bodyId: string = ""; - const reqBody = requestProps.body; - if (reqBody) { - if (typeof reqBody !== "string") { - throw new Error( - "MockHttpClient only supports string request bodies" - ); - } - if (this._expectedRequestBodies[reqBody]) { + if (requestProps.body) { + const bodyString = this.serializeBody(requestProps.body); + if (this._expectedRequestBodies[bodyString]) { // Existing body identifier - const expectedBody = this._expectedRequestBodies[reqBody]; + const expectedBody = this._expectedRequestBodies[bodyString]; if (updateBodyIds) { expectedBody.refCount++; } @@ -118,12 +113,12 @@ export class MockHttpClient extends AbstractHttpClient { } else if (updateBodyIds) { // New body identifier bodyId = `body${this._bodyIdCounter++}`; - this._expectedRequestBodies[reqBody] = { + this._expectedRequestBodies[bodyString] = { refCount: 1, bodyId: bodyId, }; } else { - throw new Error(`Unexpected request body: ${reqBody}`); + throw new Error(`Unexpected request body: ${bodyString}`); } } @@ -139,6 +134,19 @@ export class MockHttpClient extends AbstractHttpClient { (key) => key.split("::")[1] ); } + + serializeBody( + body: string | Blob | BufferSource | FormData | URLSearchParams + ): string { + if (typeof body === "string") { + return body; + } else if (body instanceof URLSearchParams) { + return body.toString(); + } + throw new Error( + "Unsupported request body type: MockHttpClient supports bodies of type string or URLSearchParams" + ); + } } /** From 779c640c597570999a1e74d8c503b7c54409accf Mon Sep 17 00:00:00 2001 From: David Watrous <509299+dpwatrous@users.noreply.github.com> Date: Sat, 23 Sep 2023 14:14:57 -0400 Subject: [PATCH 2/2] Fix: MockHttpClient ignored request URL when setting expected keys --- .../http/__tests__/mock-http-client.spec.ts | 19 +++++++++++++++++++ .../bonito-core/src/http/mock-http-client.ts | 6 +++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts b/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts index 7e425f88ed..7b7e687afd 100644 --- a/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts +++ b/packages/bonito-core/src/http/__tests__/mock-http-client.spec.ts @@ -106,6 +106,25 @@ describe("MockHttpClient", () => { ); }); + test("response URL and request URL can be different", async () => { + const client = new MockHttpClient(); + + client.addExpected( + new MockHttpResponse("https://contoso.net/foobar", { + status: 200, + body: "foobaz", + }), + { + method: "GET", + url: "/foobar", + } + ); + + const response = await client.fetch("/foobar"); + expect(response.url).toBe("https://contoso.net/foobar"); + expect(await response.text()).toBe("foobaz"); + }); + test("can mock all methods", async () => { const client = new MockHttpClient(); diff --git a/packages/bonito-core/src/http/mock-http-client.ts b/packages/bonito-core/src/http/mock-http-client.ts index 712832a722..abaf50fb4e 100644 --- a/packages/bonito-core/src/http/mock-http-client.ts +++ b/packages/bonito-core/src/http/mock-http-client.ts @@ -85,7 +85,11 @@ export class MockHttpClient extends AbstractHttpClient { response: MockHttpResponse, requestProps: HttpRequestInit = {} ): MockHttpClient { - const key = this._getKeyFromRequest(response.url, requestProps, true); + const key = this._getKeyFromRequest( + requestProps.url ?? response.url, + requestProps, + true + ); const expected = this._expectedResponses[key] ?? []; expected.push(response); this._expectedResponses[key] = expected;