123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- 'use strict'
- 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
|