-
-
Notifications
You must be signed in to change notification settings - Fork 688
Description
Bug Description
MockAgent allows us to generate a reply dynamically. The request's options are passed into that function. Undici's type definitions specify that a Headers object will be used for options.headers, but instead a flattened array is given. This is entirely unusable without splitting it into two-tuple chunks first and manually wrapping it in a new Headers() call.
Note that it is also possible to access the headers inside a matcher function passed to intercept(). This was a useful workaround for me, but keep in mind that for some reason, the matcher gets called twice which you can also see in the output below.
Reproducible By
import { fetch, MockAgent, setGlobalDispatcher } from 'undici'
const mockAgent = new MockAgent()
const mockPool = mockAgent.get('http://localhost')
setGlobalDispatcher(mockAgent)
mockPool.intercept({
path: '/foo',
method: 'GET',
headers: (headers) => {
console.log('headers in intercept:', Object.prototype.toString.call(headers), headers)
return true
}
}).reply(200, (options) => {
console.log('headers in reply:', Object.prototype.toString.call(options.headers), options.headers)
return {}
})
await fetch('http://localhost/foo')Expected Behavior
The included type definitions specify that the parameter to the headers matcher in intercept() should receive Record<string, string>. For reply(), they specify options.headers to be a Headers object.
As such I would expect the following output:
headers in intercept: [object Object] {
accept: '*/*',
'accept-language': '*',
'sec-fetch-mode': 'cors',
'user-agent': 'undici',
'accept-encoding': 'gzip, deflate'
}
headers in reply: [object Headers] HeadersList {
[Symbol(headers map)]: Map(5) {
'accept' => '*/*',
'accept-language' => '*',
'sec-fetch-mode' => 'cors',
'user-agent' => 'undici',
'accept-encoding' => 'gzip, deflate'
},
[Symbol(headers map sorted)]: null
}
Logs & Screenshots
Instead of the above, the following is logged:
headers in intercept: [object Object] {
accept: '*/*',
'accept-language': '*',
'sec-fetch-mode': 'cors',
'user-agent': 'undici',
'accept-encoding': 'gzip, deflate'
}
headers in reply: [object Array] [
'accept',
'*/*',
'accept-language',
'*',
'sec-fetch-mode',
'cors',
'user-agent',
'undici',
'accept-encoding',
'gzip, deflate'
]
headers in intercept: [object Object] {
accept: '*/*',
'accept-language': '*',
'sec-fetch-mode': 'cors',
'user-agent': 'undici',
'accept-encoding': 'gzip, deflate'
}
Environment
- Windows 11, additionally tried in WSL running Ubuntu 20.04.4 LTS with same behavior
- Node v18.6.0
- npm 8.13.2
- Undici 5.8.0
Additional context
- Relevant type definitions for
options.headersinreply():undici/types/mock-interceptor.d.ts
Line 77 in 784c6b4
headers: Headers; - I didn't yet have the time to figure out where in the source code the headers array is coming from, unfortunately.