Skip to content
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

fix(ClientRequest): support ClientRequest constructor #692

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

mikicho
Copy link
Contributor

@mikicho mikicho commented Dec 14, 2024

No description provided.

@mikicho mikicho requested a review from kettanaito December 14, 2024 13:34
const resolver = vi.fn<HttpRequestEventMap['request']>()

const interceptor = new ClientRequestInterceptor()
interceptor.on('request', resolver)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually grew to dislike this pattern. Sorry it's still present in the test suite. It leads to a shared state in a shape of the resolver function, and that's really bad.

May I please ask you to add the request listener within the test instead? It will yield a much simpler setup. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! like this?
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so!

And please add interceptor.removeAllListeners() to the afterEach() hook.

Copy link
Member

@kettanaito kettanaito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great. I cannot believe we ignored the constructor itself. Thanks for fixing this, @mikicho!

I left one comment about the test, otherwise good.

@kettanaito kettanaito changed the title fix(ClientRequest): support ClientRequest constructor fix(ClientRequest): support ClientRequest constructor Dec 15, 2024
@kettanaito
Copy link
Member

kettanaito commented Dec 16, 2024

I'm thinking, will patching ClientRequest lead to double patching when using functions like http.request()? We don't replace their implementation anymore, only inject the MockHttpAgent, which means those functions will construct new http.ClientRequest() when called. Now that we are adding a patch over that class, does that lead to both of them being patched?

I may be wrong about this. Would love to hear your thoughts on this. Also, I think we need tests for this anyway to have clear expectations toward how this should behave.

Since the ClientRequest proxy just drills down the agent, I think we should be fine. To be safe though, perhaps we should check if the options.agent is already an instance of MockHttpgent, and if it is, ignore the proxy. Does that make sense?

if (options.agent instanceof MockHttpAgent) {
  return Reflect.appy(...)
}

const agent = new MockHttpAgent()
return Reflect.apply(...)

@mikicho
Copy link
Contributor Author

mikicho commented Dec 16, 2024

I'm thinking, will patching ClientRequest lead to double patching when using functions like http.request()?

It also came to mind, but when I removed the get/request proxies, Node kept using the original ClientRequest. I think it happens because they destruct the ClientRequest in the http module: https://github.com/nodejs/node/blob/main/lib/http.js#L30

@kettanaito
Copy link
Member

That is a great find. I also thought of some cases when we should keep the .get/.request proxies to be safe. I like this approach. I would just

  • Check if the mock agent is already set on the ClientRequest level and then ignore everything else.
  • Add at least one test that ensures http.request + ClientRequest combo. We may have to assert on implementation details here because proxies are not publicly observable. Something like: if I make http.request request, grab the ClientRequest instance it constructs and make sure that it uses a single and same MockHttpAgent instance.

@mikicho
Copy link
Contributor Author

mikicho commented Dec 16, 2024

Check if the mock agent is already set on the ClientRequest level and then ignore everything else.

In runtime or in a test?

a single and same MockHttpAgent instance

Same as what? We create a new MockAgent instance on each request.
Is this the test you have in mind?

it('..', async () => {
  const req = http.request(..);
  const clientReq = new ClientRequest(..);
  req.agent.name === clientReq.agent.name?
})

I'm not sure what we are trying to check here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants