Spaces:
Runtime error
Runtime error
# Mocking Request | |
Undici has its own mocking [utility](../api/MockAgent.md). It allow us to intercept undici HTTP requests and return mocked values instead. It can be useful for testing purposes. | |
Example: | |
```js | |
// bank.mjs | |
import { request } from 'undici' | |
export async function bankTransfer(recipient, amount) { | |
const { body } = await request('http://localhost:3000/bank-transfer', | |
{ | |
method: 'POST', | |
headers: { | |
'X-TOKEN-SECRET': 'SuperSecretToken', | |
}, | |
body: JSON.stringify({ | |
recipient, | |
amount | |
}) | |
} | |
) | |
return await body.json() | |
} | |
``` | |
And this is what the test file looks like: | |
```js | |
// index.test.mjs | |
import { strict as assert } from 'assert' | |
import { MockAgent, setGlobalDispatcher, } from 'undici' | |
import { bankTransfer } from './bank.mjs' | |
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({ | |
recipient: '1234567890', | |
amount: '100' | |
}) | |
}).reply(200, { | |
message: 'transaction processed' | |
}) | |
const success = await bankTransfer('1234567890', '100') | |
assert.deepEqual(success, { message: 'transaction processed' }) | |
// if you dont want to check whether the body or the headers contain the same value | |
// just remove it from interceptor | |
mockPool.intercept({ | |
path: '/bank-transfer', | |
method: 'POST', | |
}).reply(400, { | |
message: 'bank account not found' | |
}) | |
const badRequest = await bankTransfer('1234567890', '100') | |
assert.deepEqual(badRequest, { message: 'bank account not found' }) | |
``` | |
Explore other MockAgent functionality [here](../api/MockAgent.md) | |
## Debug Mock Value | |
When the interceptor and the request options are not the same, undici will automatically make a real HTTP request. To prevent real requests from being made, use `mockAgent.disableNetConnect()`: | |
```js | |
const mockAgent = new MockAgent(); | |
setGlobalDispatcher(mockAgent); | |
mockAgent.disableNetConnect() | |
// Provide the base url to the request | |
const mockPool = mockAgent.get('http://localhost:3000'); | |
mockPool.intercept({ | |
path: '/bank-transfer', | |
method: 'POST', | |
}).reply(200, { | |
message: 'transaction processed' | |
}) | |
const badRequest = await bankTransfer('1234567890', '100') | |
// Will throw an error | |
// MockNotMatchedError: Mock dispatch not matched for path '/bank-transfer': | |
// subsequent request to origin http://localhost:3000 was not allowed (net.connect disabled) | |
``` | |
## Reply with data based on request | |
If the mocked response needs to be dynamically derived from the request parameters, you can provide a function instead of an object to `reply`: | |
```js | |
mockPool.intercept({ | |
path: '/bank-transfer', | |
method: 'POST', | |
headers: { | |
'X-TOKEN-SECRET': 'SuperSecretToken', | |
}, | |
body: JSON.stringify({ | |
recipient: '1234567890', | |
amount: '100' | |
}) | |
}).reply(200, (opts) => { | |
// do something with opts | |
return { message: 'transaction processed' } | |
}) | |
``` | |
in this case opts will be | |
``` | |
{ | |
method: 'POST', | |
headers: { 'X-TOKEN-SECRET': 'SuperSecretToken' }, | |
body: '{"recipient":"1234567890","amount":"100"}', | |
origin: 'http://localhost:3000', | |
path: '/bank-transfer' | |
} | |
``` | |