Spaces:
Runtime error
Runtime error
| const { kClients } = require('../core/symbols') | |
| const Agent = require('../agent') | |
| const { | |
| kAgent, | |
| kMockAgentSet, | |
| kMockAgentGet, | |
| kDispatches, | |
| kIsMockActive, | |
| kNetConnect, | |
| kGetNetConnect, | |
| kOptions, | |
| kFactory | |
| } = require('./mock-symbols') | |
| const MockClient = require('./mock-client') | |
| const MockPool = require('./mock-pool') | |
| const { matchValue, buildMockOptions } = require('./mock-utils') | |
| const { InvalidArgumentError, UndiciError } = require('../core/errors') | |
| const Dispatcher = require('../dispatcher') | |
| const Pluralizer = require('./pluralizer') | |
| const PendingInterceptorsFormatter = require('./pending-interceptors-formatter') | |
| class FakeWeakRef { | |
| constructor (value) { | |
| this.value = value | |
| } | |
| deref () { | |
| return this.value | |
| } | |
| } | |
| class MockAgent extends Dispatcher { | |
| constructor (opts) { | |
| super(opts) | |
| this[kNetConnect] = true | |
| this[kIsMockActive] = true | |
| // Instantiate Agent and encapsulate | |
| if ((opts && opts.agent && typeof opts.agent.dispatch !== 'function')) { | |
| throw new InvalidArgumentError('Argument opts.agent must implement Agent') | |
| } | |
| const agent = opts && opts.agent ? opts.agent : new Agent(opts) | |
| this[kAgent] = agent | |
| this[kClients] = agent[kClients] | |
| this[kOptions] = buildMockOptions(opts) | |
| } | |
| get (origin) { | |
| let dispatcher = this[kMockAgentGet](origin) | |
| if (!dispatcher) { | |
| dispatcher = this[kFactory](origin) | |
| this[kMockAgentSet](origin, dispatcher) | |
| } | |
| return dispatcher | |
| } | |
| dispatch (opts, handler) { | |
| // Call MockAgent.get to perform additional setup before dispatching as normal | |
| this.get(opts.origin) | |
| return this[kAgent].dispatch(opts, handler) | |
| } | |
| async close () { | |
| await this[kAgent].close() | |
| this[kClients].clear() | |
| } | |
| deactivate () { | |
| this[kIsMockActive] = false | |
| } | |
| activate () { | |
| this[kIsMockActive] = true | |
| } | |
| enableNetConnect (matcher) { | |
| if (typeof matcher === 'string' || typeof matcher === 'function' || matcher instanceof RegExp) { | |
| if (Array.isArray(this[kNetConnect])) { | |
| this[kNetConnect].push(matcher) | |
| } else { | |
| this[kNetConnect] = [matcher] | |
| } | |
| } else if (typeof matcher === 'undefined') { | |
| this[kNetConnect] = true | |
| } else { | |
| throw new InvalidArgumentError('Unsupported matcher. Must be one of String|Function|RegExp.') | |
| } | |
| } | |
| disableNetConnect () { | |
| this[kNetConnect] = false | |
| } | |
| // This is required to bypass issues caused by using global symbols - see: | |
| // https://github.com/nodejs/undici/issues/1447 | |
| get isMockActive () { | |
| return this[kIsMockActive] | |
| } | |
| [kMockAgentSet] (origin, dispatcher) { | |
| this[kClients].set(origin, new FakeWeakRef(dispatcher)) | |
| } | |
| [kFactory] (origin) { | |
| const mockOptions = Object.assign({ agent: this }, this[kOptions]) | |
| return this[kOptions] && this[kOptions].connections === 1 | |
| ? new MockClient(origin, mockOptions) | |
| : new MockPool(origin, mockOptions) | |
| } | |
| [kMockAgentGet] (origin) { | |
| // First check if we can immediately find it | |
| const ref = this[kClients].get(origin) | |
| if (ref) { | |
| return ref.deref() | |
| } | |
| // If the origin is not a string create a dummy parent pool and return to user | |
| if (typeof origin !== 'string') { | |
| const dispatcher = this[kFactory]('http://localhost:9999') | |
| this[kMockAgentSet](origin, dispatcher) | |
| return dispatcher | |
| } | |
| // If we match, create a pool and assign the same dispatches | |
| for (const [keyMatcher, nonExplicitRef] of Array.from(this[kClients])) { | |
| const nonExplicitDispatcher = nonExplicitRef.deref() | |
| if (nonExplicitDispatcher && typeof keyMatcher !== 'string' && matchValue(keyMatcher, origin)) { | |
| const dispatcher = this[kFactory](origin) | |
| this[kMockAgentSet](origin, dispatcher) | |
| dispatcher[kDispatches] = nonExplicitDispatcher[kDispatches] | |
| return dispatcher | |
| } | |
| } | |
| } | |
| [kGetNetConnect] () { | |
| return this[kNetConnect] | |
| } | |
| pendingInterceptors () { | |
| const mockAgentClients = this[kClients] | |
| return Array.from(mockAgentClients.entries()) | |
| .flatMap(([origin, scope]) => scope.deref()[kDispatches].map(dispatch => ({ ...dispatch, origin }))) | |
| .filter(({ pending }) => pending) | |
| } | |
| assertNoPendingInterceptors ({ pendingInterceptorsFormatter = new PendingInterceptorsFormatter() } = {}) { | |
| const pending = this.pendingInterceptors() | |
| if (pending.length === 0) { | |
| return | |
| } | |
| const pluralizer = new Pluralizer('interceptor', 'interceptors').pluralize(pending.length) | |
| throw new UndiciError(` | |
| ${pluralizer.count} ${pluralizer.noun} ${pluralizer.is} pending: | |
| ${pendingInterceptorsFormatter.format(pending)} | |
| `.trim()) | |
| } | |
| } | |
| module.exports = MockAgent | |