interceptors icon indicating copy to clipboard operation
interceptors copied to clipboard

test(undici): add interceptor tests for undici

Open chentsulin opened this issue 3 years ago • 6 comments

See #159.

chentsulin avatar Nov 10 '21 05:11 chentsulin

I've rebased your feature branch, as well as adjusted it to the latest test structure refactoring (#182). Your newly added undici tests are now under test/third-party/undici.

kettanaito avatar Nov 11 '21 13:11 kettanaito

Thank you for adding these tests!

The support for unidici will roughly follow these steps:

  1. Research how undici performs requests internally. See what modules it utilizes, what modules can be extended to support interception.
  2. Discuss the findings, assess the support strategy.
  3. If agreed, create a new interceptors/undici interceptor with the barebone implementation to cover the tests you've added.
  4. Ensure sufficient test coverage, merge and release the change.

If you have time, feel free to tackle the first step. Gathering knowledge often takes the most time, and I could definitely use your expertise in that. Thank you!

kettanaito avatar Nov 11 '21 13:11 kettanaito

In my earlier research, undici has its own mocking mechanism:

import { MockAgent, setGlobalDispatcher, } from 'undici'

const mockAgent = new MockAgent();

setGlobalDispatcher(mockAgent);

// Provide the base url to the request
const mockPool = mockAgent.get('http://localhost:3000');

// intercept the request
mockPool.intercept({
  path: '/bank-transfer',
  method: 'POST',
  headers: {
    'X-TOKEN-SECRET': 'SuperSecretToken',
  },
  body: JSON.stringify({
    recepient: '1234567890',
    ammount: '100'
  })
}).reply(200, {
  message: 'transaction processed'
})

We should take advantage of this setGlobalDispatcher stuff to implement the interceptor.

chentsulin avatar Nov 11 '21 13:11 chentsulin

@kettanaito, I don't have enough knowledge to experiment and finish all implementation details, but I did a naive and maybe buggy implementation for you to refer: https://github.com/mswjs/interceptors/commit/a7e21d1a929e0914cdd472e73ac68bdce676c75a

That's what I learned:

  • getGlobalDispatcher and setGlobalDispatcher are prefect for mocking and restoring.
  • undici classes are written in ES2015, so set compilerOptions.target to ES5 won't work.
  • The dispatch method is synchronous, so have to find a way to inject asynchronous body parsing and response resolving.
  • Relying on dispatch and handler seem to be right, because undici uses them:
    • https://github.com/nodejs/undici/issues/531#issuecomment-784018642
    • https://github.com/nodejs/undici/blob/f951002dfb86f502f1129588c021a26d7f2a0afb/lib/mock/mock-utils.js#L168-L174

chentsulin avatar Nov 12 '21 04:11 chentsulin

@chentsulin Thanks for sharing your implementation, it was super helpful. I have been playing with it and seeing an issue where undici expects @types/node to be at least 14.18 (this has the Blob type from buffer) in order to import the Dispatcher.DispatchHandlers type for the resolver.

However, updating this seems to cause issues with other intercepters, such as XML and http.get. Did you run into anything like that? How did you resolve?

@kettanaito, I don't have enough knowledge to experiment and finish all implementation details, but I did a naive and maybe buggy implementation for you to refer: a7e21d1

jtlopez18 avatar Jan 05 '22 17:01 jtlopez18

Thanks for preparing a reference implementation, @chentsulin!

I'm not sure to which extend we can reuse it, as with interceptors we're aiming at low-level request interception. Relying on MockAgent is a high-level thing, meaning we're going deeper into implementation specifics rather than relying on Node.js primitives.

I'd love to start this feature from research. We should first understand what kind of requests does undici make (it has to make a Socket connection at least, there are no other ways to request things in Node.js) and, ideally, model our interceptor around that.

I don't think I'll have time to work on this in the foreseeable future, so anybody is welcome to grab the research and implementation if they find this interesting.

kettanaito avatar Jan 11 '22 17:01 kettanaito

We are not going to support Undici directly. Instead, we will support global fetch in Node.js, which is powered by Undicit and is already available since Node 17.

kettanaito avatar Feb 06 '23 15:02 kettanaito