Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nodejs/undici/llms.txt

Use this file to discover all available pages before exploring further.

MockClient extends undici’s Client class and gives you the same intercept API as MockPool but constrained to a single persistent connection. You rarely instantiate MockClient directly — the standard approach is to call mockAgent.get(origin) on a MockAgent configured with connections: 1, which returns a MockClient automatically. Direct instantiation is available for advanced cases where you want to own the lifecycle of a single-origin mock entirely.

Constructor

MockClient requires an agent option that is a MockAgent instance. Omitting it throws an InvalidArgumentError.
origin
string
required
The origin to mock. Must include the protocol, hostname, and optionally the port — for example 'http://localhost:3000'. No path component.
options
object
required
Extends ClientOptions.

Getting a MockClient from MockAgent

The recommended way to obtain a MockClient is through MockAgent:
Obtaining a MockClient via MockAgent
import { MockAgent } from 'undici'

// connections: 1 tells MockAgent to create MockClient instances instead of MockPool
const mockAgent = new MockAgent({ connections: 1 })

const mockClient = mockAgent.get('http://localhost:3000')
// mockClient is a MockClient instance

mockClient.intercept(options)

Registers an interceptor on this client. The options and return value are identical to MockPool.intercept().
options
object
required
returns
MockInterceptor
Chain .reply(), .replyWithError(), .defaultReplyHeaders(), .defaultReplyTrailers(), .replyContentLength() to define the response. Then chain .persist(), .times(n), or .delay(ms) on the returned MockScope to control repeat behaviour.
Intercepting a GET request on MockClient
import { MockAgent, request } from 'undici'

const mockAgent = new MockAgent({ connections: 1 })
const mockClient = mockAgent.get('http://localhost:3000')

mockClient.intercept({ path: '/foo', method: 'GET' }).reply(200, 'foo')

const { statusCode, body } = await mockClient.request({
  origin: 'http://localhost:3000',
  path: '/foo',
  method: 'GET'
})

console.log(statusCode) // 200

for await (const chunk of body) {
  console.log(chunk.toString('utf8')) // foo
}

Additional instance methods

mockClient.cleanMocks()

Removes all registered interceptors from the client.
Clearing all interceptors
mockClient.cleanMocks()

mockClient.close()

Closes the client and de-registers it from its parent MockAgent.
Closing a MockClient
await mockClient.close()

mockClient.request(options)

Same as Dispatcher.request(). You can dispatch requests directly through the mock client without going through the global dispatcher.
Direct request through MockClient
import { MockAgent } from 'undici'

const mockAgent = new MockAgent({ connections: 1 })
const mockClient = mockAgent.get('http://localhost:3000')

mockClient.intercept({ path: '/health' }).reply(200, { ok: true })

const { statusCode, body } = await mockClient.request({
  origin: 'http://localhost:3000',
  path: '/health',
  method: 'GET'
})

console.log(await body.json()) // { ok: true }

When to use MockClient vs MockPool vs MockAgent

In most tests you do not need to choose — use MockAgent and let it create the right type for you.
ScenarioRecommended class
General-purpose mocking across multiple originsMockAgent + mockAgent.get() (returns MockPool by default)
Simulating a single-connection origin (e.g. HTTP/1.1 keep-alive server)MockAgent({ connections: 1 })MockClient
Owning mock lifecycle for one origin independentlyMockClient directly (advanced)
Multiple concurrent connections to one originMockPool (via MockAgent)
MockClient is backed by a single undici Client, meaning requests are serialised through one connection. MockPool allows multiple concurrent connections to the same origin. Choose MockClient when your production code targets a Client directly or when you need to test single-connection semantics.

Complete example

MockClient in a node:test test
import { test } from 'node:test'
import assert from 'node:assert/strict'
import { MockAgent, setGlobalDispatcher, getGlobalDispatcher, request } from 'undici'

test('single-connection mock with MockClient', async (t) => {
  const original = getGlobalDispatcher()

  // connections: 1 → MockAgent.get() returns a MockClient
  const mockAgent = new MockAgent({ connections: 1 })
  mockAgent.disableNetConnect()
  setGlobalDispatcher(mockAgent)

  t.after(async () => {
    await mockAgent.close()
    setGlobalDispatcher(original)
  })

  const mockClient = mockAgent.get('http://localhost:3000')

  mockClient
    .intercept({ path: '/ping', method: 'GET' })
    .reply(200, { pong: true }, { headers: { 'content-type': 'application/json' } })

  const { statusCode, body } = await request('http://localhost:3000/ping')

  assert.equal(statusCode, 200)
  const json = await body.json()
  assert.deepEqual(json, { pong: true })
})

Build docs developers (and LLMs) love