From 2baa69ba6d777d07eddefecc601bf53af10668c3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 9 Nov 2024 10:55:12 -0500 Subject: [PATCH] chore(deps): update dependency fetch-mock to v12 (#723) * chore(deps): update dependency fetch-mock to v12 * updates tests to use the new v12 fetch-mock apis --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Nick Floyd --- package-lock.json | 62 +++--- package.json | 2 +- test/defaults.test.ts | 52 +++-- test/request.test.ts | 464 ++++++++++++++++++++++-------------------- 4 files changed, 305 insertions(+), 275 deletions(-) diff --git a/package-lock.json b/package-lock.json index 04bf8cfff..baf390b34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "@types/node": "^22.0.0", "@vitest/coverage-v8": "^2.0.0", "esbuild": "^0.24.0", - "fetch-mock": "^11.0.0", + "fetch-mock": "^12.0.0", "glob": "^11.0.0", "prettier": "3.3.3", "semantic-release-plugin-update-version-in-files": "^1.0.0", @@ -1022,6 +1022,13 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, + "node_modules/@types/glob-to-regexp": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@types/glob-to-regexp/-/glob-to-regexp-0.4.4.tgz", + "integrity": "sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "22.8.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.2.tgz", @@ -1730,25 +1737,20 @@ "integrity": "sha512-fCqg/6Sps8tqk8p+kqyKqYfOF0VjPNYrqpLiqNl0RBKmD80B080AJWVV6EkSkscjToNExcXg1+Mfzftrx6+iSA==" }, "node_modules/fetch-mock": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-11.0.0.tgz", - "integrity": "sha512-AD2Gh1xDQBLBs4iJpSxar19cTOH/Gu9hf1ko2J4hHW1UbR+ZHOfmIAqfT+Wlku4U8cYbffjaTbGv7mqe5kPi3w==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-12.0.2.tgz", + "integrity": "sha512-9KVq/Scz06A+ThORLA/J/EACiPzLdSn6DeLV61hni57kd3DXhQVCtkpj4LgwES+8osEVEfcqA6LwdSX2FYVK7w==", "dev": true, "license": "MIT", "dependencies": { - "debug": "^4.1.1", + "@types/glob-to-regexp": "^0.4.4", "dequal": "^2.0.3", - "globrex": "^0.1.2", - "is-subset": "^0.1.1", + "glob-to-regexp": "^0.4.1", + "is-subset-of": "^3.1.10", "regexparam": "^3.0.0" }, "engines": { - "node": ">=8.0.0" - }, - "peerDependenciesMeta": { - "node-fetch": { - "optional": true - } + "node": ">=18.11.0" } }, "node_modules/foreground-child": { @@ -1831,6 +1833,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -1857,13 +1866,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", - "dev": true, - "license": "MIT" - }, "node_modules/html-escaper": { "version": "2.0.2", "dev": true, @@ -1912,10 +1914,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-subset": { - "version": "0.1.1", + "node_modules/is-subset-of": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/is-subset-of/-/is-subset-of-3.1.10.tgz", + "integrity": "sha512-avvaYgVmYWyaZ1NDFiv4y9JGkrE2je3op1Po4VYKKJKR8H2qVPsg1GZuuXl5elCTxTlwAIsrAjWAs4BVrISFRw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "typedescriptor": "3.0.2" + } }, "node_modules/isexe": { "version": "2.0.0", @@ -2664,6 +2672,14 @@ "node": ">=4" } }, + "node_modules/typedescriptor": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/typedescriptor/-/typedescriptor-3.0.2.tgz", + "integrity": "sha512-hyVbaCUd18UiXk656g/imaBLMogpdijIEpnhWYrSda9rhvO4gOU16n2nh7xG5lv/rjumnZzGOdz0CEGTmFe0fQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT" + }, "node_modules/typescript": { "version": "5.3.3", "dev": true, diff --git a/package.json b/package.json index 5c6747054..3825963af 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "@types/node": "^22.0.0", "@vitest/coverage-v8": "^2.0.0", "esbuild": "^0.24.0", - "fetch-mock": "^11.0.0", + "fetch-mock": "^12.0.0", "glob": "^11.0.0", "prettier": "3.3.3", "semantic-release-plugin-update-version-in-files": "^1.0.0", diff --git a/test/defaults.test.ts b/test/defaults.test.ts index 0b4514896..08d4f5214 100644 --- a/test/defaults.test.ts +++ b/test/defaults.test.ts @@ -1,4 +1,4 @@ -import fetchMock from "fetch-mock"; +import fetchMock, { FetchMock } from "fetch-mock"; import { describe, it, expect } from "vitest"; import { request } from "../src/index.ts"; @@ -9,19 +9,18 @@ describe("endpoint.defaults()", () => { }); it("README example", () => { - const mock = fetchMock - .sandbox() - .mock( - "https://github-enterprise.acme-inc.com/api/v3/orgs/my-project/repos?per_page=100", - [], - { - headers: { - accept: "application/vnd.github.v3+json", - authorization: "token 0000000000000000000000000000000000000001", - "user-agent": "myApp/1.2.3", - }, + const mock = fetchMock.createInstance(); + mock.get( + "https://github-enterprise.acme-inc.com/api/v3/orgs/my-project/repos?per_page=100", + [], + { + headers: { + accept: "application/vnd.github.v3+json", + authorization: "token 0000000000000000000000000000000000000001", + "user-agent": "myApp/1.2.3", }, - ); + }, + ); const myRequest = request.defaults({ baseUrl: "https://github-enterprise.acme-inc.com/api/v3", @@ -32,7 +31,7 @@ describe("endpoint.defaults()", () => { org: "my-project", per_page: 100, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); @@ -42,19 +41,18 @@ describe("endpoint.defaults()", () => { }); it("repeated defaults", () => { - const mock = fetchMock - .sandbox() - .get( - "https://github-enterprise.acme-inc.com/api/v3/orgs/my-project/repos", - [], - { - headers: { - accept: "application/vnd.github.v3.raw+json", - authorization: "token 0000000000000000000000000000000000000001", - "user-agent": "myApp/1.2.3", - }, + const mock = fetchMock.createInstance(); + mock.get( + "https://github-enterprise.acme-inc.com/api/v3/orgs/my-project/repos", + [], + { + headers: { + accept: "application/vnd.github.v3.raw+json", + authorization: "token 0000000000000000000000000000000000000001", + "user-agent": "myApp/1.2.3", }, - ); + }, + ); const myProjectRequest = request.defaults({ baseUrl: "https://github-enterprise.acme-inc.com/api/v3", @@ -66,7 +64,7 @@ describe("endpoint.defaults()", () => { }, org: "my-project", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); const myProjectRequestWithAuth = myProjectRequest.defaults({ diff --git a/test/request.test.ts b/test/request.test.ts index 913550480..e4bee928e 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -5,7 +5,7 @@ import { ReadableStream } from "node:stream/web"; import { describe, it, expect, vi } from "vitest"; import { getUserAgent } from "universal-user-agent"; -import fetchMock from "fetch-mock"; +import fetchMock, { FetchMock } from "fetch-mock"; import { createAppAuth } from "@octokit/auth-app"; import type { EndpointOptions, @@ -28,15 +28,14 @@ describe("request()", () => { it("README example", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .mock("https://api.github.com/orgs/octokit/repos?type=private", [], { - headers: { - accept: "application/vnd.github.v3+json", - authorization: "token 0000000000000000000000000000000000000001", - "user-agent": userAgent, - }, - }); + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/orgs/octokit/repos?type=private", [], { + headers: { + accept: "application/vnd.github.v3+json", + authorization: "token 0000000000000000000000000000000000000001", + "user-agent": userAgent, + }, + }); const response = await request("GET /orgs/{org}/repos", { headers: { @@ -45,7 +44,7 @@ describe("request()", () => { org: "octokit", type: "private", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); expect(response.data).toEqual([]); @@ -54,9 +53,8 @@ describe("request()", () => { it("README example alternative", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .mock("https://api.github.com/orgs/octokit/repos?type=private", []); + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/orgs/octokit/repos?type=private", []); const response = await request({ method: "GET", @@ -67,7 +65,7 @@ describe("request()", () => { org: "octokit", type: "private", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); expect(response.data).toEqual([]); @@ -111,8 +109,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== // see https://runkit.com/gr2m/reproducable-jwt const BEARER = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOi0zMCwiZXhwIjo1NzAsImlzcyI6MX0.q3foRa78U3WegM5PrWLEh5N0bH1SD62OqW66ZYzArp95JBNiCbo8KAlGtiRENCIfBZT9ibDUWy82cI4g3F09mdTq3bD1xLavIfmTksIQCz5EymTWR5v6gL14LSmQdWY9lSqkgUG0XCFljWUglEP39H4yeHbFgdjvAYg3ifDS12z9oQz2ACdSpvxPiTuCC804HkPVw8Qoy0OSXvCkFU70l7VXCVUxnuhHnk8-oCGcKUspmeP6UdDnXk-Aus-eGwDfJbU2WritxxaXw6B4a3flTPojkYLSkPBr6Pi0H2-mBsW_Nvs0aLPVLKobQd4gqTkosX3967DoAG8luUMhrnxe8Q"; - const mock = fetchMock - .sandbox() + const mock = fetchMock.createInstance(); + mock .postOnce("https://api.github.com/app/installations/123/access_tokens", { token: "secret123", expires_at: "1970-01-01T01:00:00.000Z", @@ -150,7 +148,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }); const requestWithAuth = request.defaults({ request: { - fetch: mock, + fetch: mock.fetchHandler, hook: auth.hook, }, }); @@ -161,20 +159,19 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== title: "Hello from the engine room", }); - expect(mock.done()).toBe(true); + expect(mock.callHistory.done()).toBe(true); vi.useRealTimers(); }); it("Request with body", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .mock("https://api.github.com/repos/octocat/hello-world/issues", 201, { - headers: { - "content-type": "application/json; charset=utf-8", - }, - }); + const mock = fetchMock.createInstance(); + mock.post("https://api.github.com/repos/octocat/hello-world/issues", 201, { + headers: { + "content-type": "application/json; charset=utf-8", + }, + }); const response = await request("POST /repos/{owner}/{repo}/issues", { owner: "octocat", @@ -188,7 +185,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== milestone: 1, labels: ["bug"], request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); @@ -196,14 +193,13 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }); it("Put without request body", async () => { - expect.assertions(1); + const mock = fetchMock.createInstance(); - const mock = fetchMock - .sandbox() - .mock("https://api.github.com/user/starred/octocat/hello-world", 204, { - body: undefined, - }); + mock.put("https://api.github.com/user/starred/octocat/hello-world", { + status: 204, + }); + // Perform the request const response = await request("PUT /user/starred/{owner}/{repo}", { headers: { authorization: `token 0000000000000000000000000000000000000001`, @@ -211,17 +207,18 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== owner: "octocat", repo: "hello-world", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); + expect(response.status).toEqual(204); }); it("HEAD requests (octokit/rest.js#841)", async () => { expect.assertions(2); - const mock = fetchMock - .sandbox() + const mock = fetchMock.createInstance(); + mock .head("https://api.github.com/repos/whatwg/html/pulls/1", { status: 200, headers: { @@ -242,7 +239,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "html", number: 1, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }; @@ -261,8 +258,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }); it.skip("Binary response with redirect (🤔 unclear how to mock fetch redirect properly)", async () => { - const mock = fetchMock - .sandbox() + const mock = fetchMock.createInstance(); + mock .get( "https://codeload.github.com/repos/octokit-fixture-org/get-archive-1/tarball/master", { @@ -296,7 +293,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== archive_format: "tarball", ref: "master", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }, ); @@ -309,31 +306,30 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== const payload = "1f8b0800000000000003cb4f2ec9cfce2cd14dcbac28292d4ad5cd2f4ad74d4f2dd14d2c4acec82c4bd53580007d060a0050bfb9b9a90203c428741ac2313436343307222320dbc010a8dc5c81c194124b8905a5c525894540a714e5e797e05347481edd734304e41319ff41ae8e2ebeae7ab92964d801d46f66668227fe0d4d51e3dfc8d0c8d808284f75df6201233cfe951590627ba01d330a46c1281805a3806e000024cb59d6000a0000"; - const mock = fetchMock - .sandbox() - .get( - "https://codeload.github.com/octokit-fixture-org/get-archive/legacy.tar.gz/master", - { - status: 200, + const mock = fetchMock.createInstance(); + mock.get( + "https://codeload.github.com/octokit-fixture-org/get-archive/legacy.tar.gz/master", + { + status: 200, - // expect(response.data.length).toEqual(172) - // body: Buffer.from('1f8b0800000000000003cb4f2ec9cfce2cd14dcbac28292d4ad5cd2f4ad74d4f2dd14d2c4acec82c4bd53580007d060a0050bfb9b9a90203c428741ac2313436343307222320dbc010a8dc5c81c194124b8905a5c525894540a714e5e797e05347481edd734304e41319ff41ae8e2ebeae7ab92964d801d46f66668227fe0d4d51e3dfc8d0c8d808284f75df6201233cfe951590627ba01d330a46c1281805a3806e000024cb59d6000a0000', 'hex'), - body: Buffer.from( - "1f8b0800000000000003cb4f2ec9cfce2cd14dcbac28292d4ad5cd2f4ad74d4f2dd14d2c4acec82c4bd53580007d060a0050bfb9b9a90203c428741ac2313436343307222320dbc010a8dc5c81c194124b8905a5c525894540a714e5e797e05347481edd734304e41319ff41ae8e2ebeae7ab92964d801d46f66668227fe0d4d51e3dfc8d0c8d808284f75df6201233cfe951590627ba01d330a46c1281805a3806e000024cb59d6000a0000", - "hex", - ), - headers: { - "content-type": "application/x-gzip", - "content-length": "172", - }, + // expect(response.data.length).toEqual(172) + // body: Buffer.from('1f8b0800000000000003cb4f2ec9cfce2cd14dcbac28292d4ad5cd2f4ad74d4f2dd14d2c4acec82c4bd53580007d060a0050bfb9b9a90203c428741ac2313436343307222320dbc010a8dc5c81c194124b8905a5c525894540a714e5e797e05347481edd734304e41319ff41ae8e2ebeae7ab92964d801d46f66668227fe0d4d51e3dfc8d0c8d808284f75df6201233cfe951590627ba01d330a46c1281805a3806e000024cb59d6000a0000', 'hex'), + body: Buffer.from( + "1f8b0800000000000003cb4f2ec9cfce2cd14dcbac28292d4ad5cd2f4ad74d4f2dd14d2c4acec82c4bd53580007d060a0050bfb9b9a90203c428741ac2313436343307222320dbc010a8dc5c81c194124b8905a5c525894540a714e5e797e05347481edd734304e41319ff41ae8e2ebeae7ab92964d801d46f66668227fe0d4d51e3dfc8d0c8d808284f75df6201233cfe951590627ba01d330a46c1281805a3806e000024cb59d6000a0000", + "hex", + ), + headers: { + "content-type": "application/x-gzip", + "content-length": "172", }, - ); + }, + ); const response = await request( "GET https://codeload.github.com/octokit-fixture-org/get-archive/legacy.tar.gz/master", { request: { - fetch: mock, + fetch: mock.fetchHandler, }, }, ); @@ -349,20 +345,21 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("304 etag", async () => { expect.assertions(1); + const mock = fetchMock.createInstance(); - const mock = fetchMock.sandbox().get((url, { headers }) => { - return ( - url === "https://api.github.com/orgs/myorg" && - (headers as ResponseHeaders)["if-none-match"] === "etag" - ); - }, 304); + mock.get("https://api.github.com/orgs/myorg", { + status: 304, + headers: { + "If-None-Match": "etag", + }, + }); await expect( request("GET /orgs/{org}", { org: "myorg", headers: { "If-None-Match": "etag" }, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }), ).rejects.toHaveProperty("status", 304); @@ -371,13 +368,13 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("304 last-modified", async () => { expect.assertions(1); - const mock = fetchMock.sandbox().get((url, { headers }) => { - return ( - url === "https://api.github.com/orgs/myorg" && - (headers as ResponseHeaders)["if-modified-since"] === - "Sun Dec 24 2017 22:00:00 GMT-0600 (CST)" - ); - }, 304); + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/orgs/myorg", { + status: 304, + headers: { + "if-modified-since": "Sun Dec 24 2017 22:00:00 GMT-0600 (CST)", + }, + }); await expect( request("GET /orgs/{org}", { @@ -386,7 +383,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== "If-Modified-Since": "Sun Dec 24 2017 22:00:00 GMT-0600 (CST)", }, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }), ).rejects.toHaveProperty("status", 304); @@ -395,13 +392,14 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("Not found", async () => { expect.assertions(3); - const mock = fetchMock.sandbox().get("path:/orgs/nope", 404); + const mock = fetchMock.createInstance(); + mock.get("path:/orgs/nope", 404); try { await request("GET /orgs/{org}", { org: "nope", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("should not resolve"); @@ -433,15 +431,14 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("error response with no body (octokit/request.js#649)", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .get("path:/repos/octokit-fixture-org/hello-world/contents/README.md", { - status: 500, - body: "", - headers: { - "content-type": "application/json", - }, - }); + const mock = fetchMock.createInstance(); + mock.get("path:/repos/octokit-fixture-org/hello-world/contents/README.md", { + status: 500, + body: "", + headers: { + "content-type": "application/json", + }, + }); try { await request("GET /repos/{owner}/{repo}/contents/{path}", { @@ -452,7 +449,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "hello-world", path: "README.md", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("should not resolve"); @@ -464,16 +461,15 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("non-JSON response", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .get("path:/repos/octokit-fixture-org/hello-world/contents/README.md", { - status: 200, - body: "# hello-world", - headers: { - "content-length": "13", - "content-type": "application/vnd.github.v3.raw; charset=utf-8", - }, - }); + const mock = fetchMock.createInstance(); + mock.get("path:/repos/octokit-fixture-org/hello-world/contents/README.md", { + status: 200, + body: "# hello-world", + headers: { + "content-length": "13", + "content-type": "application/vnd.github.v3.raw; charset=utf-8", + }, + }); const response = await request( "GET /repos/{owner}/{repo}/contents/{path}", @@ -485,7 +481,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "hello-world", path: "README.md", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }, ); @@ -505,7 +501,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("Request TypeError error with an Error cause", async () => { expect.assertions(2); - const mock = fetchMock.sandbox().get("https://127.0.0.1:8/", { + const mock = fetchMock.createInstance(); + mock.get("https://127.0.0.1:8/", { throws: Object.assign(new TypeError("fetch failed"), { cause: new Error("bad"), }), @@ -515,7 +512,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== // port: 8 // officially unassigned port. See https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers await request("GET https://127.0.0.1:8/", { request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("should not resolve"); @@ -528,7 +525,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("Request TypeError error with a string cause", async () => { expect.assertions(2); - const mock = fetchMock.sandbox().get("https://127.0.0.1:8/", { + const mock = fetchMock.createInstance(); + mock.get("https://127.0.0.1:8/", { throws: Object.assign(new TypeError("fetch failed"), { cause: "bad" }), }); @@ -536,7 +534,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== // port: 8 // officially unassigned port. See https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers await request("GET https://127.0.0.1:8/", { request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("should not resolve"); @@ -547,54 +545,62 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }); it("custom user-agent", async () => { - expect.assertions(1); + expect.assertions(2); + const mock = fetchMock.createInstance(); - const mock = fetchMock.sandbox().get((_url, mockRequest) => { - expect(mockRequest.headers!["user-agent"]).toEqual("funky boom boom pow"); - return true; - }, 200); + mock.get("https://api.github.com/orgs/myorg", { + status: 200, + headers: { + "user-agent": "funky boom boom pow", + }, + }); - await request("GET /", { + const response = await request("GET /orgs/{owner}", { headers: { "user-agent": "funky boom boom pow", }, + owner: "myorg", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); + + expect(response.status).toEqual(200); + expect(mock.callHistory.calls()[0].options.headers!["user-agent"]).toEqual( + "funky boom boom pow", + ); }); it("422 error with details", async () => { expect.assertions(4); - const mock = fetchMock - .sandbox() - .post("https://api.github.com/repos/octocat/hello-world/labels", { - status: 422, - headers: { - "Content-Type": "application/json; charset=utf-8", - "X-Foo": "bar", - }, - body: { - message: "Validation Failed", - errors: [ - { - resource: "Label", - code: "invalid", - field: "color", - }, - ], - documentation_url: - "https://developer.github.com/v3/issues/labels/#create-a-label", - }, - }); + const mock = fetchMock.createInstance(); + mock.post("https://api.github.com/repos/octocat/hello-world/labels", { + status: 422, + headers: { + "Content-Type": "application/json; charset=utf-8", + "X-Foo": "bar", + }, + body: { + message: "Validation Failed", + errors: [ + { + resource: "Label", + code: "invalid", + field: "color", + }, + ], + documentation_url: + "https://developer.github.com/v3/issues/labels/#create-a-label", + }, + }); try { await request("POST /repos/octocat/hello-world/labels", { name: "foo", color: "invalid", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("should not resolve"); @@ -613,7 +619,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("redacts credentials from error.request.headers.authorization", async () => { expect.assertions(1); - const mock = fetchMock.sandbox().get("https://api.github.com/", { + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/", { status: 500, }); @@ -623,7 +630,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== authorization: "token secret123", }, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("should not resolve"); @@ -634,18 +641,17 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("redacts credentials from error.request.url", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .get("https://api.github.com/?client_id=123&client_secret=secret123", { - status: 500, - }); + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/?client_id=123&client_secret=secret123", { + status: 500, + }); try { await request("/", { client_id: "123", client_secret: "secret123", request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("should not resolve"); @@ -659,11 +665,12 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("Just URL", async () => { expect.assertions(1); - const mock = fetchMock.sandbox().get("path:/", 200); + const mock = fetchMock.createInstance(); + mock.get("path:/", 200); const response = await request("/", { request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); @@ -714,7 +721,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("options.request.hook", async () => { expect.assertions(4); - const mock = fetchMock.sandbox().mock( + const mock = fetchMock.createInstance(); + mock.get( "https://api.github.com/foo", { ok: true }, { @@ -738,7 +746,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }, method: "GET", request: { - fetch: mock, + fetch: mock.fetchHandler, hook, }, url: "/", @@ -749,14 +757,14 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== "x-foo": "bar", }, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); }; const response = await request("/", { request: { - fetch: mock, + fetch: mock.fetchHandler, hook, }, }); @@ -766,15 +774,14 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("options.mediaType.format", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .mock("https://api.github.com/repos/octokit/request.js/issues/1", "ok", { - headers: { - accept: "application/vnd.github.v3.raw+json", - authorization: "token 0000000000000000000000000000000000000001", - "user-agent": userAgent, - }, - }); + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/repos/octokit/request.js/issues/1", "ok", { + headers: { + accept: "application/vnd.github.v3.raw+json", + authorization: "token 0000000000000000000000000000000000000001", + "user-agent": userAgent, + }, + }); const response = await request( "GET /repos/{owner}/{repo}/issues/{number}", @@ -789,7 +796,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "request.js", number: 1, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }, ); @@ -799,16 +806,15 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("options.mediaType.previews", async () => { expect.assertions(1); - const mock = fetchMock - .sandbox() - .mock("https://api.github.com/graphql", "ok", { - headers: { - accept: - "application/vnd.github.foo-preview+json,application/vnd.github.bar-preview+json", - authorization: "token 0000000000000000000000000000000000000001", - "user-agent": userAgent, - }, - }); + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/graphql", "ok", { + headers: { + accept: + "application/vnd.github.foo-preview+json,application/vnd.github.bar-preview+json", + authorization: "token 0000000000000000000000000000000000000001", + "user-agent": userAgent, + }, + }); const response = await request("GET /graphql", { headers: { @@ -818,14 +824,15 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== previews: ["foo", "bar"], }, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); expect(response.data).toEqual("ok"); }); it("octokit/octokit.js#1497", async () => { - const mock = fetchMock.sandbox().mock( + const mock = fetchMock.createInstance(); + mock.put( "https://request-errors-test.com/repos/gr2m/sandbox/branches/gr2m-patch-1/protection", { status: 400, @@ -867,7 +874,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }, restrictions: { users: [], teams: [] }, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }), ).rejects.toHaveProperty( @@ -879,7 +886,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("logs deprecation warning if `deprecation` header is present", async () => { expect.assertions(3); - const mock = fetchMock.sandbox().mock( + const mock = fetchMock.createInstance(); + mock.get( "https://api.github.com/teams/123", { body: { @@ -907,7 +915,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== authorization: "token 0000000000000000000000000000000000000001", }, team_id: 123, - request: { fetch: mock, log: { warn } }, + request: { fetch: mock.fetchHandler, log: { warn } }, }); expect(response.data).toEqual({ id: 123 }); expect(warn).toHaveBeenCalledTimes(1); @@ -917,7 +925,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }); it("deprecation header without deprecation link", async () => { - const mock = fetchMock.sandbox().mock( + const mock = fetchMock.createInstance(); + mock.get( "https://api.github.com/teams/123", { body: { @@ -944,7 +953,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== authorization: "token 0000000000000000000000000000000000000001", }, team_id: 123, - request: { fetch: mock, log: { warn } }, + request: { fetch: mock.fetchHandler, log: { warn } }, }); expect(response.data).toEqual({ id: 123 }); expect(warn).toHaveBeenCalledTimes(1); @@ -956,22 +965,21 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("404 not found", async () => { expect.assertions(3); - const mock = fetchMock - .sandbox() - .get("https://api.github.com/repos/octocat/unknown", { - status: 404, - headers: {}, - body: { - message: "Not Found", - documentation_url: - "https://docs.github.com/en/rest/reference/repos#get-a-repository", - }, - }); + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/repos/octocat/unknown", { + status: 404, + headers: {}, + body: { + message: "Not Found", + documentation_url: + "https://docs.github.com/en/rest/reference/repos#get-a-repository", + }, + }); try { await request("GET /repos/octocat/unknown", { request: { - fetch: mock, + fetch: mock.fetchHandler, }, }); throw new Error("Should have thrown"); @@ -993,7 +1001,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }); }; - const mock = fetchMock.sandbox().get("https://api.github.com/", () => + const mock = fetchMock.createInstance(); + mock.get("https://api.github.com/", () => delay(3000).then(() => ({ message: "Not Found", documentation_url: @@ -1004,7 +1013,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== try { await request("GET /", { request: { - fetch: mock, + fetch: mock.fetchHandler, signal: AbortSignal.timeout(500), }, }); @@ -1020,14 +1029,13 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== expect.assertions(3); const size = fs.statSync(__filename).size; - const mock = fetchMock - .sandbox() - .post( - "https://api.github.com/repos/octokit-fixture-org/release-assets/releases/v1.0.0/assets", - { - status: 200, - }, - ); + const mock = fetchMock.createInstance(); + mock.post( + "https://api.github.com/repos/octokit-fixture-org/release-assets/releases/v1.0.0/assets", + { + status: 200, + }, + ); const response = await request( "POST /repos/{owner}/{repo}/releases/{release_id}/assets", @@ -1036,7 +1044,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "release-assets", release_id: "v1.0.0", request: { - fetch: mock, + fetch: mock.fetchHandler, }, headers: { "content-type": "text/json", @@ -1047,22 +1055,24 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== label: "test", }, ); + + expect(mock.callHistory.calls()[0].options.body).toBeInstanceOf( + stream.Readable, + ); expect(response.status).toEqual(200); - expect(mock.lastOptions()?.body).toBeInstanceOf(stream.Readable); - expect(mock.done()).toBe(true); + expect(mock.callHistory.done()).toBe(true); }); it("validate request with data set to Buffer type", async () => { expect.assertions(3); - const mock = fetchMock - .sandbox() - .post( - "https://api.github.com/repos/octokit-fixture-org/release-assets/releases/tags/v1.0.0", - { - status: 200, - }, - ); + const mock = fetchMock.createInstance(); + mock.post( + "https://api.github.com/repos/octokit-fixture-org/release-assets/releases/tags/v1.0.0", + { + status: 200, + }, + ); const response = await request( "POST /repos/{owner}/{repo}/releases/tags/{tag}", @@ -1071,7 +1081,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "release-assets", tag: "v1.0.0", request: { - fetch: mock, + fetch: mock.fetchHandler, }, headers: { "content-type": "text/plain", @@ -1082,21 +1092,22 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }, ); expect(response.status).toEqual(200); - expect(mock.lastOptions()?.body).toEqual(Buffer.from("Hello, world!\n")); - expect(mock.done()).toBe(true); + expect(mock.callHistory.calls()[0].options.body).toEqual( + Buffer.from("Hello, world!\n"), + ); + expect(mock.callHistory.done()).toBe(true); }); it("validate request with data set to ArrayBuffer type", async () => { expect.assertions(3); - const mock = fetchMock - .sandbox() - .post( - "https://api.github.com/repos/octokit-fixture-org/release-assets/releases/tags/v1.0.0", - { - status: 200, - }, - ); + const mock = fetchMock.createInstance(); + mock.post( + "https://api.github.com/repos/octokit-fixture-org/release-assets/releases/tags/v1.0.0", + { + status: 200, + }, + ); const response = await request( "POST /repos/{owner}/{repo}/releases/tags/{tag}", @@ -1105,7 +1116,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "release-assets", tag: "v1.0.0", request: { - fetch: mock, + fetch: mock.fetchHandler, }, headers: { "content-type": "text/plain", @@ -1117,17 +1128,21 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== ); expect(response.status).toEqual(200); - expect(mock.lastOptions()?.body).toEqual( + expect(mock.callHistory.calls()[0].options.body).toEqual( stringToArrayBuffer("Hello, world!\n"), ); - expect(mock.done()).toBe(true); + // expect(mock.callHistory.lastCall()[1].body).toEqual( + // stringToArrayBuffer("Hello, world!\n"), + // ); + expect(mock.callHistory.done()).toBe(true); }); it("bubbles up AbortError if the request is aborted", async () => { expect.assertions(1); const abortController = new AbortController(); - const mock = fetchMock.sandbox().post( + const mock = fetchMock.createInstance(); + mock.post( "https://api.github.com/repos/octokit-fixture-org/release-assets/releases/tags/v1.0.0", new Promise(() => { abortController.abort(); @@ -1140,7 +1155,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== repo: "release-assets", tag: "v1.0.0", request: { - fetch: mock, + fetch: mock.fetchHandler, signal: abortController.signal, }, headers: { @@ -1156,7 +1171,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("request should pass the stream in the response", async () => { expect.assertions(4); - const mock = fetchMock.sandbox().get( + const mock = fetchMock.createInstance().get( "https://api.github.com/repos/octokit-fixture-org/release-assets/tarball/main", { status: 200, @@ -1178,7 +1193,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== branch: "main", request: { parseSuccessResponseBody: false, - fetch: mock, + fetch: mock.fetchHandler, }, }, ); @@ -1186,7 +1201,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== expect(response.status).toEqual(200); expect(response.headers["content-type"]).toEqual("application/x-gzip"); expect(response.data).toBeInstanceOf(ReadableStream); - expect(mock.done()).toBe(true); + expect(mock.callHistory.done()).toBe(true); }); it("request should pass the `redirect` option to fetch", () => { @@ -1208,7 +1223,8 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== it("invalid error responses should result in errors with a message field describing the error as an unknown error", async () => { expect.assertions(1); - const mock = fetchMock.sandbox().mock( + const mock = fetchMock.createInstance(); + mock.put( "https://request-errors-test.com/repos/gr2m/sandbox/branches/gr2m-patch-1/protection", { status: 400, @@ -1242,7 +1258,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== }, restrictions: { users: [], teams: [] }, request: { - fetch: mock, + fetch: mock.fetchHandler, }, }), ).rejects.toHaveProperty("message", "Unknown error: {}");