-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Migrate to undici MockClient #79
Conversation
a196cef
to
61ea9ff
Compare
Breaking change! - Internally uses `undici`'s `MockAgent`, instead of `nock` to mock requests. - `nock` is still used for data-matching to retain backwards compatibility. - Tests now use `fetch` instead of `axios`. Requires node>=18 and @octokit/rest>=20 Closes kiegroup#77
61ea9ff
to
74fa0bc
Compare
Thank you for your PR! I will take a look at the changes over this week |
@shubhbapna Please let me know if the chance to have this merged is low. I can also transition my project to my fork. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So sorry for the delay! It slipped through the cracks for me.
@@ -14,7 +14,7 @@ jobs: | |||
- uses: actions/checkout@v3 | |||
- uses: actions/setup-node@v3 | |||
with: | |||
node-version: 16 | |||
node-version: 20 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to support node 18 as well, so probably change it to matrix and test for both? Same for all the other workflow files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, this is the publish job. The matrix is already in pull_request
😄 I'll add 18 there.
test/moctokit/moctokit.test.ts
Outdated
@@ -15,14 +15,14 @@ test("with default base url", async () => { | |||
repo: "project", | |||
}); | |||
expect(data1.status).toBe(200); | |||
expect(data1.data).toStrictEqual({ full_name: "it definitely worked" }); | |||
expect(data1.data).toEqual({ full_name: "it definitely worked" }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why was this change needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it wasn't. It must have been an oversight when rewriting the tests.
@@ -42,21 +42,23 @@ async function generateEndpointRequest() { | |||
|
|||
newEndpointRequest[scope][ | |||
endpoint.id | |||
] = `new MoctokitRequestMocker<"${path}", "${method}">(baseUrl, endpoints["${scope}"]["${endpoint.id}"], allowUnmocked).request`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why was allowUnmocked
removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior is controlled globally through https://undici.nodejs.org/#/docs/api/MockAgent?id=mockagentdisablenetconnect in undici.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we keep such that the user can decide the behaviour? So if the user passes allowUnmocked
as false
then we call MockAgent.disableNetConnect()
otherwise we do nothing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm doing that in EndpointMocker
actually 😊
if (process.env.JEST_WORKER_ID !== undefined) { | ||
// @ts-expect-error This seems impossible to type correctly. | ||
globalThis.fetch = ( | ||
input: NodeJS.fetch.RequestInfo, | ||
init?: NodeJS.fetch.RequestInit | undefined | ||
) => | ||
fetch(input, { | ||
dispatcher: this.agent, | ||
...(init as undiciRequestInit), | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain why we need this? I think this is more of a jest issue where the jest globals differ from node globals: jestjs/jest#2549. So we could leave the workaround for this user where, the user has to configure the globals correctly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could probably be moved to the test suites themselves. Of course, all consumers of this package will have to do that too for all their test suites, if they use Jest. Could be painful. Or maybe I'm missing a better solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, lets keep it for now
path: requestPath => this.pathHandler(requestPath), | ||
method: this.method.toUpperCase(), | ||
body: requestBody => this.bodyHandler(requestBody), | ||
query: this.query, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't able to find the docs on this, but does undici match queries based on regex as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Queries are matched as part of the path. See further comments on this below.
@@ -1,18 +1,18 @@ | |||
/* eslint-disable @typescript-eslint/no-explicit-any */ | |||
import axios from "axios"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was axios removed? I wouldn't change the existing test cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
axios doesn't use Node's fetch
implementation and isn't affected by undici
mocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm this PR would break backward compatibility altogether in the case. I think a better solution would be to have nock and as well as undici mocks. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would definitely be an option.
I've seen several other projects introduce a similar breaking change when they moved to Node18 and beyond. Many projects only support Node18 and newer now, at least in my part of the bubble :)
However, as I remember, the new Octokit tooling also has a new fetch-based, and the old interface still built in.
This also made me think about if both paths should be implemented in mock-github. I felt like users of old octokit versions could still use the existing version of mock-github; the path into the future will be entirely fetch-based, as that is what the latest implementations from GitHub use. If you are mocking Octokit, it is likely that you want to work with the latest supported version, which uses fetch by default in the latest version, and is highly likely to continue doing so moving ahead.
Given all that, I felt like it could make sense to just accept the breaking change and focus on a single implementation.
If you think it's worth the effort to maintain the two paths, I'm happy to work on that as well :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I addressed the comments and I'll work on some changes.
test/moctokit/moctokit.test.ts
Outdated
@@ -15,14 +15,14 @@ test("with default base url", async () => { | |||
repo: "project", | |||
}); | |||
expect(data1.status).toBe(200); | |||
expect(data1.data).toStrictEqual({ full_name: "it definitely worked" }); | |||
expect(data1.data).toEqual({ full_name: "it definitely worked" }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it wasn't. It must have been an oversight when rewriting the tests.
@@ -1,18 +1,18 @@ | |||
/* eslint-disable @typescript-eslint/no-explicit-any */ | |||
import axios from "axios"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
axios doesn't use Node's fetch
implementation and isn't affected by undici
mocks.
path: requestPath => this.pathHandler(requestPath), | ||
method: this.method.toUpperCase(), | ||
body: requestBody => this.bodyHandler(requestBody), | ||
query: this.query, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Queries are matched as part of the path. See further comments on this below.
if (process.env.JEST_WORKER_ID !== undefined) { | ||
// @ts-expect-error This seems impossible to type correctly. | ||
globalThis.fetch = ( | ||
input: NodeJS.fetch.RequestInfo, | ||
init?: NodeJS.fetch.RequestInit | undefined | ||
) => | ||
fetch(input, { | ||
dispatcher: this.agent, | ||
...(init as undiciRequestInit), | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could probably be moved to the test suites themselves. Of course, all consumers of this package will have to do that too for all their test suites, if they use Jest. Could be painful. Or maybe I'm missing a better solution.
@@ -42,21 +42,23 @@ async function generateEndpointRequest() { | |||
|
|||
newEndpointRequest[scope][ | |||
endpoint.id | |||
] = `new MoctokitRequestMocker<"${path}", "${method}">(baseUrl, endpoints["${scope}"]["${endpoint.id}"], allowUnmocked).request`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This behavior is controlled globally through https://undici.nodejs.org/#/docs/api/MockAgent?id=mockagentdisablenetconnect in undici.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope I addressed everything :)
@@ -14,7 +14,7 @@ jobs: | |||
- uses: actions/checkout@v3 | |||
- uses: actions/setup-node@v3 | |||
with: | |||
node-version: 16 | |||
node-version: 20 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, this is the publish job. The matrix is already in pull_request
😄 I'll add 18 there.
@@ -42,21 +42,23 @@ async function generateEndpointRequest() { | |||
|
|||
newEndpointRequest[scope][ | |||
endpoint.id | |||
] = `new MoctokitRequestMocker<"${path}", "${method}">(baseUrl, endpoints["${scope}"]["${endpoint.id}"], allowUnmocked).request`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm doing that in EndpointMocker
actually 😊
.reply(response.status, response.data as Record<string, unknown>, { | ||
headers: { | ||
...(response.headers as IncomingHttpHeaders), | ||
"content-type": this.getContentTypeForResponseData(response.data), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow. In the headers
hash, the content-type
is the first entry, then we spread the user-defined response.headers
(which could also include a content-type
) into the hash, overriding any existing properties.
Shouldn't that already have the desired effect?
Hi, sorry I was away for sometime. I was recently made aware of the ongoing effort in nock to support undici: nock/nock#2517 They estimate that this work will be done by January. I would rather wait for this and have the mocking entirely handled by |
Breaking change!
undici
'sMockAgent
, instead ofnock
to mock requests.nock
is still used for data-matching to retain backwards compatibility.fetch
instead ofaxios
.Requires node>=18 and @octokit/rest>=20
Closes #77