1'use strict'
2
3const { promisify } = require('util')
4const Client = require('../client')
5const { buildMockDispatch } = require('./mock-utils')
6const {
7  kDispatches,
8  kMockAgent,
9  kClose,
10  kOriginalClose,
11  kOrigin,
12  kOriginalDispatch,
13  kConnected
14} = require('./mock-symbols')
15const { MockInterceptor } = require('./mock-interceptor')
16const Symbols = require('../core/symbols')
17const { InvalidArgumentError } = require('../core/errors')
18
19/**
20 * MockClient provides an API that extends the Client to influence the mockDispatches.
21 */
22class MockClient extends Client {
23  constructor (origin, opts) {
24    super(origin, opts)
25
26    if (!opts || !opts.agent || typeof opts.agent.dispatch !== 'function') {
27      throw new InvalidArgumentError('Argument opts.agent must implement Agent')
28    }
29
30    this[kMockAgent] = opts.agent
31    this[kOrigin] = origin
32    this[kDispatches] = []
33    this[kConnected] = 1
34    this[kOriginalDispatch] = this.dispatch
35    this[kOriginalClose] = this.close.bind(this)
36
37    this.dispatch = buildMockDispatch.call(this)
38    this.close = this[kClose]
39  }
40
41  get [Symbols.kConnected] () {
42    return this[kConnected]
43  }
44
45  /**
46   * Sets up the base interceptor for mocking replies from undici.
47   */
48  intercept (opts) {
49    return new MockInterceptor(opts, this[kDispatches])
50  }
51
52  async [kClose] () {
53    await promisify(this[kOriginalClose])()
54    this[kConnected] = 0
55    this[kMockAgent][Symbols.kClients].delete(this[kOrigin])
56  }
57}
58
59module.exports = MockClient
60