Skip to content

Commit

Permalink
test: use native fetch with mock server (#702)
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak authored Jul 10, 2024
1 parent eaceec7 commit af8ef43
Show file tree
Hide file tree
Showing 10 changed files with 3,294 additions and 1,884 deletions.
2,870 changes: 1,412 additions & 1,458 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"lint": "prettier --check '{src,test}/**/*' README.md package.json",
"lint:fix": "prettier --write '{src,test}/**/*' README.md package.json vite.config.js",
"pretest": "npm run -s lint",
"test": "vitest run --coverage"
"test": "vitest run --coverage",
"test:watch": "vitest --coverage"
},
"repository": "github:octokit/request.js",
"keywords": [
Expand Down
8 changes: 8 additions & 0 deletions src/defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { getUserAgent } from "universal-user-agent";
import { VERSION } from "./version.js";

export default {
headers: {
"user-agent": `octokit-request.js/${VERSION} ${getUserAgent()}`,
},
};
10 changes: 2 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { endpoint } from "@octokit/endpoint";
import { getUserAgent } from "universal-user-agent";

import { VERSION } from "./version.js";
import defaults from "./defaults.js";
import withDefaults from "./with-defaults.js";

export const request = withDefaults(endpoint, {
headers: {
"user-agent": `octokit-request.js/${VERSION} ${getUserAgent()}`,
},
});
export const request = withDefaults(endpoint, defaults);
10 changes: 10 additions & 0 deletions test/body-parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { IncomingMessage } from "http";

export default function bodyParser(request: IncomingMessage) {
return new Promise((resolve, reject) => {
let body = "";
request.on("error", reject);
request.on("data", (chunk: string) => (body += chunk));
request.on("end", () => resolve(body));
});
}
37 changes: 37 additions & 0 deletions test/mock-request-http-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createServer, RequestListener } from "node:http";
import { type AddressInfo } from "node:net";
import { once } from "node:stream";

import { endpoint } from "@octokit/endpoint";
import type { RequestInterface } from "@octokit/types";

import withDefaults from "../src/with-defaults.ts";
import defaults from "../src/defaults.ts";

export default async function mockRequestHttpServer(
requestListener: RequestListener,
): Promise<
RequestInterface<object> & {
closeMockServer: () => void;
baseUrlMockServer: string;
}
> {
const server = createServer(requestListener);
server.listen(0);
await once(server, "listening");

const baseUrl = `http://localhost:${(server.address() as AddressInfo).port}`;

const request = withDefaults(endpoint, {
...defaults,
baseUrl,
}) as RequestInterface<object> & {
closeMockServer: () => void;
baseUrlMockServer: string;
};

request.baseUrlMockServer = baseUrl;
request.closeMockServer = server.close.bind(server);

return request;
}
122 changes: 122 additions & 0 deletions test/request-common.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { describe, it, expect } from "vitest";
import fetchMock from "fetch-mock";

import { request } from "../src/index.ts";

describe("request()", () => {
it("is a function", () => {
expect(request).toBeInstanceOf(Function);
});

it("Request error", async () => {
expect.assertions(1);

// port: 8 // officially unassigned port. See https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers
await expect(request("GET https://127.0.0.1:8/")).rejects.toHaveProperty(
"status",
500,
);
});

it("Resolves with url", async () => {
expect.assertions(1);

// this test cannot be mocked with `fetch-mock`. I don’t like to rely on
// external websites to run tests, but in this case I’ll make an exception.
// The alternative would be to start a local server we then send a request to,
// this would only work in Node, so we would need to adapt the test setup, too.
// We also can’t test the GitHub API, because on Travis unauthenticated
// GitHub API requests are usually blocked due to IP rate limiting
const response = await request(
"https://www.githubstatus.com/api/v2/status.json",
);
expect(response.url).toEqual(
"https://www.githubstatus.com/api/v2/status.json",
);
});

it("request should pass the `redirect` option to fetch", () => {
expect.assertions(1);

const customFetch = async (url: string, options: RequestInit) => {
expect(options.redirect).toEqual("manual");
return await fetch(url, options);
};

return request("/", {
request: {
redirect: "manual",
fetch: customFetch,
},
});
});

it("options.request.fetch", async () => {
expect.assertions(1);

const response = await request("/", {
request: {
fetch: () =>
Promise.resolve({
status: 200,
headers: new Headers({
"Content-Type": "application/json; charset=utf-8",
}),
url: "http://api.github.com/",
json() {
return Promise.resolve("funk");
},
}),
},
});
expect(response.data).toEqual("funk");
});

it("Request TypeError error with an Error cause", async () => {
expect.assertions(2);

try {
// 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: () =>
Promise.reject(
Object.assign(new TypeError("fetch failed"), {
cause: new Error("bad"),
}),
),
},
});
throw new Error("should not resolve");
} catch (error) {
expect(error.status).toEqual(500);
expect(error.message).toEqual("bad");
}
});

it("Request TypeError error with a string cause", async () => {
expect.assertions(2);

const mock = fetchMock.sandbox().get("https://127.0.0.1:8/", {
throws: Object.assign(new TypeError("fetch failed"), { cause: "bad" }),
});

try {
// 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: () =>
Promise.reject(
Object.assign(new TypeError("fetch failed"), {
cause: "bad",
}),
),
},
});
throw new Error("should not resolve");
} catch (error) {
expect(error.status).toEqual(500);
expect(error.message).toEqual("bad");
}
});
});
Loading

0 comments on commit af8ef43

Please sign in to comment.