-
-
Notifications
You must be signed in to change notification settings - Fork 745
Use @mswjs/interceptors for mocking #2517
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
Conversation
Sorry I'm not sure when I get to review it, I'll try to find time on Saturday. If we manage to replace nock's on interceptors with the one from @mswjs while keeping all tests passing then I'm all for it |
lib/intercept.js
Outdated
return overriddenRequest(options, callback) | ||
const req = convertFetchRequestToClientRequest(request); | ||
req.on('response', response => { | ||
request.respondWith(new Response('test', { status: 200 })) |
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.
Nitpick: we'd want to read the response stream to the ReadableStream
of the response
instance and call request.respondWith()
on the end
event of the original response here.
As I mentioned in the issue, let me know if exporting this existing utility from Interceptors would help here. I think it would.
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.
Do you have an idea how we can wait for the nockResponse end
event? I use a promise, but maybe you had something else in mind.
As I mentioned in the issue, let me know if exporting this existing utility from Interceptors would help here. I think it would.
Thanks!! For now, I copied the file. We can update this later.
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.
In this case, we can rely on the internal http.ClientRequest
implementation to guarantee the order of event execution.
const stream = new Readable()
const fetchResponse = new Response(stream, {
status: response.statusCode,
statusText: response.statusMessage,
headers: response.headers // pseudo-code
})
response.on('data', (chunk) => stream.write(chunk))
response.on('end', () => {
stream.finish()
request.respndWith(fetchResponse)
})
This is a gist. If you want the actual implementation example, take a look at this function.
lib/intercept.js
Outdated
) | ||
overrideClientRequest() | ||
const interceptor = new BatchInterceptor({ | ||
name: 'my-interceptor', |
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.
Giving this a meaningful name may improve the logging output, afaik. Maybe name: 'nock-interceptor'
?
lib/intercept.js
Outdated
host: url.hostname, | ||
port: url.port || (url.protocol === 'https:' ? 443 : 80), | ||
path: url.pathname + url.search, | ||
headers: fetchRequest.headers, |
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 think Node expects OutgoingHeaders
here, which is not compatible with the Headers
instance. You should be fine doing this:
headers: Object.fromEntries(fetchRequest.headers.entries())
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.
great catch! 🙏
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.
Just be cautious about the compilation target here. I'm not sure what's the support range is for Nock, but .fromEntries()
and .entries()
methods may not exist on super old versions of ECMAScript and Node.
lib/create_response.js
Outdated
* @param {IncomingMessage} message | ||
*/ | ||
function createResponse(message) { | ||
const readable = new ReadableStream({ |
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.
Looks like the version of Node Nock uses doesn't have the ReadableStream
global. I'd double-check if this isn't the linter's problem as the first measure.
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.
Sometimes the linter doesn't play well with relatively newly added globals. This can be modified in the linter's globals
key, if talking about ESLint.
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.
Thanks!
I think we can fix this after we will solve the got
error. Most of Nock's tests are based on it and I'm eager to solve it and run all tests to find cases that we haven't covered yet.
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 will try to look into the got
issue this week based on my availability. Right now, the best next step is to reliably reproduce it in an automated test. I've already written one (see mswjs/interceptors#432) but you've provided some input that I need to reflect in the test.
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've fixed the got
issue, would appreciate a quick review of the pull request!
@kettanaito Maybe you have an idea of how I can propagate errors from the interceptors? Specifically, I'm trying to fix this test. I tried something like: interceptor.on('request', function ({ request, requestId }) {
...
const nockRequest = convertFetchRequestToClientRequest(request);
nockRequest.on('error', error => {
request.respondWith(new Response('put here the real error'))
resolve()
})
...
}) But it stuck. |
@mikicho, you can throw in the request listener but that will be considered a request error. Try it, see if it produces the result you need. interceptor.on('request', () => {
nockRequest.on('error', (error) => {
throw error
})
}) |
@kettanaito |
Oh, I see. Try responding with request.respondWith(Response.error(YOUR_ERROR_MESSAGE)) This will instruct Interceptors to treat this as an intentional error, and it will forward it to the appropriate error handling logic based on the request module, like emitting the |
Just want to say thank you @mikicho and @kettanaito for working on this 💐💝 |
@kettanaito Thank you for your willingness to help and I apologize for any clutter I may cause! |
@gr2m Why does Nock expose the request object via the response ("res.req") |
@gr2m Also, we currently pass the |
I believe it's not part of the public API but Node.js associates the OutgoingMessage with the IncomingMessage that way. I do recall seeing something like that recently during testing, so you may be seeing the same thing. It's highly likely Node's internals. |
Ok, so as developers tend to do... this PR led to a re-write of the @gr2m @Uzlopak (even if it looks the same as the previous picture I shared, we had a lot of progress :)) |
I summed up what is left here. |
@nock/maintainers Tests fail due to insufficient coverage, which IMHO we should ignore now. A lot of code has been changed, and I want to do a big cleanup, which I think will bring the coverage back to 100% :) |
Sounds good to me 🥳 thank you for all your hard work on this 💐❤️ |
🎉 This PR is included in version 14.0.0-beta.8 🎉 The release is available on: Your semantic-release bot 📦🚀 |
🎉 This PR is included in version 13.5.5 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Why?
nock
work nativefetch
#2397.@mswjs/interceptors
supports bothhttp.get/request
andfetch
.@mswjs/interceptors
is inspired byNock
and written in a modern way for maximum compatibility.closes #2397
Parity Gaps
Nock is a mature and battle-proof project and used by a lot of developers over the years. therefore, Nock covers many real-life scenarios and takes care of a LOT of edge cases.
@mswjs/interceptors
is great, but it still has some gaps to cover in order to reach Nock's level of maturity and ability to cover its wide test suite.I adjust as much as I can Nock's code to
@mswjs/interceptors
logic and current capabilities and opened tickets in the repo to track issues and feature requests:Failed tests list: mswjs/interceptors#575
Topics to discuss about
During the work, I gathered a few topics we need to discuss further. I'll open dedicated issue(s) for them in Nock's repo.
CC @gr2m @kettanaito