• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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