|
1 | 1 | import fetchMock from "fetch-mock";
|
2 |
| -import { RequestOptions } from "https"; |
3 |
| -import { HttpsProxyAgent } from "https-proxy-agent"; |
| 2 | +import { createServer, type Server } from "https"; |
| 3 | +import { Octokit, getProxyAgent, customFetch } from "../src"; |
| 4 | +import { ProxyAgent } from "undici"; |
| 5 | + |
| 6 | +// mock undici such that we can substitute our own fetch implementation |
| 7 | +// but use the actual ProxyAgent implementation for most tests. the |
| 8 | +// exception is "should call undiciFetch with the correct dispatcher" |
| 9 | +// where we want to validate that a mocked ProxyAgent is passed through |
| 10 | +// to undici.fetch. |
| 11 | +jest.mock("undici", () => { |
| 12 | + return { |
| 13 | + fetch: jest.fn(), |
| 14 | + ProxyAgent: jest.requireActual("undici").ProxyAgent, |
| 15 | + }; |
| 16 | +}); |
| 17 | +const undici = jest.requireMock("undici"); |
4 | 18 |
|
5 |
| -import { Octokit } from "../src"; |
| 19 | +describe("Smoke test", () => { |
| 20 | + let server: Server; |
6 | 21 |
|
7 |
| -jest.mock("https-proxy-agent"); |
| 22 | + beforeAll((done) => { |
| 23 | + server = createServer( |
| 24 | + { |
| 25 | + requestCert: false, |
| 26 | + rejectUnauthorized: false, |
| 27 | + }, |
| 28 | + (request: any, response: any) => { |
| 29 | + expect(request.method).toEqual("GET"); |
| 30 | + expect(request.url).toEqual("/"); |
| 31 | + |
| 32 | + response.writeHead(200); |
| 33 | + response.write("ok"); |
| 34 | + response.end(); |
| 35 | + }, |
| 36 | + ); |
| 37 | + |
| 38 | + server.listen(0, done); |
| 39 | + }); |
8 | 40 |
|
9 |
| -describe("Smoke test", () => { |
10 | 41 | beforeEach(() => {
|
11 | 42 | delete process.env.GITHUB_TOKEN;
|
12 | 43 | delete process.env.INPUT_GITHUB_TOKEN;
|
13 | 44 | delete process.env.GITHUB_ACTION;
|
14 | 45 | delete process.env.GITHUB_API_URL;
|
15 | 46 | delete process.env.HTTPS_PROXY;
|
16 | 47 | delete process.env.https_proxy;
|
| 48 | + delete process.env.HTTP_PROXY; |
| 49 | + delete process.env.http_proxy; |
| 50 | + }); |
| 51 | + |
| 52 | + afterAll((done) => { |
| 53 | + server.close(done); |
| 54 | + jest.unmock("undici"); |
| 55 | + }); |
| 56 | + |
| 57 | + it("should return a ProxyAgent for the httpProxy environment variable", () => { |
| 58 | + process.env.HTTP_PROXY = "https://127.0.0.1"; |
| 59 | + const agent = getProxyAgent(); |
| 60 | + expect(agent).toBeInstanceOf(ProxyAgent); |
| 61 | + }); |
| 62 | + |
| 63 | + it("should return a ProxyAgent for the httpsProxy environment variable", () => { |
| 64 | + process.env.HTTPS_PROXY = "https://127.0.0.1"; |
| 65 | + const agent = getProxyAgent(); |
| 66 | + expect(agent).toBeInstanceOf(ProxyAgent); |
| 67 | + }); |
| 68 | + |
| 69 | + it("should return undefined if no proxy environment variables are set", () => { |
| 70 | + const agent = getProxyAgent(); |
| 71 | + expect(agent).toBeUndefined(); |
17 | 72 | });
|
18 | 73 |
|
19 | 74 | it("happy path with GITHUB_TOKEN", () => {
|
@@ -175,11 +230,12 @@ describe("Smoke test", () => {
|
175 | 230 | title: "My test issue",
|
176 | 231 | });
|
177 | 232 |
|
178 |
| - expect(data).toStrictEqual({ ok: true }); |
| 233 | + // TODO: need a follow up issue to clean this up |
| 234 | + expect(JSON.stringify(data)).toStrictEqual(JSON.stringify({ ok: true })); |
179 | 235 | });
|
180 | 236 |
|
181 | 237 | it.each(["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"])(
|
182 |
| - "Uses https-proxy-agent with %s env var", |
| 238 | + "Uses ProxyAgent with %s env var", |
183 | 239 | async (https_proxy_env) => {
|
184 | 240 | process.env.GITHUB_TOKEN = "secret123";
|
185 | 241 | process.env.GITHUB_ACTION = "test";
|
@@ -209,52 +265,46 @@ describe("Smoke test", () => {
|
209 | 265 | title: "My test issue",
|
210 | 266 | });
|
211 | 267 |
|
212 |
| - expect(HttpsProxyAgent).toHaveBeenCalled(); |
213 |
| - |
214 | 268 | const [call] = fetchSandbox.calls();
|
215 | 269 | expect(call[0]).toEqual(
|
216 | 270 | "https://api.github.com/repos/octocat/hello-world/issues",
|
217 | 271 | );
|
218 |
| - expect((call[1] as RequestOptions).agent).toBeInstanceOf(HttpsProxyAgent); |
219 | 272 | },
|
220 | 273 | );
|
| 274 | + describe("customFetch", () => { |
| 275 | + afterAll(() => { |
| 276 | + delete process.env.HTTPS_PROXY; |
| 277 | + jest.clearAllMocks(); |
| 278 | + }); |
221 | 279 |
|
222 |
| - it("Uses the explicitly provided request.agent value if it's provided", async () => { |
223 |
| - process.env.GITHUB_TOKEN = "secret123"; |
224 |
| - process.env.GITHUB_ACTION = "test"; |
225 |
| - process.env.HTTPS_PROXY = "https://127.0.0.1"; |
226 |
| - |
227 |
| - const fetchSandbox = fetchMock.sandbox(); |
228 |
| - const mock = fetchSandbox.post( |
229 |
| - "path:/repos/octocat/hello-world/issues", |
230 |
| - { id: 1 }, |
231 |
| - { |
232 |
| - body: { |
233 |
| - title: "My test issue", |
234 |
| - }, |
235 |
| - }, |
236 |
| - ); |
| 280 | + it("should call undiciFetch with the correct dispatcher", async () => { |
| 281 | + process.env.HTTPS_PROXY = "https://127.0.0.1"; |
| 282 | + const expectedAgent = new ProxyAgent("https://127.0.0.1"); |
237 | 283 |
|
238 |
| - expect(Octokit).toBeInstanceOf(Function); |
239 |
| - const octokit = new Octokit({ |
240 |
| - auth: "secret123", |
241 |
| - request: { |
242 |
| - fetch: mock, |
243 |
| - agent: null, |
244 |
| - }, |
245 |
| - }); |
246 |
| - await octokit.request("POST /repos/{owner}/{repo}/issues", { |
247 |
| - owner: "octocat", |
248 |
| - repo: "hello-world", |
249 |
| - title: "My test issue", |
250 |
| - }); |
| 284 | + jest.mock("../src", () => { |
| 285 | + const actualModule = jest.requireActual("../src"); |
| 286 | + return { |
| 287 | + ...actualModule, |
| 288 | + getProxyAgent: jest.fn(() => expectedAgent), |
| 289 | + }; |
| 290 | + }); |
| 291 | + expect(JSON.stringify(getProxyAgent())).toBe( |
| 292 | + JSON.stringify(expectedAgent), |
| 293 | + ); |
251 | 294 |
|
252 |
| - expect(HttpsProxyAgent).toHaveBeenCalled(); |
| 295 | + // mock undici.fetch to extract the `dispatcher` option passed in. |
| 296 | + // this allows us to verify that `customFetch` correctly sets |
| 297 | + // the dispatcher to `expectedAgent` when HTTPS_PROXY is set. |
| 298 | + let dispatcher: any; |
| 299 | + (undici.fetch as jest.Mock).mockImplementation( |
| 300 | + (_url: string, options: any) => { |
| 301 | + dispatcher = options.dispatcher; |
253 | 302 |
|
254 |
| - const [call] = fetchSandbox.calls(); |
255 |
| - expect(call[0]).toEqual( |
256 |
| - "https://api.github.com/repos/octocat/hello-world/issues", |
257 |
| - ); |
258 |
| - expect((call[1] as RequestOptions).agent).toBeNull(); |
| 303 | + return Promise.resolve(new Response()); |
| 304 | + }, |
| 305 | + ); |
| 306 | + await customFetch("http://api.github.com", {}); |
| 307 | + expect(JSON.stringify(dispatcher)).toEqual(JSON.stringify(expectedAgent)); |
| 308 | + }); |
259 | 309 | });
|
260 | 310 | });
|
0 commit comments