Skip to content

MockPool/MockClient cleanMocks() doesn't clear the interceptors that Node.js global fetch uses #6013

Open

Description

@Anoesj

Bug Description

After mockPool.cleanMocks(), requests from Node.js' global fetch still match the interceptors from before the call, and never match interceptors added after it. Requests through undici's own fetch/request aren't affected.

Cause: since #5648 (v8.10.1), MockAgent.dispatch mirrors a pool's interceptors into a separate ${origin}#http1-only dispatcher for legacy global dispatcher consumers like Node.js' bundled fetch (which goes through Dispatcher1Wrapper with allowH2: false). It does so by sharing the kDispatches array once:

http1OnlyDispatcher[kDispatches] = mockDispatcher[kDispatches]

cleanMocks() on MockPool and MockClient replaces that array instead of emptying it:

cleanMocks () {
  this[kDispatches] = []
}

So the #http1-only dispatcher keeps the old array: its interceptors stay active, and new ones never reach it.

Reproduction

Standalone reproduction script:

'use strict'

const { test } = require('node:test')
const assert = require('node:assert')
const { MockAgent, setGlobalDispatcher } = require('undici')

test('cleanMocks() also clears the interceptors that global fetch uses', async (t) => {
  const agent = new MockAgent()
  agent.disableNetConnect()
  setGlobalDispatcher(agent)
  t.after(() => agent.close())

  const mockPool = agent.get('https://example.com')
  mockPool.intercept({ path: '/' }).reply(200, 'first').persist()
  assert.strictEqual(await (await fetch('https://example.com/')).text(), 'first')

  mockPool.cleanMocks()
  mockPool.intercept({ path: '/' }).reply(200, 'second').persist()
  assert.strictEqual(await (await fetch('https://example.com/')).text(), 'second')
})

Expected Behavior

The second fetch gets 'second': after cleanMocks(), only the interceptors added after it apply.

Actual Behavior

The second fetch gets 'first':

actual: 'first',
expected: 'second',

Without .persist(), the first interceptor is used up, and the second fetch fails with MockNotMatchedError instead.

Environment

  • OS: Linux
  • Node.js version: v24.15.0
  • undici version: 8.12.1 (current main), also 8.11.2

Additional context

This breaks the common test setup of one MockAgent as the global dispatcher with cleanMocks() between tests, for code that uses Node.js' global fetch. I'll open a PR that empties the array in place.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions