• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Class: MockAgent
2
3Extends: `undici.Dispatcher`
4
5A mocked Agent class that implements the Agent API. It allows one to intercept HTTP requests made through undici and return mocked responses instead.
6
7## `new MockAgent([options])`
8
9Arguments:
10
11* **options** `MockAgentOptions` (optional) - It extends the `Agent` options.
12
13Returns: `MockAgent`
14
15### Parameter: `MockAgentOptions`
16
17Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
18
19* **agent** `Agent` (optional) - Default: `new Agent([options])` - a custom agent encapsulated by the MockAgent.
20
21### Example - Basic MockAgent instantiation
22
23This will instantiate the MockAgent. It will not do anything until registered as the agent to use with requests and mock interceptions are added.
24
25```js
26import { MockAgent } from 'undici'
27
28const mockAgent = new MockAgent()
29```
30
31### Example - Basic MockAgent instantiation with custom agent
32
33```js
34import { Agent, MockAgent } from 'undici'
35
36const agent = new Agent()
37
38const mockAgent = new MockAgent({ agent })
39```
40
41## Instance Methods
42
43### `MockAgent.get(origin)`
44
45This method creates and retrieves MockPool or MockClient instances which can then be used to intercept HTTP requests. If the number of connections on the mock agent is set to 1, a MockClient instance is returned. Otherwise a MockPool instance is returned.
46
47For subsequent `MockAgent.get` calls on the same origin, the same mock instance will be returned.
48
49Arguments:
50
51* **origin** `string | RegExp | (value) => boolean` - a matcher for the pool origin to be retrieved from the MockAgent.
52
53| Matcher type | Condition to pass          |
54|:------------:| -------------------------- |
55| `string`     | Exact match against string |
56| `RegExp`     | Regex must pass            |
57| `Function`   | Function must return true  |
58
59Returns: `MockClient | MockPool`.
60
61| `MockAgentOptions`   | Mock instance returned |
62| -------------------- | ---------------------- |
63| `connections === 1`  | `MockClient`           |
64| `connections` > `1`  | `MockPool`             |
65
66#### Example - Basic Mocked Request
67
68```js
69import { MockAgent, setGlobalDispatcher, request } from 'undici'
70
71const mockAgent = new MockAgent()
72setGlobalDispatcher(mockAgent)
73
74const mockPool = mockAgent.get('http://localhost:3000')
75mockPool.intercept({ path: '/foo' }).reply(200, 'foo')
76
77const { statusCode, body } = await request('http://localhost:3000/foo')
78
79console.log('response received', statusCode) // response received 200
80
81for await (const data of body) {
82  console.log('data', data.toString('utf8')) // data foo
83}
84```
85
86#### Example - Basic Mocked Request with local mock agent dispatcher
87
88```js
89import { MockAgent, request } from 'undici'
90
91const mockAgent = new MockAgent()
92
93const mockPool = mockAgent.get('http://localhost:3000')
94mockPool.intercept({ path: '/foo' }).reply(200, 'foo')
95
96const {
97  statusCode,
98  body
99} = await request('http://localhost:3000/foo', { dispatcher: mockAgent })
100
101console.log('response received', statusCode) // response received 200
102
103for await (const data of body) {
104  console.log('data', data.toString('utf8')) // data foo
105}
106```
107
108#### Example - Basic Mocked Request with local mock pool dispatcher
109
110```js
111import { MockAgent, request } from 'undici'
112
113const mockAgent = new MockAgent()
114
115const mockPool = mockAgent.get('http://localhost:3000')
116mockPool.intercept({ path: '/foo' }).reply(200, 'foo')
117
118const {
119  statusCode,
120  body
121} = await request('http://localhost:3000/foo', { dispatcher: mockPool })
122
123console.log('response received', statusCode) // response received 200
124
125for await (const data of body) {
126  console.log('data', data.toString('utf8')) // data foo
127}
128```
129
130#### Example - Basic Mocked Request with local mock client dispatcher
131
132```js
133import { MockAgent, request } from 'undici'
134
135const mockAgent = new MockAgent({ connections: 1 })
136
137const mockClient = mockAgent.get('http://localhost:3000')
138mockClient.intercept({ path: '/foo' }).reply(200, 'foo')
139
140const {
141  statusCode,
142  body
143} = await request('http://localhost:3000/foo', { dispatcher: mockClient })
144
145console.log('response received', statusCode) // response received 200
146
147for await (const data of body) {
148  console.log('data', data.toString('utf8')) // data foo
149}
150```
151
152#### Example - Basic Mocked requests with multiple intercepts
153
154```js
155import { MockAgent, setGlobalDispatcher, request } from 'undici'
156
157const mockAgent = new MockAgent()
158setGlobalDispatcher(mockAgent)
159
160const mockPool = mockAgent.get('http://localhost:3000')
161mockPool.intercept({ path: '/foo' }).reply(200, 'foo')
162mockPool.intercept({ path: '/hello'}).reply(200, 'hello')
163
164const result1 = await request('http://localhost:3000/foo')
165
166console.log('response received', result1.statusCode) // response received 200
167
168for await (const data of result1.body) {
169  console.log('data', data.toString('utf8')) // data foo
170}
171
172const result2 = await request('http://localhost:3000/hello')
173
174console.log('response received', result2.statusCode) // response received 200
175
176for await (const data of result2.body) {
177  console.log('data', data.toString('utf8')) // data hello
178}
179```
180#### Example - Mock different requests within the same file
181```js
182const { MockAgent, setGlobalDispatcher } = require('undici');
183const agent = new MockAgent();
184agent.disableNetConnect();
185setGlobalDispatcher(agent);
186describe('Test', () => {
187  it('200', async () => {
188    const mockAgent = agent.get('http://test.com');
189    // your test
190  });
191  it('200', async () => {
192    const mockAgent = agent.get('http://testing.com');
193    // your test
194  });
195});
196```
197
198#### Example - Mocked request with query body, headers and trailers
199
200```js
201import { MockAgent, setGlobalDispatcher, request } from 'undici'
202
203const mockAgent = new MockAgent()
204setGlobalDispatcher(mockAgent)
205
206const mockPool = mockAgent.get('http://localhost:3000')
207
208mockPool.intercept({
209  path: '/foo?hello=there&see=ya',
210  method: 'POST',
211  body: 'form1=data1&form2=data2'
212}).reply(200, { foo: 'bar' }, {
213  headers: { 'content-type': 'application/json' },
214  trailers: { 'Content-MD5': 'test' }
215})
216
217const {
218  statusCode,
219  headers,
220  trailers,
221  body
222} = await request('http://localhost:3000/foo?hello=there&see=ya', {
223  method: 'POST',
224  body: 'form1=data1&form2=data2'
225})
226
227console.log('response received', statusCode) // response received 200
228console.log('headers', headers) // { 'content-type': 'application/json' }
229
230for await (const data of body) {
231  console.log('data', data.toString('utf8')) // '{"foo":"bar"}'
232}
233
234console.log('trailers', trailers) // { 'content-md5': 'test' }
235```
236
237#### Example - Mocked request with origin regex
238
239```js
240import { MockAgent, setGlobalDispatcher, request } from 'undici'
241
242const mockAgent = new MockAgent()
243setGlobalDispatcher(mockAgent)
244
245const mockPool = mockAgent.get(new RegExp('http://localhost:3000'))
246mockPool.intercept({ path: '/foo' }).reply(200, 'foo')
247
248const {
249  statusCode,
250  body
251} = await request('http://localhost:3000/foo')
252
253console.log('response received', statusCode) // response received 200
254
255for await (const data of body) {
256  console.log('data', data.toString('utf8')) // data foo
257}
258```
259
260#### Example - Mocked request with origin function
261
262```js
263import { MockAgent, setGlobalDispatcher, request } from 'undici'
264
265const mockAgent = new MockAgent()
266setGlobalDispatcher(mockAgent)
267
268const mockPool = mockAgent.get((origin) => origin === 'http://localhost:3000')
269mockPool.intercept({ path: '/foo' }).reply(200, 'foo')
270
271const {
272  statusCode,
273  body
274} = await request('http://localhost:3000/foo')
275
276console.log('response received', statusCode) // response received 200
277
278for await (const data of body) {
279  console.log('data', data.toString('utf8')) // data foo
280}
281```
282
283### `MockAgent.close()`
284
285Closes the mock agent and waits for registered mock pools and clients to also close before resolving.
286
287Returns: `Promise<void>`
288
289#### Example - clean up after tests are complete
290
291```js
292import { MockAgent, setGlobalDispatcher } from 'undici'
293
294const mockAgent = new MockAgent()
295setGlobalDispatcher(mockAgent)
296
297await mockAgent.close()
298```
299
300### `MockAgent.dispatch(options, handlers)`
301
302Implements [`Agent.dispatch(options, handlers)`](Agent.md#parameter-agentdispatchoptions).
303
304### `MockAgent.request(options[, callback])`
305
306See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
307
308#### Example - MockAgent request
309
310```js
311import { MockAgent } from 'undici'
312
313const mockAgent = new MockAgent()
314
315const mockPool = mockAgent.get('http://localhost:3000')
316mockPool.intercept({ path: '/foo' }).reply(200, 'foo')
317
318const {
319  statusCode,
320  body
321} = await mockAgent.request({
322  origin: 'http://localhost:3000',
323  path: '/foo',
324  method: 'GET'
325})
326
327console.log('response received', statusCode) // response received 200
328
329for await (const data of body) {
330  console.log('data', data.toString('utf8')) // data foo
331}
332```
333
334### `MockAgent.deactivate()`
335
336This method disables mocking in MockAgent.
337
338Returns: `void`
339
340#### Example - Deactivate Mocking
341
342```js
343import { MockAgent, setGlobalDispatcher } from 'undici'
344
345const mockAgent = new MockAgent()
346setGlobalDispatcher(mockAgent)
347
348mockAgent.deactivate()
349```
350
351### `MockAgent.activate()`
352
353This method enables mocking in a MockAgent instance. When instantiated, a MockAgent is automatically activated. Therefore, this method is only effective after `MockAgent.deactivate` has been called.
354
355Returns: `void`
356
357#### Example - Activate Mocking
358
359```js
360import { MockAgent, setGlobalDispatcher } from 'undici'
361
362const mockAgent = new MockAgent()
363setGlobalDispatcher(mockAgent)
364
365mockAgent.deactivate()
366// No mocking will occur
367
368// Later
369mockAgent.activate()
370```
371
372### `MockAgent.enableNetConnect([host])`
373
374When requests are not matched in a MockAgent intercept, a real HTTP request is attempted. We can control this further through the use of `enableNetConnect`. This is achieved by defining host matchers so only matching requests will be attempted.
375
376When using a string, it should only include the **hostname and optionally, the port**. In addition, calling this method multiple times with a string will allow all HTTP requests that match these values.
377
378Arguments:
379
380* **host** `string | RegExp | (value) => boolean` - (optional)
381
382Returns: `void`
383
384#### Example - Allow all non-matching urls to be dispatched in a real HTTP request
385
386```js
387import { MockAgent, setGlobalDispatcher, request } from 'undici'
388
389const mockAgent = new MockAgent()
390setGlobalDispatcher(mockAgent)
391
392mockAgent.enableNetConnect()
393
394await request('http://example.com')
395// A real request is made
396```
397
398#### Example - Allow requests matching a host string to make real requests
399
400```js
401import { MockAgent, setGlobalDispatcher, request } from 'undici'
402
403const mockAgent = new MockAgent()
404setGlobalDispatcher(mockAgent)
405
406mockAgent.enableNetConnect('example-1.com')
407mockAgent.enableNetConnect('example-2.com:8080')
408
409await request('http://example-1.com')
410// A real request is made
411
412await request('http://example-2.com:8080')
413// A real request is made
414
415await request('http://example-3.com')
416// Will throw
417```
418
419#### Example - Allow requests matching a host regex to make real requests
420
421```js
422import { MockAgent, setGlobalDispatcher, request } from 'undici'
423
424const mockAgent = new MockAgent()
425setGlobalDispatcher(mockAgent)
426
427mockAgent.enableNetConnect(new RegExp('example.com'))
428
429await request('http://example.com')
430// A real request is made
431```
432
433#### Example - Allow requests matching a host function to make real requests
434
435```js
436import { MockAgent, setGlobalDispatcher, request } from 'undici'
437
438const mockAgent = new MockAgent()
439setGlobalDispatcher(mockAgent)
440
441mockAgent.enableNetConnect((value) => value === 'example.com')
442
443await request('http://example.com')
444// A real request is made
445```
446
447### `MockAgent.disableNetConnect()`
448
449This method causes all requests to throw when requests are not matched in a MockAgent intercept.
450
451Returns: `void`
452
453#### Example - Disable all non-matching requests by throwing an error for each
454
455```js
456import { MockAgent, request } from 'undici'
457
458const mockAgent = new MockAgent()
459
460mockAgent.disableNetConnect()
461
462await request('http://example.com')
463// Will throw
464```
465
466### `MockAgent.pendingInterceptors()`
467
468This method returns any pending interceptors registered on a mock agent. A pending interceptor meets one of the following criteria:
469
470- Is registered with neither `.times(<number>)` nor `.persist()`, and has not been invoked;
471- Is persistent (i.e., registered with `.persist()`) and has not been invoked;
472- Is registered with `.times(<number>)` and has not been invoked `<number>` of times.
473
474Returns: `PendingInterceptor[]` (where `PendingInterceptor` is a `MockDispatch` with an additional `origin: string`)
475
476#### Example - List all pending inteceptors
477
478```js
479const agent = new MockAgent()
480agent.disableNetConnect()
481
482agent
483  .get('https://example.com')
484  .intercept({ method: 'GET', path: '/' })
485  .reply(200)
486
487const pendingInterceptors = agent.pendingInterceptors()
488// Returns [
489//   {
490//     timesInvoked: 0,
491//     times: 1,
492//     persist: false,
493//     consumed: false,
494//     pending: true,
495//     path: '/',
496//     method: 'GET',
497//     body: undefined,
498//     headers: undefined,
499//     data: {
500//       error: null,
501//       statusCode: 200,
502//       data: '',
503//       headers: {},
504//       trailers: {}
505//     },
506//     origin: 'https://example.com'
507//   }
508// ]
509```
510
511### `MockAgent.assertNoPendingInterceptors([options])`
512
513This method throws if the mock agent has any pending interceptors. A pending interceptor meets one of the following criteria:
514
515- Is registered with neither `.times(<number>)` nor `.persist()`, and has not been invoked;
516- Is persistent (i.e., registered with `.persist()`) and has not been invoked;
517- Is registered with `.times(<number>)` and has not been invoked `<number>` of times.
518
519#### Example - Check that there are no pending interceptors
520
521```js
522const agent = new MockAgent()
523agent.disableNetConnect()
524
525agent
526  .get('https://example.com')
527  .intercept({ method: 'GET', path: '/' })
528  .reply(200)
529
530agent.assertNoPendingInterceptors()
531// Throws an UndiciError with the following message:
532//
533// 1 interceptor is pending:
534//
535// ┌─────────┬────────┬───────────────────────┬──────┬─────────────┬────────────┬─────────────┬───────────┐
536// │ (index) │ Method │        Origin         │ Path │ Status code │ Persistent │ Invocations │ Remaining │
537// ├─────────┼────────┼───────────────────────┼──────┼─────────────┼────────────┼─────────────┼───────────┤
538// │    0    │ 'GET'  │ 'https://example.com' │ '/'  │     200     │    '❌'    │      0      │     1     │
539// └─────────┴────────┴───────────────────────┴──────┴─────────────┴────────────┴─────────────┴───────────┘
540```
541