1# Mocking Request 2 3Undici 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. 4 5Example: 6 7```js 8// bank.mjs 9import { request } from 'undici' 10 11export async function bankTransfer(recipient, amount) { 12 const { body } = await request('http://localhost:3000/bank-transfer', 13 { 14 method: 'POST', 15 headers: { 16 'X-TOKEN-SECRET': 'SuperSecretToken', 17 }, 18 body: JSON.stringify({ 19 recipient, 20 amount 21 }) 22 } 23 ) 24 return await body.json() 25} 26``` 27 28And this is what the test file looks like: 29 30```js 31// index.test.mjs 32import { strict as assert } from 'assert' 33import { MockAgent, setGlobalDispatcher, } from 'undici' 34import { bankTransfer } from './bank.mjs' 35 36const mockAgent = new MockAgent(); 37 38setGlobalDispatcher(mockAgent); 39 40// Provide the base url to the request 41const mockPool = mockAgent.get('http://localhost:3000'); 42 43// intercept the request 44mockPool.intercept({ 45 path: '/bank-transfer', 46 method: 'POST', 47 headers: { 48 'X-TOKEN-SECRET': 'SuperSecretToken', 49 }, 50 body: JSON.stringify({ 51 recipient: '1234567890', 52 amount: '100' 53 }) 54}).reply(200, { 55 message: 'transaction processed' 56}) 57 58const success = await bankTransfer('1234567890', '100') 59 60assert.deepEqual(success, { message: 'transaction processed' }) 61 62// if you dont want to check whether the body or the headers contain the same value 63// just remove it from interceptor 64mockPool.intercept({ 65 path: '/bank-transfer', 66 method: 'POST', 67}).reply(400, { 68 message: 'bank account not found' 69}) 70 71const badRequest = await bankTransfer('1234567890', '100') 72 73assert.deepEqual(badRequest, { message: 'bank account not found' }) 74``` 75 76Explore other MockAgent functionality [here](../api/MockAgent.md) 77 78## Debug Mock Value 79 80When 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()`: 81 82```js 83const mockAgent = new MockAgent(); 84 85setGlobalDispatcher(mockAgent); 86mockAgent.disableNetConnect() 87 88// Provide the base url to the request 89const mockPool = mockAgent.get('http://localhost:3000'); 90 91mockPool.intercept({ 92 path: '/bank-transfer', 93 method: 'POST', 94}).reply(200, { 95 message: 'transaction processed' 96}) 97 98const badRequest = await bankTransfer('1234567890', '100') 99// Will throw an error 100// MockNotMatchedError: Mock dispatch not matched for path '/bank-transfer': 101// subsequent request to origin http://localhost:3000 was not allowed (net.connect disabled) 102``` 103 104## Reply with data based on request 105 106If the mocked response needs to be dynamically derived from the request parameters, you can provide a function instead of an object to `reply`: 107 108```js 109mockPool.intercept({ 110 path: '/bank-transfer', 111 method: 'POST', 112 headers: { 113 'X-TOKEN-SECRET': 'SuperSecretToken', 114 }, 115 body: JSON.stringify({ 116 recipient: '1234567890', 117 amount: '100' 118 }) 119}).reply(200, (opts) => { 120 // do something with opts 121 122 return { message: 'transaction processed' } 123}) 124``` 125 126in this case opts will be 127 128``` 129{ 130 method: 'POST', 131 headers: { 'X-TOKEN-SECRET': 'SuperSecretToken' }, 132 body: '{"recipient":"1234567890","amount":"100"}', 133 origin: 'http://localhost:3000', 134 path: '/bank-transfer' 135} 136``` 137