From 3269cdc73e6700e5d78ab86098010ee93f84e50b Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 09:14:54 -0500 Subject: [PATCH 01/10] test: remove MSW in favor of nock --- __tests__/cmds/openapi/index.test.ts | 45 ++++++++++------------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/__tests__/cmds/openapi/index.test.ts b/__tests__/cmds/openapi/index.test.ts index 854e59f4c..2dd9a36e6 100644 --- a/__tests__/cmds/openapi/index.test.ts +++ b/__tests__/cmds/openapi/index.test.ts @@ -2,8 +2,6 @@ import fs from 'node:fs'; import chalk from 'chalk'; -import { http } from 'msw'; -import { setupServer } from 'msw/node'; import nock from 'nock'; import prompts from 'prompts'; import { describe, beforeAll, beforeEach, afterEach, it, expect, vi } from 'vitest'; @@ -1350,37 +1348,24 @@ describe('rdme openapi', () => { }); it('should send proper headers in GitHub Actions CI for spec hosted at URL', async () => { - expect.assertions(8); const registryUUID = getRandomRegistryId(); const spec = 'https://example.com/openapi.json'; - // TODO: move all of this boilerplate to the top-level once we migrate everything over to MSW - const server = setupServer(...[]); + const mock = getAPIMock() + .post('/api/v1/api-registry', body => body.match('form-data; name="spec"')) + .reply(201, { registryUUID }); - server.listen({ onUnhandledRequest: 'error' }); + const exampleMock = nock('https://example.com').get('/openapi.json').reply(200, petstoreWeird); - server.use( - ...[ - http.post(`${config.host}/api/v1/api-registry`, async ({ request }) => { - const body = await request.text(); - expect(body).toMatch('form-data; name="spec"'); - return Response.json({ registryUUID }, { status: 201 }); - }), - http.get(spec, () => { - return Response.json(petstoreWeird, { status: 200 }); - }), - http.put(`${config.host}/api/v1/api-specification/${id}`, async ({ request }) => { - expect(request.headers.get('authorization')).toBeBasicAuthApiKey(key); - expect(request.headers.get('x-rdme-ci')).toBe('GitHub Actions (test)'); - expect(request.headers.get('x-readme-source')).toBe('cli-gh'); - expect(request.headers.get('x-readme-source-url')).toBe(spec); - expect(request.headers.get('x-readme-version')).toBe(version); - const body = await request.json(); - expect(body).toStrictEqual({ registryUUID }); - return Response.json({ _id: 1 }, { status: 201, headers: { location: exampleRefLocation } }); - }), - ], - ); + const putMock = getAPIMock({ + 'x-rdme-ci': 'GitHub Actions (test)', + 'x-readme-source': 'cli-gh', + 'x-readme-source-url': spec, + 'x-readme-version': version, + }) + .put(`/api/v1/api-specification/${id}`, { registryUUID }) + .basicAuth({ user: key }) + .reply(201, { _id: 1 }, { location: exampleRefLocation }); await expect( openapi.run({ @@ -1391,7 +1376,9 @@ describe('rdme openapi', () => { }), ).resolves.toBe(successfulUpdate(spec)); - return server.resetHandlers(); + putMock.done(); + exampleMock.done(); + return mock.done(); }); }); }); From f72351a22a231b80a09a03dd0734bd7514976950 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 09:18:10 -0500 Subject: [PATCH 02/10] test: remove useless connection delay turns out this isn't really necessary at all and tests run way faster without this! --- __tests__/cmds/openapi/index.test.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/__tests__/cmds/openapi/index.test.ts b/__tests__/cmds/openapi/index.test.ts index 2dd9a36e6..38679c49d 100644 --- a/__tests__/cmds/openapi/index.test.ts +++ b/__tests__/cmds/openapi/index.test.ts @@ -133,7 +133,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, [{ _id: 'spec1', title: 'spec1_title' }]) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -163,7 +162,6 @@ describe('rdme openapi', () => { const postMock = getAPIMockWithVersionHeader(version) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -194,7 +192,6 @@ describe('rdme openapi', () => { const postMock = getAPIMockWithVersionHeader(version) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -414,7 +411,6 @@ describe('rdme openapi', () => { { _id: 'spec2', title: 'spec2_title' }, ]) .put('/api/v1/api-specification/spec2', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -482,7 +478,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, [{ _id: 'spec1', title: 'spec1_title' }]) .put('/api/v1/api-specification/spec1', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -542,7 +537,6 @@ describe('rdme openapi', () => { .post('/api/v1/api-registry', body => body.match('form-data; name="spec"')) .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }) .put('/api/v1/api-specification/spec1', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(function (uri, rBody, cb) { expect(this.req.headers['x-readme-version']).toBeUndefined(); @@ -822,7 +816,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, []) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(400, errorObject); @@ -854,7 +847,6 @@ describe('rdme openapi', () => { const putMock = getAPIMockWithVersionHeader(version) .put(`/api/v1/api-specification/${id}`, { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(400, errorObject); @@ -920,7 +912,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, []) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(400, errorObject); @@ -947,7 +938,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, []) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(400, 'some non-JSON upload error'); @@ -978,7 +968,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, []) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(500, 'Application Error'); @@ -1026,7 +1015,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, [{ _id: 'spec1', title: 'spec1_title' }]) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -1069,7 +1057,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, [{ _id: 'spec1', title: 'spec1_title' }]) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -1116,7 +1103,6 @@ describe('rdme openapi', () => { { _id: 'spec2', title: 'spec2_title' }, ]) .put('/api/v1/api-specification/spec2', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 'spec2' }, { location: exampleRefLocation }); @@ -1153,7 +1139,6 @@ describe('rdme openapi', () => { const mockWithHeader = getAPIMockWithVersionHeader(altVersion) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -1190,7 +1175,6 @@ describe('rdme openapi', () => { const postMock = getAPIMockWithVersionHeader(version) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -1230,7 +1214,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, [{ _id: 'spec1', title: 'spec1_title' }]) .put('/api/v1/api-specification/spec1', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); @@ -1268,7 +1251,6 @@ describe('rdme openapi', () => { .basicAuth({ user: key }) .reply(200, [{ _id: 'spec1', title: 'spec1_title' }]) .post('/api/v1/api-specification', { registryUUID }) - .delayConnection(1000) .basicAuth({ user: key }) .reply(201, { _id: 1 }, { location: exampleRefLocation }); From f80d95a617b7b2a88b177f14f1e5346674db5283 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 09:42:50 -0500 Subject: [PATCH 03/10] test: remove last instance of MSW --- .../single-threaded/openapi/index.test.ts | 223 +++++++++--------- 1 file changed, 111 insertions(+), 112 deletions(-) diff --git a/__tests__/single-threaded/openapi/index.test.ts b/__tests__/single-threaded/openapi/index.test.ts index cc25941a2..bf818fcd1 100644 --- a/__tests__/single-threaded/openapi/index.test.ts +++ b/__tests__/single-threaded/openapi/index.test.ts @@ -2,14 +2,13 @@ import fs from 'node:fs'; import chalk from 'chalk'; -import { http } from 'msw'; -import { setupServer } from 'msw/node'; +import nock from 'nock'; import prompts from 'prompts'; -import { describe, beforeAll, beforeEach, afterEach, it, expect, vi, afterAll } from 'vitest'; +import { describe, beforeAll, beforeEach, afterEach, it, expect, vi } from 'vitest'; import OpenAPICommand from '../../../src/cmds/openapi/index.js'; import config from '../../../src/lib/config.js'; -import { getAPIMockMSW } from '../../helpers/get-api-mock.js'; +import getAPIMock, { getAPIMockWithVersionHeader } from '../../helpers/get-api-mock.js'; import { after, before } from '../../helpers/get-gha-setup.js'; import { after as afterGHAEnv, before as beforeGHAEnv } from '../../helpers/setup-gha-env.js'; @@ -41,12 +40,12 @@ const getCommandOutput = () => { const getRandomRegistryId = () => Math.random().toString(36).substring(2); -const server = setupServer(...[]); - describe('rdme openapi (single-threaded)', () => { let testWorkingDir: string; - beforeAll(() => server.listen({ onUnhandledRequest: 'error' })); + beforeAll(() => { + nock.disableNetConnect(); + }); beforeEach(() => { consoleInfoSpy = vi.spyOn(console, 'info').mockImplementation(() => {}); @@ -58,35 +57,31 @@ describe('rdme openapi (single-threaded)', () => { consoleInfoSpy.mockRestore(); consoleWarnSpy.mockRestore(); - server.resetHandlers(); - process.chdir(testWorkingDir); - }); - afterAll(() => server.close()); + nock.cleanAll(); + }); describe('upload', () => { it('should discover and upload an API definition if none is provided', async () => { - expect.assertions(6); const registryUUID = getRandomRegistryId(); - server.use( - ...[ - getAPIMockMSW(`/api/v1/version/${version}`, 200, { json: { version } }, key), - http.post(`${config.host}/api/v1/api-registry`, async ({ request }) => { - const body = await request.text(); - expect(body).toMatch('form-data; name="spec"'); - return Response.json({ registryUUID, spec: { openapi: '3.0.0' } }, { status: 201 }); - }), - getAPIMockMSW('/api/v1/api-specification', 200, { json: [] }, key, { 'x-readme-version': version }), - http.post(`${config.host}/api/v1/api-specification`, async ({ request }) => { - const body = await request.json(); - expect(body).toStrictEqual({ registryUUID }); - expect(request.headers.get('authorization')).toBeBasicAuthApiKey(key); - return Response.json({ _id: 1 }, { status: 201, headers: { location: exampleRefLocation } }); - }), - ], - ); + const mock = getAPIMock() + .get(`/api/v1/version/${version}`) + .basicAuth({ user: key }) + .reply(200, { version }) + .post('/api/v1/api-registry', body => { + return body.match('form-data; name="spec"'); + }) + .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }) + .get('/api/v1/api-specification') + .basicAuth({ user: key }) + .reply(200, []); + + const postMock = getAPIMockWithVersionHeader(version) + .post('/api/v1/api-specification', { registryUUID }) + .basicAuth({ user: key }) + .reply(201, { _id: 1 }, { location: exampleRefLocation }); const spec = 'petstore.json'; @@ -101,33 +96,35 @@ describe('rdme openapi (single-threaded)', () => { expect(console.info).toHaveBeenCalledTimes(1); const output = getCommandOutput(); - return expect(output).toBe(chalk.yellow(`ℹ️ We found ${spec} and are attempting to upload it.`)); + expect(output).toBe(chalk.yellow(`ℹ️ We found ${spec} and are attempting to upload it.`)); + + postMock.done(); + return mock.done(); }); it('should use specified working directory and upload the expected content', async () => { - expect.assertions(6); let requestBody; const registryUUID = getRandomRegistryId(); - server.use( - ...[ - getAPIMockMSW(`/api/v1/version/${version}`, 200, { json: { version } }, key), - http.post(`${config.host}/api/v1/api-registry`, async ({ request }) => { - const body = await request.text(); - requestBody = body.substring(body.indexOf('{'), body.lastIndexOf('}') + 1); - requestBody = JSON.parse(requestBody); - expect(body).toMatch('form-data; name="spec"'); - return Response.json({ registryUUID, spec: { openapi: '3.0.0' } }, { status: 201 }); - }), - getAPIMockMSW('/api/v1/api-specification', 200, { json: [] }, key, { 'x-readme-version': version }), - http.post(`${config.host}/api/v1/api-specification`, async ({ request }) => { - const body = await request.json(); - expect(body).toStrictEqual({ registryUUID }); - expect(request.headers.get('authorization')).toBeBasicAuthApiKey(key); - return Response.json({ _id: 1 }, { status: 201, headers: { location: exampleRefLocation } }); - }), - ], - ); + const mock = getAPIMock() + .get(`/api/v1/version/${version}`) + .basicAuth({ user: key }) + .reply(200, { version }) + .post('/api/v1/api-registry', body => { + requestBody = body.substring(body.indexOf('{'), body.lastIndexOf('}') + 1); + requestBody = JSON.parse(requestBody); + + return body.match('form-data; name="spec"'); + }) + .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }) + .get('/api/v1/api-specification') + .basicAuth({ user: key }) + .reply(200, []); + + const postMock = getAPIMockWithVersionHeader(version) + .post('/api/v1/api-specification', { registryUUID }) + .basicAuth({ user: key }) + .reply(201, { _id: 1 }, { location: exampleRefLocation }); const spec = 'petstore.json'; @@ -142,24 +139,26 @@ describe('rdme openapi (single-threaded)', () => { expect(console.info).toHaveBeenCalledTimes(0); - return expect(requestBody).toMatchSnapshot(); + expect(requestBody).toMatchSnapshot(); + + postMock.done(); + return mock.done(); }); it('should return spec create info for dry run', async () => { - expect.assertions(3); const registryUUID = getRandomRegistryId(); - server.use( - ...[ - getAPIMockMSW(`/api/v1/version/${version}`, 200, { json: { version } }, key), - http.post(`${config.host}/api/v1/api-registry`, async ({ request }) => { - const body = await request.text(); - expect(body).toMatch('form-data; name="spec"'); - return Response.json({ registryUUID, spec: { openapi: '3.0.0' } }, { status: 201 }); - }), - getAPIMockMSW('/api/v1/api-specification', 200, { json: [] }, key, { 'x-readme-version': version }), - ], - ); + const mock = getAPIMock() + .get(`/api/v1/version/${version}`) + .basicAuth({ user: key }) + .reply(200, { version }) + .post('/api/v1/api-registry', body => { + return body.match('form-data; name="spec"'); + }) + .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }) + .get('/api/v1/api-specification') + .basicAuth({ user: key }) + .reply(200, []); await expect( openapi.run({ @@ -173,9 +172,11 @@ describe('rdme openapi (single-threaded)', () => { ); const output = getCommandOutput(); - return expect(output).toMatch( + expect(output).toMatch( chalk.yellow('🎭 dry run option detected! No API definitions will be created or updated in ReadMe.'), ); + + return mock.done(); }); }); @@ -203,28 +204,26 @@ describe('rdme openapi (single-threaded)', () => { }); it('should create GHA workflow (including workingDirectory)', async () => { - expect.assertions(7); const yamlFileName = 'openapi-file-workingdirectory'; prompts.inject([true, 'openapi-branch-workingdirectory', yamlFileName]); const registryUUID = getRandomRegistryId(); - server.use( - ...[ - getAPIMockMSW(`/api/v1/version/${version}`, 200, { json: { version } }, key), - http.post(`${config.host}/api/v1/api-registry`, async ({ request }) => { - const body = await request.text(); - expect(body).toMatch('form-data; name="spec"'); - return Response.json({ registryUUID, spec: { openapi: '3.0.0' } }, { status: 201 }); - }), - getAPIMockMSW('/api/v1/api-specification', 200, { json: [] }, key, { 'x-readme-version': version }), - http.post(`${config.host}/api/v1/api-specification`, async ({ request }) => { - expect(request.headers.get('authorization')).toBeBasicAuthApiKey(key); - const body = await request.json(); - expect(body).toStrictEqual({ registryUUID }); - return Response.json({ _id: 1 }, { status: 201, headers: { location: exampleRefLocation } }); - }), - ], - ); + const mock = getAPIMock() + .get(`/api/v1/version/${version}`) + .basicAuth({ user: key }) + .reply(200, { version }) + .post('/api/v1/api-registry', body => { + return body.match('form-data; name="spec"'); + }) + .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }) + .get('/api/v1/api-specification') + .basicAuth({ user: key }) + .reply(200, []); + + const postMock = getAPIMockWithVersionHeader(version) + .post('/api/v1/api-specification', { registryUUID }) + .basicAuth({ user: key }) + .reply(201, { _id: 1 }, { location: exampleRefLocation }); const spec = 'petstore.json'; @@ -239,11 +238,10 @@ describe('rdme openapi (single-threaded)', () => { expect(yamlOutput).toMatchSnapshot(); expect(fs.writeFileSync).toHaveBeenCalledTimes(2); - return expect(fs.writeFileSync).toHaveBeenNthCalledWith( - 2, - `.github/workflows/${yamlFileName}.yml`, - expect.any(String), - ); + expect(fs.writeFileSync).toHaveBeenNthCalledWith(2, `.github/workflows/${yamlFileName}.yml`, expect.any(String)); + + postMock.done(); + return mock.done(); }); }); @@ -255,31 +253,29 @@ describe('rdme openapi (single-threaded)', () => { afterEach(afterGHAEnv); it('should contain request header with correct URL with working directory', async () => { - expect.assertions(8); const registryUUID = getRandomRegistryId(); - server.use( - ...[ - getAPIMockMSW(`/api/v1/version/${version}`, 200, { json: { version } }, key), - http.post(`${config.host}/api/v1/api-registry`, async ({ request }) => { - const body = await request.text(); - expect(body).toMatch('form-data; name="spec"'); - return Response.json({ registryUUID, spec: { openapi: '3.0.0' } }, { status: 201 }); - }), - getAPIMockMSW('/api/v1/api-specification', 200, { json: [] }, key, { 'x-readme-version': version }), - http.post(`${config.host}/api/v1/api-specification`, async ({ request }) => { - expect(request.headers.get('authorization')).toBeBasicAuthApiKey(key); - expect(request.headers.get('x-rdme-ci')).toBe('GitHub Actions (test)'); - expect(request.headers.get('x-readme-source')).toBe('cli-gh'); - expect(request.headers.get('x-readme-source-url')).toBe( - 'https://github.com/octocat/Hello-World/blob/ffac537e6cbbf934b08745a378932722df287a53/__tests__/__fixtures__/relative-ref-oas/petstore.json', - ); - expect(request.headers.get('x-readme-version')).toBe(version); - const body = await request.json(); - expect(body).toStrictEqual({ registryUUID }); - return Response.json({ _id: 1 }, { status: 201, headers: { location: exampleRefLocation } }); - }), - ], - ); + const mock = getAPIMock() + .get(`/api/v1/version/${version}`) + .basicAuth({ user: key }) + .reply(200, { version }) + .post('/api/v1/api-registry', body => { + return body.match('form-data; name="spec"'); + }) + .reply(201, { registryUUID, spec: { openapi: '3.0.0' } }) + .get('/api/v1/api-specification') + .basicAuth({ user: key }) + .reply(200, []); + + const postMock = getAPIMock({ + 'x-rdme-ci': 'GitHub Actions (test)', + 'x-readme-source': 'cli-gh', + 'x-readme-source-url': + 'https://github.com/octocat/Hello-World/blob/ffac537e6cbbf934b08745a378932722df287a53/__tests__/__fixtures__/relative-ref-oas/petstore.json', + 'x-readme-version': version, + }) + .post('/api/v1/api-specification', { registryUUID }) + .basicAuth({ user: key }) + .reply(201, { _id: 1 }, { location: exampleRefLocation }); const spec = 'petstore.json'; @@ -292,7 +288,10 @@ describe('rdme openapi (single-threaded)', () => { }), ).resolves.toBe(successfulUpload(spec)); - return after(); + after(); + + postMock.done(); + return mock.done(); }); }); }); From 951624f47ed7d14ee885995f896838425394df1e Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 09:43:41 -0500 Subject: [PATCH 04/10] test: remove msw helper --- __tests__/helpers/get-api-mock.ts | 35 ------------------------------- 1 file changed, 35 deletions(-) diff --git a/__tests__/helpers/get-api-mock.ts b/__tests__/helpers/get-api-mock.ts index 2d8f63e8c..70c23cdf8 100644 --- a/__tests__/helpers/get-api-mock.ts +++ b/__tests__/helpers/get-api-mock.ts @@ -1,6 +1,5 @@ import type { Headers } from 'node-fetch'; -import { http } from 'msw'; import nock from 'nock'; import config from '../../src/lib/config.js'; @@ -57,37 +56,3 @@ function validateHeaders(headers: Headers, basicAuthUser: string, expectedReqHea throw new Error(`Expected user agent '${getUserAgent()}', received '${userAgent}'`); } } - -export function getAPIMockMSW( - /** - * API route to mock against, must start with slash - * @example /api/v1 - */ - path: string = '', - status = 200, - response?: { json?: unknown; text?: string }, - /** - * A string which represents the user that's passed via basic authentication. - * In our case, this will almost always be the user's ReadMe API key. - */ - basicAuthUser = '', - /** Any request headers that should be matched. */ - expectedReqHeaders: ReqHeaders = {}, - proxy = '', -) { - return http.get(`${proxy}${config.host}${path}`, ({ request }) => { - try { - // @ts-expect-error once we move off node-fetch, we can make these types consistent - validateHeaders(request.headers, basicAuthUser, expectedReqHeaders); - let httpResponse = new Response(null, { status }); - if (response?.json) { - httpResponse = Response.json(response.json, { status }); - } else if (response?.text) { - httpResponse = new Response(response.text, { status }); - } - return httpResponse; - } catch (e) { - throw new Error(`Error mocking GET request to https://dash.readme.com${path}: ${e.message}`); - } - }); -} From 1d2b5f19ad1a93ae7096984f47695ce2b6fef6e3 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 09:43:57 -0500 Subject: [PATCH 05/10] chore(deps): uninstall msw --- package-lock.json | 435 ---------------------------------------------- package.json | 1 - 2 files changed, 436 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0d97856c4..a3291b3dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,7 +72,6 @@ "husky": "^9.0.10", "js-yaml": "^4.1.0", "knip": "^5.0.2", - "msw": "^2.0.3", "nock": "^14.0.0-beta.6", "openapi-types": "^12.1.3", "prettier": "^3.0.2", @@ -311,24 +310,6 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "node_modules/@bundled-es-modules/cookie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", - "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", - "dev": true, - "dependencies": { - "cookie": "^0.5.0" - } - }, - "node_modules/@bundled-es-modules/statuses": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", - "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", - "dev": true, - "dependencies": { - "statuses": "^2.0.1" - } - }, "node_modules/@commitlint/cli": { "version": "19.3.0", "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-19.3.0.tgz", @@ -1153,135 +1134,6 @@ "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, - "node_modules/@inquirer/confirm": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-3.1.1.tgz", - "integrity": "sha512-epf2RVHJJxX5qF85U41PBq9qq2KTJW9sKNLx6+bb2/i2rjXgeoHVGUm8kJxZHavrESgXgBLKCABcfOJYIso8cQ==", - "dev": true, - "dependencies": { - "@inquirer/core": "^7.1.1", - "@inquirer/type": "^1.2.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/core": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-7.1.1.tgz", - "integrity": "sha512-rD1UI3eARN9qJBcLRXPOaZu++Bg+xsk0Tuz1EUOXEW+UbYif1sGjr0Tw7lKejHzKD9IbXE1CEtZ+xR/DrNlQGQ==", - "dev": true, - "dependencies": { - "@inquirer/type": "^1.2.1", - "@types/mute-stream": "^0.0.4", - "@types/node": "^20.11.30", - "@types/wrap-ansi": "^3.0.0", - "ansi-escapes": "^4.3.2", - "chalk": "^4.1.2", - "cli-spinners": "^2.9.2", - "cli-width": "^4.1.0", - "figures": "^3.2.0", - "mute-stream": "^1.0.0", - "signal-exit": "^4.1.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/core/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@inquirer/core/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@inquirer/core/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@inquirer/core/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@inquirer/core/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@inquirer/core/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/core/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@inquirer/type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-1.2.1.tgz", - "integrity": "sha512-xwMfkPAxeo8Ji/IxfUSqzRi0/+F2GIqJmpc5/thelgMGsjNZcjDDRBO9TLXT1s/hdx/mK5QbVIvgoLIFgXhTMQ==", - "dev": true, - "engines": { - "node": ">=18" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1413,32 +1265,6 @@ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, - "node_modules/@mswjs/cookies": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-1.1.0.tgz", - "integrity": "sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@mswjs/interceptors": { - "version": "0.26.15", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.26.15.tgz", - "integrity": "sha512-HM47Lu1YFmnYHKMBynFfjCp0U/yRskHj/8QEJW0CBEPOlw8Gkmjfll+S9b8M7V5CNDw2/ciRxjjnWeaCiblSIQ==", - "dev": true, - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1539,28 +1365,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", - "dev": true - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", - "dev": true, - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" - } - }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", - "dev": true - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2180,12 +1984,6 @@ "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true - }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -2274,15 +2072,6 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", "dev": true }, - "node_modules/@types/mute-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/@types/mute-stream/-/mute-stream-0.0.4.tgz", - "integrity": "sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/nlcst": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@types/nlcst/-/nlcst-1.0.4.tgz", @@ -2341,12 +2130,6 @@ "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, - "node_modules/@types/statuses": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.5.tgz", - "integrity": "sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==", - "dev": true - }, "node_modules/@types/supports-color": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.3.tgz", @@ -2381,12 +2164,6 @@ "integrity": "sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw==", "dev": true }, - "node_modules/@types/wrap-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", - "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", @@ -3274,33 +3051,6 @@ "node": ">=8" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -4237,15 +3987,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -4600,15 +4341,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/core-js-compat": { "version": "3.36.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", @@ -6934,30 +6666,6 @@ "node": "^12.20 || >= 14.13" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -7574,15 +7282,6 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" - } - }, "node_modules/gray-matter": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", @@ -7898,12 +7597,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/headers-polyfill": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.3.tgz", - "integrity": "sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==", - "dev": true - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -8535,12 +8228,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-node-process": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", - "dev": true - }, "node_modules/is-npm": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", @@ -11033,98 +10720,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/msw": { - "version": "2.2.14", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.2.14.tgz", - "integrity": "sha512-64i8rNCa1xzDK8ZYsTrVMli05D687jty8+Th+PU5VTbJ2/4P7fkQFVyDQ6ZFT5FrNR8z2BHhbY47fKNvfHrumA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.0", - "@bundled-es-modules/statuses": "^1.0.1", - "@inquirer/confirm": "^3.0.0", - "@mswjs/cookies": "^1.1.0", - "@mswjs/interceptors": "^0.26.14", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.6.0", - "@types/statuses": "^2.0.4", - "chalk": "^4.1.2", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.2", - "is-node-process": "^1.2.0", - "outvariant": "^1.4.2", - "path-to-regexp": "^6.2.0", - "strict-event-emitter": "^0.5.1", - "type-fest": "^4.9.0", - "yargs": "^17.7.2" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.7.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/msw/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/msw/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/msw/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/msw/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/multistream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", @@ -11171,15 +10766,6 @@ "mustache": "bin/mustache" } }, - "node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -11789,12 +11375,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/outvariant": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.2.tgz", - "integrity": "sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==", - "dev": true - }, "node_modules/p-cancelable": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", @@ -13916,15 +13496,6 @@ "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", "dev": true }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/std-env": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", @@ -13971,12 +13542,6 @@ "node": ">=10" } }, - "node_modules/strict-event-emitter": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", - "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", - "dev": true - }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", diff --git a/package.json b/package.json index 7dd88cd5c..b514dc3c4 100644 --- a/package.json +++ b/package.json @@ -96,7 +96,6 @@ "husky": "^9.0.10", "js-yaml": "^4.1.0", "knip": "^5.0.2", - "msw": "^2.0.3", "nock": "^14.0.0-beta.6", "openapi-types": "^12.1.3", "prettier": "^3.0.2", From 1be03902c70850be5b09d7128598118ab32d6ee4 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 09:55:42 -0500 Subject: [PATCH 06/10] chore: whoops also remove this --- __tests__/helpers/get-api-mock.ts | 34 ------------------------------- 1 file changed, 34 deletions(-) diff --git a/__tests__/helpers/get-api-mock.ts b/__tests__/helpers/get-api-mock.ts index 70c23cdf8..752f47fe9 100644 --- a/__tests__/helpers/get-api-mock.ts +++ b/__tests__/helpers/get-api-mock.ts @@ -1,17 +1,8 @@ -import type { Headers } from 'node-fetch'; - import nock from 'nock'; import config from '../../src/lib/config.js'; import { getUserAgent } from '../../src/lib/readmeAPIFetch.js'; -/** - * A type describing a raw object of request headers. - * We use this in our API request mocking to validate that the request - * contains all the expected headers. - */ -type ReqHeaders = Record; - /** * Nock wrapper that adds required `user-agent` request header * so it gets properly picked up by nock. @@ -31,28 +22,3 @@ export function getAPIMockWithVersionHeader(v: string) { 'x-readme-version': v, }); } - -function validateHeaders(headers: Headers, basicAuthUser: string, expectedReqHeaders: ReqHeaders) { - // validate all headers in expectedReqHeaders - Object.keys(expectedReqHeaders).forEach(reqHeaderKey => { - if (headers.get(reqHeaderKey) !== expectedReqHeaders[reqHeaderKey]) { - throw new Error( - `Expected the request header '${expectedReqHeaders[reqHeaderKey]}', received '${headers.get(reqHeaderKey)}'`, - ); - } - }); - - // validate basic auth header - if (basicAuthUser) { - const encodedApiKey = headers.get('Authorization').split(' ')[1]; - const decodedApiKey = Buffer.from(encodedApiKey, 'base64').toString(); - if (decodedApiKey !== `${basicAuthUser}:`) { - throw new Error(`Expected API key '${basicAuthUser}', received '${decodedApiKey}'`); - } - } - - const userAgent = headers.get('user-agent'); - if (userAgent !== getUserAgent()) { - throw new Error(`Expected user agent '${getUserAgent()}', received '${userAgent}'`); - } -} From b9cc12bf17bf6a6d3e9465dfad8ad2a19cbaa627 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 10:00:29 -0500 Subject: [PATCH 07/10] chore(deps): remove node-fetch and formdata-node --- .eslintrc | 5 -- __tests__/lib/fetch.test.ts | 1 - __tests__/lib/prompts.test.ts | 2 - bin/json-schema-store.js | 2 - package-lock.json | 94 --------------------------------- package.json | 2 - src/cmds/categories/create.ts | 1 - src/cmds/openapi/index.ts | 2 - src/cmds/versions/create.ts | 1 - src/cmds/versions/update.ts | 1 - src/lib/deleteDoc.ts | 2 - src/lib/getCategories.ts | 2 - src/lib/getDocs.ts | 2 - src/lib/getPkgVersion.ts | 2 - src/lib/prompts.ts | 1 - src/lib/readmeAPIFetch.ts | 13 ++--- src/lib/streamSpecToRegistry.ts | 1 - src/lib/syncDocsPath.ts | 1 - 18 files changed, 7 insertions(+), 128 deletions(-) diff --git a/.eslintrc b/.eslintrc index 26ed767bf..3160ee89f 100644 --- a/.eslintrc +++ b/.eslintrc @@ -55,11 +55,6 @@ "error", { "paths": [ - { - "name": "node-fetch", - "importNames": ["default"], - "message": "Avoid using `node-fetch` directly and instead use the fetch wrapper located in `lib/readmeAPIFetch.ts`. See CONTRIBUTING.md for more information." - }, { "name": "ci-info", "message": "The `ci-info` package is difficult to test because misleading results will appear when running tests in the GitHub Actions runner. Instead of importing this package directly, create a wrapper function in `lib/isCI.ts` and import that instead." diff --git a/__tests__/lib/fetch.test.ts b/__tests__/lib/fetch.test.ts index 3c56a54d8..047ca8890 100644 --- a/__tests__/lib/fetch.test.ts +++ b/__tests__/lib/fetch.test.ts @@ -1,5 +1,4 @@ /* eslint-disable no-console */ -import { Headers } from 'node-fetch'; import { describe, beforeEach, afterEach, it, expect, vi } from 'vitest'; import pkg from '../../package.json' with { type: 'json' }; diff --git a/__tests__/lib/prompts.test.ts b/__tests__/lib/prompts.test.ts index 05a951472..d1dba0a90 100644 --- a/__tests__/lib/prompts.test.ts +++ b/__tests__/lib/prompts.test.ts @@ -1,5 +1,3 @@ -import type { Response } from 'node-fetch'; - import prompts from 'prompts'; import { describe, it, expect } from 'vitest'; diff --git a/bin/json-schema-store.js b/bin/json-schema-store.js index ac56f2518..7d5815ab0 100755 --- a/bin/json-schema-store.js +++ b/bin/json-schema-store.js @@ -4,8 +4,6 @@ import fs from 'node:fs/promises'; import path from 'node:path'; -// eslint-disable-next-line no-restricted-imports -import fetch from 'node-fetch'; import prettier from 'prettier'; const files = [ diff --git a/package-lock.json b/package-lock.json index a3291b3dd..0ec8dc946 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,11 +16,9 @@ "command-line-usage": "^7.0.1", "configstore": "^6.0.0", "debug": "^4.3.3", - "formdata-node": "^6.0.3", "gray-matter": "^4.0.1", "ignore": "^5.2.0", "mime-types": "^2.1.35", - "node-fetch": "^3.3.2", "oas": "^24.0.0", "oas-normalize": "^11.0.1", "open": "^10.0.2", @@ -4482,14 +4480,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -6644,28 +6634,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6795,25 +6763,6 @@ "node": ">=0.4.x" } }, - "node_modules/formdata-node": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-6.0.3.tgz", - "integrity": "sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==", - "engines": { - "node": ">= 18" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -10891,41 +10840,6 @@ "node": ">=10" } }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-fetch-h2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", @@ -15365,14 +15279,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index b514dc3c4..d6d6a014d 100644 --- a/package.json +++ b/package.json @@ -43,11 +43,9 @@ "command-line-usage": "^7.0.1", "configstore": "^6.0.0", "debug": "^4.3.3", - "formdata-node": "^6.0.3", "gray-matter": "^4.0.1", "ignore": "^5.2.0", "mime-types": "^2.1.35", - "node-fetch": "^3.3.2", "oas": "^24.0.0", "oas-normalize": "^11.0.1", "open": "^10.0.2", diff --git a/src/cmds/categories/create.ts b/src/cmds/categories/create.ts index 0551af2c7..4763d1746 100644 --- a/src/cmds/categories/create.ts +++ b/src/cmds/categories/create.ts @@ -1,7 +1,6 @@ import type { AuthenticatedCommandOptions } from '../../lib/baseCommand.js'; import chalk from 'chalk'; -import { Headers } from 'node-fetch'; import Command, { CommandCategories } from '../../lib/baseCommand.js'; import config from '../../lib/config.js'; diff --git a/src/cmds/openapi/index.ts b/src/cmds/openapi/index.ts index 8bebe0f6b..f2668fed9 100644 --- a/src/cmds/openapi/index.ts +++ b/src/cmds/openapi/index.ts @@ -1,9 +1,7 @@ import type { AuthenticatedCommandOptions } from '../../lib/baseCommand.js'; import type { OpenAPIPromptOptions } from '../../lib/prompts.js'; -import type { RequestInit, Response } from 'node-fetch'; import chalk from 'chalk'; -import { Headers } from 'node-fetch'; import ora from 'ora'; import parse from 'parse-link-header'; diff --git a/src/cmds/versions/create.ts b/src/cmds/versions/create.ts index 72e90dd74..43488c472 100644 --- a/src/cmds/versions/create.ts +++ b/src/cmds/versions/create.ts @@ -1,7 +1,6 @@ import type { Version } from './index.js'; import type { AuthenticatedCommandOptions } from '../../lib/baseCommand.js'; -import { Headers } from 'node-fetch'; import prompts from 'prompts'; import semver from 'semver'; diff --git a/src/cmds/versions/update.ts b/src/cmds/versions/update.ts index 6055123f1..fcf7dcedc 100644 --- a/src/cmds/versions/update.ts +++ b/src/cmds/versions/update.ts @@ -2,7 +2,6 @@ import type { CommonOptions } from './create.js'; import type { Version } from './index.js'; import type { AuthenticatedCommandOptions } from '../../lib/baseCommand.js'; -import { Headers } from 'node-fetch'; import prompts from 'prompts'; import Command, { CommandCategories } from '../../lib/baseCommand.js'; diff --git a/src/lib/deleteDoc.ts b/src/lib/deleteDoc.ts index d31ae2ed4..52912ec0e 100644 --- a/src/lib/deleteDoc.ts +++ b/src/lib/deleteDoc.ts @@ -1,7 +1,5 @@ import type { CommandCategories } from './baseCommand.js'; -import { Headers } from 'node-fetch'; - import readmeAPIFetch, { cleanHeaders, handleRes } from './readmeAPIFetch.js'; /** diff --git a/src/lib/getCategories.ts b/src/lib/getCategories.ts index e050c1c02..d72af5572 100644 --- a/src/lib/getCategories.ts +++ b/src/lib/getCategories.ts @@ -1,5 +1,3 @@ -import { Headers } from 'node-fetch'; - import readmeAPIFetch, { cleanHeaders, handleRes } from './readmeAPIFetch.js'; /** diff --git a/src/lib/getDocs.ts b/src/lib/getDocs.ts index 2d8370917..d74f2d569 100644 --- a/src/lib/getDocs.ts +++ b/src/lib/getDocs.ts @@ -1,5 +1,3 @@ -import { Headers } from 'node-fetch'; - import getCategories from './getCategories.js'; import readmeAPIFetch, { cleanHeaders, handleRes } from './readmeAPIFetch.js'; diff --git a/src/lib/getPkgVersion.ts b/src/lib/getPkgVersion.ts index 9a05333af..4c1928bd8 100644 --- a/src/lib/getPkgVersion.ts +++ b/src/lib/getPkgVersion.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line no-restricted-imports -import fetch from 'node-fetch'; import semver from 'semver'; import pkg from '../../package.json' with { type: 'json' }; diff --git a/src/lib/prompts.ts b/src/lib/prompts.ts index 109cfdd57..651d5e16d 100644 --- a/src/lib/prompts.ts +++ b/src/lib/prompts.ts @@ -1,5 +1,4 @@ import type { Version } from '../cmds/versions/index.js'; -import type { Response } from 'node-fetch'; import type { Choice, PromptObject } from 'prompts'; import parse from 'parse-link-header'; diff --git a/src/lib/readmeAPIFetch.ts b/src/lib/readmeAPIFetch.ts index 25823bc96..d0482a00e 100644 --- a/src/lib/readmeAPIFetch.ts +++ b/src/lib/readmeAPIFetch.ts @@ -1,10 +1,8 @@ import type { SpecFileType } from './prepareOas.js'; -import type { RequestInit, Response } from 'node-fetch'; import path from 'node:path'; import mime from 'mime-types'; -import nodeFetch, { Headers } from 'node-fetch'; // eslint-disable-line no-restricted-imports import pkg from '../../package.json' with { type: 'json' }; @@ -119,8 +117,11 @@ async function normalizeFilePath(opts: FilePathDetails) { * Sanitizes and stringifies the `Headers` object for logging purposes */ function sanitizeHeaders(headers: Headers) { - const raw = new Headers(headers).raw(); - if (raw.Authorization) raw.Authorization = ['redacted']; + const raw = Array.from(headers.entries()).reduce>((prev, current) => { + // eslint-disable-next-line no-param-reassign + prev[current[0]] = current[0].toLowerCase() === 'authorization' ? 'redacted' : current[1]; + return prev; + }, {}); return JSON.stringify(raw); } @@ -188,7 +189,7 @@ export default async function readmeAPIFetch( `making ${(options.method || 'get').toUpperCase()} request to ${fullUrl} with headers: ${sanitizeHeaders(headers)}`, ); - return nodeFetch(fullUrl, { + return fetch(fullUrl, { ...options, headers, }).then(res => { @@ -241,7 +242,7 @@ async function handleRes(res: Response, rejectOnJsonError = true) { } /** - * Returns the basic auth header and any other defined headers for use in `node-fetch` API calls. + * Returns the basic auth header and any other defined headers for use in `fetch` API calls. * */ function cleanHeaders( diff --git a/src/lib/streamSpecToRegistry.ts b/src/lib/streamSpecToRegistry.ts index a73445f5f..7f8525078 100644 --- a/src/lib/streamSpecToRegistry.ts +++ b/src/lib/streamSpecToRegistry.ts @@ -1,6 +1,5 @@ import fs from 'node:fs'; -import { FormData } from 'formdata-node'; import ora from 'ora'; import { file as tmpFile } from 'tmp-promise'; diff --git a/src/lib/syncDocsPath.ts b/src/lib/syncDocsPath.ts index 8701cf6b1..83988ef5b 100644 --- a/src/lib/syncDocsPath.ts +++ b/src/lib/syncDocsPath.ts @@ -4,7 +4,6 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import chalk from 'chalk'; -import { Headers } from 'node-fetch'; import toposort from 'toposort'; import APIError from './apiError.js'; From 04fe2f42544be5dc360c916c2f1b6851f3530a7f Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 10:50:21 -0500 Subject: [PATCH 08/10] feat: use undici ProxyAgent --- __tests__/helpers/get-api-mock.ts | 4 ++-- __tests__/lib/fetch.test.ts | 21 ++++++++++++++------- package-lock.json | 1 + package.json | 1 + src/lib/readmeAPIFetch.ts | 14 ++++++-------- 5 files changed, 24 insertions(+), 17 deletions(-) diff --git a/__tests__/helpers/get-api-mock.ts b/__tests__/helpers/get-api-mock.ts index 752f47fe9..9a2456cbe 100644 --- a/__tests__/helpers/get-api-mock.ts +++ b/__tests__/helpers/get-api-mock.ts @@ -8,8 +8,8 @@ import { getUserAgent } from '../../src/lib/readmeAPIFetch.js'; * so it gets properly picked up by nock. * @param proxy Optional proxy URL. Must contain trailing slash. */ -export default function getAPIMock(reqHeaders = {}, proxy = '') { - return nock(`${proxy}${config.host}`, { +export default function getAPIMock(reqHeaders = {}) { + return nock(config.host, { reqheaders: { 'User-Agent': getUserAgent(), ...reqHeaders, diff --git a/__tests__/lib/fetch.test.ts b/__tests__/lib/fetch.test.ts index 047ca8890..cadefd2d2 100644 --- a/__tests__/lib/fetch.test.ts +++ b/__tests__/lib/fetch.test.ts @@ -1,5 +1,6 @@ /* eslint-disable no-console */ -import { describe, beforeEach, afterEach, it, expect, vi } from 'vitest'; +import nock from 'nock'; +import { describe, beforeEach, afterEach, it, expect, vi, beforeAll } from 'vitest'; import pkg from '../../package.json' with { type: 'json' }; import readmeAPIFetch, { cleanHeaders, handleRes } from '../../src/lib/readmeAPIFetch.js'; @@ -7,6 +8,12 @@ import getAPIMock from '../helpers/get-api-mock.js'; import { after, before } from '../helpers/setup-gha-env.js'; describe('#fetch()', () => { + beforeAll(() => { + nock.disableNetConnect(); + }); + + afterEach(() => nock.cleanAll()); + describe('GitHub Actions environment', () => { beforeEach(before); @@ -288,11 +295,11 @@ describe('#fetch()', () => { vi.stubEnv('HTTPS_PROXY', proxy); - const mock = getAPIMock({}, `${proxy}/`).get('/api/v1/proxy').reply(200); + const mock = getAPIMock({}).get('/api/v1/proxy').reply(200); await readmeAPIFetch('/api/v1/proxy'); - expect(mock.isDone()).toBe(true); + mock.done(); }); it('should support proxies via https_proxy env variable', async () => { @@ -300,11 +307,11 @@ describe('#fetch()', () => { vi.stubEnv('https_proxy', proxy); - const mock = getAPIMock({}, `${proxy}/`).get('/api/v1/proxy').reply(200); + const mock = getAPIMock({}).get('/api/v1/proxy').reply(200); await readmeAPIFetch('/api/v1/proxy'); - expect(mock.isDone()).toBe(true); + mock.done(); }); it('should handle trailing slash in proxy URL', async () => { @@ -312,11 +319,11 @@ describe('#fetch()', () => { vi.stubEnv('https_proxy', proxy); - const mock = getAPIMock({}, proxy).get('/api/v1/proxy').reply(200); + const mock = getAPIMock({}).get('/api/v1/proxy').reply(200); await readmeAPIFetch('/api/v1/proxy'); - expect(mock.isDone()).toBe(true); + mock.done(); }); }); }); diff --git a/package-lock.json b/package-lock.json index 0ec8dc946..597766f8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "table": "^6.8.1", "tmp-promise": "^3.0.2", "toposort": "^2.0.2", + "undici": "^5.28.4", "update-notifier": "^7.0.0", "validator": "^13.7.0" }, diff --git a/package.json b/package.json index d6d6a014d..c9f482d44 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "table": "^6.8.1", "tmp-promise": "^3.0.2", "toposort": "^2.0.2", + "undici": "^5.28.4", "update-notifier": "^7.0.0", "validator": "^13.7.0" }, diff --git a/src/lib/readmeAPIFetch.ts b/src/lib/readmeAPIFetch.ts index d0482a00e..7d0d7de30 100644 --- a/src/lib/readmeAPIFetch.ts +++ b/src/lib/readmeAPIFetch.ts @@ -3,6 +3,7 @@ import type { SpecFileType } from './prepareOas.js'; import path from 'node:path'; import mime from 'mime-types'; +import { ProxyAgent } from 'undici'; import pkg from '../../package.json' with { type: 'json' }; @@ -27,12 +28,7 @@ interface FilePathDetails { function getProxy() { // this is something of an industry standard env var, hence the checks for different casings - const proxy = process.env.HTTPS_PROXY || process.env.https_proxy; - if (proxy) { - // adds trailing slash - return proxy.endsWith('/') ? proxy : `${proxy}/`; - } - return ''; + return process.env.HTTPS_PROXY || process.env.https_proxy; } /** @@ -183,15 +179,17 @@ export default async function readmeAPIFetch( headers.set('x-readme-source-url', fileOpts.filePath); } - const fullUrl = `${getProxy()}${config.host}${pathname}`; + const fullUrl = `${config.host}${pathname}`; + const proxy = getProxy(); debug( - `making ${(options.method || 'get').toUpperCase()} request to ${fullUrl} with headers: ${sanitizeHeaders(headers)}`, + `making ${(options.method || 'get').toUpperCase()} request to ${fullUrl} ${proxy ? `with proxy ${proxy} and ` : ''}with headers: ${sanitizeHeaders(headers)}`, ); return fetch(fullUrl, { ...options, headers, + dispatcher: proxy ? new ProxyAgent(proxy) : undefined, }).then(res => { const warningHeader = res.headers.get('Warning'); if (warningHeader) { From 2c0f8e3b8ddc0c74f8b465a9939babba16d43563 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Mon, 6 May 2024 10:55:44 -0500 Subject: [PATCH 09/10] test: add note --- __tests__/lib/fetch.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/__tests__/lib/fetch.test.ts b/__tests__/lib/fetch.test.ts index cadefd2d2..77ec2884d 100644 --- a/__tests__/lib/fetch.test.ts +++ b/__tests__/lib/fetch.test.ts @@ -285,6 +285,11 @@ describe('#fetch()', () => { }); }); + /** + * @note these tests aren't doing much since there's no way for nock to intercept proxy agents properly. + * Undici has its own [`MockAgent`](https://undici.nodejs.org/#/docs/api/MockAgent) but I haven't figured out + * how to get it working with [ProxyAgent](https://undici.nodejs.org/#/docs/api/ProxyAgent). + */ describe('proxies', () => { afterEach(() => { vi.unstubAllEnvs(); From 5d7f6ad9625baa33791b333abd78aaefe46c3024 Mon Sep 17 00:00:00 2001 From: Kanad Gupta Date: Tue, 7 May 2024 10:27:35 -0500 Subject: [PATCH 10/10] ci: pin undici --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bb637ba59..7f5291c41 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -37,3 +37,10 @@ updates: - dependency-name: ora versions: - '>= 7' + # There are ProxyAgent discrepancies between undici@6 and + # the Node.js fetch implementation (which uses undici@5). + # Until we use undici itself for fetch calls, we should + # pin undici to the version used in Node.js core. + - dependency-name: undici + versions: + - '>= 6'