chore: update deps
This commit is contained in:
105
node_modules/undici/lib/mock/mock-agent.js
generated
vendored
105
node_modules/undici/lib/mock/mock-agent.js
generated
vendored
@ -1,7 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const { kClients } = require('../core/symbols')
|
||||
const Agent = require('../agent')
|
||||
const Agent = require('../dispatcher/agent')
|
||||
const {
|
||||
kAgent,
|
||||
kMockAgentSet,
|
||||
@ -11,42 +11,44 @@ const {
|
||||
kNetConnect,
|
||||
kGetNetConnect,
|
||||
kOptions,
|
||||
kFactory
|
||||
kFactory,
|
||||
kMockAgentRegisterCallHistory,
|
||||
kMockAgentIsCallHistoryEnabled,
|
||||
kMockAgentAddCallHistoryLog,
|
||||
kMockAgentMockCallHistoryInstance,
|
||||
kMockCallHistoryAddLog
|
||||
} = require('./mock-symbols')
|
||||
const MockClient = require('./mock-client')
|
||||
const MockPool = require('./mock-pool')
|
||||
const { matchValue, buildMockOptions } = require('./mock-utils')
|
||||
const { matchValue, buildAndValidateMockOptions } = require('./mock-utils')
|
||||
const { InvalidArgumentError, UndiciError } = require('../core/errors')
|
||||
const Dispatcher = require('../dispatcher')
|
||||
const Pluralizer = require('./pluralizer')
|
||||
const Dispatcher = require('../dispatcher/dispatcher')
|
||||
const PendingInterceptorsFormatter = require('./pending-interceptors-formatter')
|
||||
|
||||
class FakeWeakRef {
|
||||
constructor (value) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
deref () {
|
||||
return this.value
|
||||
}
|
||||
}
|
||||
const { MockCallHistory } = require('./mock-call-history')
|
||||
|
||||
class MockAgent extends Dispatcher {
|
||||
constructor (opts) {
|
||||
super(opts)
|
||||
|
||||
const mockOptions = buildAndValidateMockOptions(opts)
|
||||
|
||||
this[kNetConnect] = true
|
||||
this[kIsMockActive] = true
|
||||
this[kMockAgentIsCallHistoryEnabled] = mockOptions?.enableCallHistory ?? false
|
||||
|
||||
// Instantiate Agent and encapsulate
|
||||
if ((opts && opts.agent && typeof opts.agent.dispatch !== 'function')) {
|
||||
if (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)
|
||||
const agent = opts?.agent ? opts.agent : new Agent(opts)
|
||||
this[kAgent] = agent
|
||||
|
||||
this[kClients] = agent[kClients]
|
||||
this[kOptions] = buildMockOptions(opts)
|
||||
this[kOptions] = mockOptions
|
||||
|
||||
if (this[kMockAgentIsCallHistoryEnabled]) {
|
||||
this[kMockAgentRegisterCallHistory]()
|
||||
}
|
||||
}
|
||||
|
||||
get (origin) {
|
||||
@ -62,10 +64,14 @@ class MockAgent extends Dispatcher {
|
||||
dispatch (opts, handler) {
|
||||
// Call MockAgent.get to perform additional setup before dispatching as normal
|
||||
this.get(opts.origin)
|
||||
|
||||
this[kMockAgentAddCallHistoryLog](opts)
|
||||
|
||||
return this[kAgent].dispatch(opts, handler)
|
||||
}
|
||||
|
||||
async close () {
|
||||
this.clearCallHistory()
|
||||
await this[kAgent].close()
|
||||
this[kClients].clear()
|
||||
}
|
||||
@ -96,14 +102,52 @@ class MockAgent extends Dispatcher {
|
||||
this[kNetConnect] = false
|
||||
}
|
||||
|
||||
enableCallHistory () {
|
||||
this[kMockAgentIsCallHistoryEnabled] = true
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
disableCallHistory () {
|
||||
this[kMockAgentIsCallHistoryEnabled] = false
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
getCallHistory () {
|
||||
return this[kMockAgentMockCallHistoryInstance]
|
||||
}
|
||||
|
||||
clearCallHistory () {
|
||||
if (this[kMockAgentMockCallHistoryInstance] !== undefined) {
|
||||
this[kMockAgentMockCallHistoryInstance].clear()
|
||||
}
|
||||
}
|
||||
|
||||
// This is required to bypass issues caused by using global symbols - see:
|
||||
// https://github.com/nodejs/undici/issues/1447
|
||||
get isMockActive () {
|
||||
return this[kIsMockActive]
|
||||
}
|
||||
|
||||
[kMockAgentRegisterCallHistory] () {
|
||||
if (this[kMockAgentMockCallHistoryInstance] === undefined) {
|
||||
this[kMockAgentMockCallHistoryInstance] = new MockCallHistory()
|
||||
}
|
||||
}
|
||||
|
||||
[kMockAgentAddCallHistoryLog] (opts) {
|
||||
if (this[kMockAgentIsCallHistoryEnabled]) {
|
||||
// additional setup when enableCallHistory class method is used after mockAgent instantiation
|
||||
this[kMockAgentRegisterCallHistory]()
|
||||
|
||||
// add call history log on every call (intercepted or not)
|
||||
this[kMockAgentMockCallHistoryInstance][kMockCallHistoryAddLog](opts)
|
||||
}
|
||||
}
|
||||
|
||||
[kMockAgentSet] (origin, dispatcher) {
|
||||
this[kClients].set(origin, new FakeWeakRef(dispatcher))
|
||||
this[kClients].set(origin, dispatcher)
|
||||
}
|
||||
|
||||
[kFactory] (origin) {
|
||||
@ -115,9 +159,9 @@ class MockAgent extends Dispatcher {
|
||||
|
||||
[kMockAgentGet] (origin) {
|
||||
// First check if we can immediately find it
|
||||
const ref = this[kClients].get(origin)
|
||||
if (ref) {
|
||||
return ref.deref()
|
||||
const client = this[kClients].get(origin)
|
||||
if (client) {
|
||||
return client
|
||||
}
|
||||
|
||||
// If the origin is not a string create a dummy parent pool and return to user
|
||||
@ -128,8 +172,7 @@ class MockAgent extends 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()
|
||||
for (const [keyMatcher, nonExplicitDispatcher] of Array.from(this[kClients])) {
|
||||
if (nonExplicitDispatcher && typeof keyMatcher !== 'string' && matchValue(keyMatcher, origin)) {
|
||||
const dispatcher = this[kFactory](origin)
|
||||
this[kMockAgentSet](origin, dispatcher)
|
||||
@ -147,7 +190,7 @@ class MockAgent extends Dispatcher {
|
||||
const mockAgentClients = this[kClients]
|
||||
|
||||
return Array.from(mockAgentClients.entries())
|
||||
.flatMap(([origin, scope]) => scope.deref()[kDispatches].map(dispatch => ({ ...dispatch, origin })))
|
||||
.flatMap(([origin, scope]) => scope[kDispatches].map(dispatch => ({ ...dispatch, origin })))
|
||||
.filter(({ pending }) => pending)
|
||||
}
|
||||
|
||||
@ -158,13 +201,11 @@ class MockAgent extends Dispatcher {
|
||||
return
|
||||
}
|
||||
|
||||
const pluralizer = new Pluralizer('interceptor', 'interceptors').pluralize(pending.length)
|
||||
|
||||
throw new UndiciError(`
|
||||
${pluralizer.count} ${pluralizer.noun} ${pluralizer.is} pending:
|
||||
|
||||
${pendingInterceptorsFormatter.format(pending)}
|
||||
`.trim())
|
||||
throw new UndiciError(
|
||||
pending.length === 1
|
||||
? `1 interceptor is pending:\n\n${pendingInterceptorsFormatter.format(pending)}`.trim()
|
||||
: `${pending.length} interceptors are pending:\n\n${pendingInterceptorsFormatter.format(pending)}`.trim()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
248
node_modules/undici/lib/mock/mock-call-history.js
generated
vendored
Normal file
248
node_modules/undici/lib/mock/mock-call-history.js
generated
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
'use strict'
|
||||
|
||||
const { kMockCallHistoryAddLog } = require('./mock-symbols')
|
||||
const { InvalidArgumentError } = require('../core/errors')
|
||||
|
||||
function handleFilterCallsWithOptions (criteria, options, handler, store) {
|
||||
switch (options.operator) {
|
||||
case 'OR':
|
||||
store.push(...handler(criteria))
|
||||
|
||||
return store
|
||||
case 'AND':
|
||||
return handler.call({ logs: store }, criteria)
|
||||
default:
|
||||
// guard -- should never happens because buildAndValidateFilterCallsOptions is called before
|
||||
throw new InvalidArgumentError('options.operator must to be a case insensitive string equal to \'OR\' or \'AND\'')
|
||||
}
|
||||
}
|
||||
|
||||
function buildAndValidateFilterCallsOptions (options = {}) {
|
||||
const finalOptions = {}
|
||||
|
||||
if ('operator' in options) {
|
||||
if (typeof options.operator !== 'string' || (options.operator.toUpperCase() !== 'OR' && options.operator.toUpperCase() !== 'AND')) {
|
||||
throw new InvalidArgumentError('options.operator must to be a case insensitive string equal to \'OR\' or \'AND\'')
|
||||
}
|
||||
|
||||
return {
|
||||
...finalOptions,
|
||||
operator: options.operator.toUpperCase()
|
||||
}
|
||||
}
|
||||
|
||||
return finalOptions
|
||||
}
|
||||
|
||||
function makeFilterCalls (parameterName) {
|
||||
return (parameterValue) => {
|
||||
if (typeof parameterValue === 'string' || parameterValue == null) {
|
||||
return this.logs.filter((log) => {
|
||||
return log[parameterName] === parameterValue
|
||||
})
|
||||
}
|
||||
if (parameterValue instanceof RegExp) {
|
||||
return this.logs.filter((log) => {
|
||||
return parameterValue.test(log[parameterName])
|
||||
})
|
||||
}
|
||||
|
||||
throw new InvalidArgumentError(`${parameterName} parameter should be one of string, regexp, undefined or null`)
|
||||
}
|
||||
}
|
||||
function computeUrlWithMaybeSearchParameters (requestInit) {
|
||||
// path can contains query url parameters
|
||||
// or query can contains query url parameters
|
||||
try {
|
||||
const url = new URL(requestInit.path, requestInit.origin)
|
||||
|
||||
// requestInit.path contains query url parameters
|
||||
// requestInit.query is then undefined
|
||||
if (url.search.length !== 0) {
|
||||
return url
|
||||
}
|
||||
|
||||
// requestInit.query can be populated here
|
||||
url.search = new URLSearchParams(requestInit.query).toString()
|
||||
|
||||
return url
|
||||
} catch (error) {
|
||||
throw new InvalidArgumentError('An error occurred when computing MockCallHistoryLog.url', { cause: error })
|
||||
}
|
||||
}
|
||||
|
||||
class MockCallHistoryLog {
|
||||
constructor (requestInit = {}) {
|
||||
this.body = requestInit.body
|
||||
this.headers = requestInit.headers
|
||||
this.method = requestInit.method
|
||||
|
||||
const url = computeUrlWithMaybeSearchParameters(requestInit)
|
||||
|
||||
this.fullUrl = url.toString()
|
||||
this.origin = url.origin
|
||||
this.path = url.pathname
|
||||
this.searchParams = Object.fromEntries(url.searchParams)
|
||||
this.protocol = url.protocol
|
||||
this.host = url.host
|
||||
this.port = url.port
|
||||
this.hash = url.hash
|
||||
}
|
||||
|
||||
toMap () {
|
||||
return new Map([
|
||||
['protocol', this.protocol],
|
||||
['host', this.host],
|
||||
['port', this.port],
|
||||
['origin', this.origin],
|
||||
['path', this.path],
|
||||
['hash', this.hash],
|
||||
['searchParams', this.searchParams],
|
||||
['fullUrl', this.fullUrl],
|
||||
['method', this.method],
|
||||
['body', this.body],
|
||||
['headers', this.headers]]
|
||||
)
|
||||
}
|
||||
|
||||
toString () {
|
||||
const options = { betweenKeyValueSeparator: '->', betweenPairSeparator: '|' }
|
||||
let result = ''
|
||||
|
||||
this.toMap().forEach((value, key) => {
|
||||
if (typeof value === 'string' || value === undefined || value === null) {
|
||||
result = `${result}${key}${options.betweenKeyValueSeparator}${value}${options.betweenPairSeparator}`
|
||||
}
|
||||
if ((typeof value === 'object' && value !== null) || Array.isArray(value)) {
|
||||
result = `${result}${key}${options.betweenKeyValueSeparator}${JSON.stringify(value)}${options.betweenPairSeparator}`
|
||||
}
|
||||
// maybe miss something for non Record / Array headers and searchParams here
|
||||
})
|
||||
|
||||
// delete last betweenPairSeparator
|
||||
return result.slice(0, -1)
|
||||
}
|
||||
}
|
||||
|
||||
class MockCallHistory {
|
||||
logs = []
|
||||
|
||||
calls () {
|
||||
return this.logs
|
||||
}
|
||||
|
||||
firstCall () {
|
||||
return this.logs.at(0)
|
||||
}
|
||||
|
||||
lastCall () {
|
||||
return this.logs.at(-1)
|
||||
}
|
||||
|
||||
nthCall (number) {
|
||||
if (typeof number !== 'number') {
|
||||
throw new InvalidArgumentError('nthCall must be called with a number')
|
||||
}
|
||||
if (!Number.isInteger(number)) {
|
||||
throw new InvalidArgumentError('nthCall must be called with an integer')
|
||||
}
|
||||
if (Math.sign(number) !== 1) {
|
||||
throw new InvalidArgumentError('nthCall must be called with a positive value. use firstCall or lastCall instead')
|
||||
}
|
||||
|
||||
// non zero based index. this is more human readable
|
||||
return this.logs.at(number - 1)
|
||||
}
|
||||
|
||||
filterCalls (criteria, options) {
|
||||
// perf
|
||||
if (this.logs.length === 0) {
|
||||
return this.logs
|
||||
}
|
||||
if (typeof criteria === 'function') {
|
||||
return this.logs.filter(criteria)
|
||||
}
|
||||
if (criteria instanceof RegExp) {
|
||||
return this.logs.filter((log) => {
|
||||
return criteria.test(log.toString())
|
||||
})
|
||||
}
|
||||
if (typeof criteria === 'object' && criteria !== null) {
|
||||
// no criteria - returning all logs
|
||||
if (Object.keys(criteria).length === 0) {
|
||||
return this.logs
|
||||
}
|
||||
|
||||
const finalOptions = { operator: 'OR', ...buildAndValidateFilterCallsOptions(options) }
|
||||
|
||||
let maybeDuplicatedLogsFiltered = []
|
||||
if ('protocol' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.protocol, finalOptions, this.filterCallsByProtocol, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
if ('host' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.host, finalOptions, this.filterCallsByHost, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
if ('port' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.port, finalOptions, this.filterCallsByPort, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
if ('origin' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.origin, finalOptions, this.filterCallsByOrigin, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
if ('path' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.path, finalOptions, this.filterCallsByPath, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
if ('hash' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.hash, finalOptions, this.filterCallsByHash, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
if ('fullUrl' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.fullUrl, finalOptions, this.filterCallsByFullUrl, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
if ('method' in criteria) {
|
||||
maybeDuplicatedLogsFiltered = handleFilterCallsWithOptions(criteria.method, finalOptions, this.filterCallsByMethod, maybeDuplicatedLogsFiltered)
|
||||
}
|
||||
|
||||
const uniqLogsFiltered = [...new Set(maybeDuplicatedLogsFiltered)]
|
||||
|
||||
return uniqLogsFiltered
|
||||
}
|
||||
|
||||
throw new InvalidArgumentError('criteria parameter should be one of function, regexp, or object')
|
||||
}
|
||||
|
||||
filterCallsByProtocol = makeFilterCalls.call(this, 'protocol')
|
||||
|
||||
filterCallsByHost = makeFilterCalls.call(this, 'host')
|
||||
|
||||
filterCallsByPort = makeFilterCalls.call(this, 'port')
|
||||
|
||||
filterCallsByOrigin = makeFilterCalls.call(this, 'origin')
|
||||
|
||||
filterCallsByPath = makeFilterCalls.call(this, 'path')
|
||||
|
||||
filterCallsByHash = makeFilterCalls.call(this, 'hash')
|
||||
|
||||
filterCallsByFullUrl = makeFilterCalls.call(this, 'fullUrl')
|
||||
|
||||
filterCallsByMethod = makeFilterCalls.call(this, 'method')
|
||||
|
||||
clear () {
|
||||
this.logs = []
|
||||
}
|
||||
|
||||
[kMockCallHistoryAddLog] (requestInit) {
|
||||
const log = new MockCallHistoryLog(requestInit)
|
||||
|
||||
this.logs.push(log)
|
||||
|
||||
return log
|
||||
}
|
||||
|
||||
* [Symbol.iterator] () {
|
||||
for (const log of this.calls()) {
|
||||
yield log
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.MockCallHistory = MockCallHistory
|
||||
module.exports.MockCallHistoryLog = MockCallHistoryLog
|
17
node_modules/undici/lib/mock/mock-client.js
generated
vendored
17
node_modules/undici/lib/mock/mock-client.js
generated
vendored
@ -1,7 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const { promisify } = require('util')
|
||||
const Client = require('../client')
|
||||
const { promisify } = require('node:util')
|
||||
const Client = require('../dispatcher/client')
|
||||
const { buildMockDispatch } = require('./mock-utils')
|
||||
const {
|
||||
kDispatches,
|
||||
@ -10,7 +10,8 @@ const {
|
||||
kOriginalClose,
|
||||
kOrigin,
|
||||
kOriginalDispatch,
|
||||
kConnected
|
||||
kConnected,
|
||||
kIgnoreTrailingSlash
|
||||
} = require('./mock-symbols')
|
||||
const { MockInterceptor } = require('./mock-interceptor')
|
||||
const Symbols = require('../core/symbols')
|
||||
@ -21,14 +22,15 @@ const { InvalidArgumentError } = require('../core/errors')
|
||||
*/
|
||||
class MockClient extends Client {
|
||||
constructor (origin, opts) {
|
||||
super(origin, opts)
|
||||
|
||||
if (!opts || !opts.agent || typeof opts.agent.dispatch !== 'function') {
|
||||
throw new InvalidArgumentError('Argument opts.agent must implement Agent')
|
||||
}
|
||||
|
||||
super(origin, opts)
|
||||
|
||||
this[kMockAgent] = opts.agent
|
||||
this[kOrigin] = origin
|
||||
this[kIgnoreTrailingSlash] = opts.ignoreTrailingSlash ?? false
|
||||
this[kDispatches] = []
|
||||
this[kConnected] = 1
|
||||
this[kOriginalDispatch] = this.dispatch
|
||||
@ -46,7 +48,10 @@ class MockClient extends Client {
|
||||
* Sets up the base interceptor for mocking replies from undici.
|
||||
*/
|
||||
intercept (opts) {
|
||||
return new MockInterceptor(opts, this[kDispatches])
|
||||
return new MockInterceptor(
|
||||
opts && { ignoreTrailingSlash: this[kIgnoreTrailingSlash], ...opts },
|
||||
this[kDispatches]
|
||||
)
|
||||
}
|
||||
|
||||
async [kClose] () {
|
||||
|
4
node_modules/undici/lib/mock/mock-errors.js
generated
vendored
4
node_modules/undici/lib/mock/mock-errors.js
generated
vendored
@ -2,10 +2,12 @@
|
||||
|
||||
const { UndiciError } = require('../core/errors')
|
||||
|
||||
/**
|
||||
* The request does not match any registered mock dispatches.
|
||||
*/
|
||||
class MockNotMatchedError extends UndiciError {
|
||||
constructor (message) {
|
||||
super(message)
|
||||
Error.captureStackTrace(this, MockNotMatchedError)
|
||||
this.name = 'MockNotMatchedError'
|
||||
this.message = message || 'The request does not match any registered mock dispatches'
|
||||
this.code = 'UND_MOCK_ERR_MOCK_NOT_MATCHED'
|
||||
|
51
node_modules/undici/lib/mock/mock-interceptor.js
generated
vendored
51
node_modules/undici/lib/mock/mock-interceptor.js
generated
vendored
@ -7,10 +7,11 @@ const {
|
||||
kDefaultHeaders,
|
||||
kDefaultTrailers,
|
||||
kContentLength,
|
||||
kMockDispatch
|
||||
kMockDispatch,
|
||||
kIgnoreTrailingSlash
|
||||
} = require('./mock-symbols')
|
||||
const { InvalidArgumentError } = require('../core/errors')
|
||||
const { buildURL } = require('../core/util')
|
||||
const { serializePathWithQuery } = require('../core/util')
|
||||
|
||||
/**
|
||||
* Defines the scope API for an interceptor reply
|
||||
@ -72,9 +73,9 @@ class MockInterceptor {
|
||||
// fragments to servers when they retrieve a document,
|
||||
if (typeof opts.path === 'string') {
|
||||
if (opts.query) {
|
||||
opts.path = buildURL(opts.path, opts.query)
|
||||
opts.path = serializePathWithQuery(opts.path, opts.query)
|
||||
} else {
|
||||
// Matches https://github.com/nodejs/undici/blob/main/lib/fetch/index.js#L1811
|
||||
// Matches https://github.com/nodejs/undici/blob/main/lib/web/fetch/index.js#L1811
|
||||
const parsedURL = new URL(opts.path, 'data://')
|
||||
opts.path = parsedURL.pathname + parsedURL.search
|
||||
}
|
||||
@ -85,12 +86,13 @@ class MockInterceptor {
|
||||
|
||||
this[kDispatchKey] = buildKey(opts)
|
||||
this[kDispatches] = mockDispatches
|
||||
this[kIgnoreTrailingSlash] = opts.ignoreTrailingSlash ?? false
|
||||
this[kDefaultHeaders] = {}
|
||||
this[kDefaultTrailers] = {}
|
||||
this[kContentLength] = false
|
||||
}
|
||||
|
||||
createMockScopeDispatchData (statusCode, data, responseOptions = {}) {
|
||||
createMockScopeDispatchData ({ statusCode, data, responseOptions }) {
|
||||
const responseData = getResponseData(data)
|
||||
const contentLength = this[kContentLength] ? { 'content-length': responseData.length } : {}
|
||||
const headers = { ...this[kDefaultHeaders], ...contentLength, ...responseOptions.headers }
|
||||
@ -99,14 +101,11 @@ class MockInterceptor {
|
||||
return { statusCode, data, headers, trailers }
|
||||
}
|
||||
|
||||
validateReplyParameters (statusCode, data, responseOptions) {
|
||||
if (typeof statusCode === 'undefined') {
|
||||
validateReplyParameters (replyParameters) {
|
||||
if (typeof replyParameters.statusCode === 'undefined') {
|
||||
throw new InvalidArgumentError('statusCode must be defined')
|
||||
}
|
||||
if (typeof data === 'undefined') {
|
||||
throw new InvalidArgumentError('data must be defined')
|
||||
}
|
||||
if (typeof responseOptions !== 'object') {
|
||||
if (typeof replyParameters.responseOptions !== 'object' || replyParameters.responseOptions === null) {
|
||||
throw new InvalidArgumentError('responseOptions must be an object')
|
||||
}
|
||||
}
|
||||
@ -114,33 +113,33 @@ class MockInterceptor {
|
||||
/**
|
||||
* Mock an undici request with a defined reply.
|
||||
*/
|
||||
reply (replyData) {
|
||||
reply (replyOptionsCallbackOrStatusCode) {
|
||||
// Values of reply aren't available right now as they
|
||||
// can only be available when the reply callback is invoked.
|
||||
if (typeof replyData === 'function') {
|
||||
if (typeof replyOptionsCallbackOrStatusCode === 'function') {
|
||||
// We'll first wrap the provided callback in another function,
|
||||
// this function will properly resolve the data from the callback
|
||||
// when invoked.
|
||||
const wrappedDefaultsCallback = (opts) => {
|
||||
// Our reply options callback contains the parameter for statusCode, data and options.
|
||||
const resolvedData = replyData(opts)
|
||||
const resolvedData = replyOptionsCallbackOrStatusCode(opts)
|
||||
|
||||
// Check if it is in the right format
|
||||
if (typeof resolvedData !== 'object') {
|
||||
if (typeof resolvedData !== 'object' || resolvedData === null) {
|
||||
throw new InvalidArgumentError('reply options callback must return an object')
|
||||
}
|
||||
|
||||
const { statusCode, data = '', responseOptions = {} } = resolvedData
|
||||
this.validateReplyParameters(statusCode, data, responseOptions)
|
||||
const replyParameters = { data: '', responseOptions: {}, ...resolvedData }
|
||||
this.validateReplyParameters(replyParameters)
|
||||
// Since the values can be obtained immediately we return them
|
||||
// from this higher order function that will be resolved later.
|
||||
return {
|
||||
...this.createMockScopeDispatchData(statusCode, data, responseOptions)
|
||||
...this.createMockScopeDispatchData(replyParameters)
|
||||
}
|
||||
}
|
||||
|
||||
// Add usual dispatch data, but this time set the data parameter to function that will eventually provide data.
|
||||
const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], wrappedDefaultsCallback)
|
||||
const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], wrappedDefaultsCallback, { ignoreTrailingSlash: this[kIgnoreTrailingSlash] })
|
||||
return new MockScope(newMockDispatch)
|
||||
}
|
||||
|
||||
@ -148,12 +147,16 @@ class MockInterceptor {
|
||||
// we should have 1-3 parameters. So we spread the arguments of
|
||||
// this function to obtain the parameters, since replyData will always
|
||||
// just be the statusCode.
|
||||
const [statusCode, data = '', responseOptions = {}] = [...arguments]
|
||||
this.validateReplyParameters(statusCode, data, responseOptions)
|
||||
const replyParameters = {
|
||||
statusCode: replyOptionsCallbackOrStatusCode,
|
||||
data: arguments[1] === undefined ? '' : arguments[1],
|
||||
responseOptions: arguments[2] === undefined ? {} : arguments[2]
|
||||
}
|
||||
this.validateReplyParameters(replyParameters)
|
||||
|
||||
// Send in-already provided data like usual
|
||||
const dispatchData = this.createMockScopeDispatchData(statusCode, data, responseOptions)
|
||||
const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], dispatchData)
|
||||
const dispatchData = this.createMockScopeDispatchData(replyParameters)
|
||||
const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], dispatchData, { ignoreTrailingSlash: this[kIgnoreTrailingSlash] })
|
||||
return new MockScope(newMockDispatch)
|
||||
}
|
||||
|
||||
@ -165,7 +168,7 @@ class MockInterceptor {
|
||||
throw new InvalidArgumentError('error must be defined')
|
||||
}
|
||||
|
||||
const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], { error })
|
||||
const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], { error }, { ignoreTrailingSlash: this[kIgnoreTrailingSlash] })
|
||||
return new MockScope(newMockDispatch)
|
||||
}
|
||||
|
||||
|
17
node_modules/undici/lib/mock/mock-pool.js
generated
vendored
17
node_modules/undici/lib/mock/mock-pool.js
generated
vendored
@ -1,7 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const { promisify } = require('util')
|
||||
const Pool = require('../pool')
|
||||
const { promisify } = require('node:util')
|
||||
const Pool = require('../dispatcher/pool')
|
||||
const { buildMockDispatch } = require('./mock-utils')
|
||||
const {
|
||||
kDispatches,
|
||||
@ -10,7 +10,8 @@ const {
|
||||
kOriginalClose,
|
||||
kOrigin,
|
||||
kOriginalDispatch,
|
||||
kConnected
|
||||
kConnected,
|
||||
kIgnoreTrailingSlash
|
||||
} = require('./mock-symbols')
|
||||
const { MockInterceptor } = require('./mock-interceptor')
|
||||
const Symbols = require('../core/symbols')
|
||||
@ -21,14 +22,15 @@ const { InvalidArgumentError } = require('../core/errors')
|
||||
*/
|
||||
class MockPool extends Pool {
|
||||
constructor (origin, opts) {
|
||||
super(origin, opts)
|
||||
|
||||
if (!opts || !opts.agent || typeof opts.agent.dispatch !== 'function') {
|
||||
throw new InvalidArgumentError('Argument opts.agent must implement Agent')
|
||||
}
|
||||
|
||||
super(origin, opts)
|
||||
|
||||
this[kMockAgent] = opts.agent
|
||||
this[kOrigin] = origin
|
||||
this[kIgnoreTrailingSlash] = opts.ignoreTrailingSlash ?? false
|
||||
this[kDispatches] = []
|
||||
this[kConnected] = 1
|
||||
this[kOriginalDispatch] = this.dispatch
|
||||
@ -46,7 +48,10 @@ class MockPool extends Pool {
|
||||
* Sets up the base interceptor for mocking replies from undici.
|
||||
*/
|
||||
intercept (opts) {
|
||||
return new MockInterceptor(opts, this[kDispatches])
|
||||
return new MockInterceptor(
|
||||
opts && { ignoreTrailingSlash: this[kIgnoreTrailingSlash], ...opts },
|
||||
this[kDispatches]
|
||||
)
|
||||
}
|
||||
|
||||
async [kClose] () {
|
||||
|
9
node_modules/undici/lib/mock/mock-symbols.js
generated
vendored
9
node_modules/undici/lib/mock/mock-symbols.js
generated
vendored
@ -15,9 +15,16 @@ module.exports = {
|
||||
kMockDispatch: Symbol('mock dispatch'),
|
||||
kClose: Symbol('close'),
|
||||
kOriginalClose: Symbol('original agent close'),
|
||||
kOriginalDispatch: Symbol('original dispatch'),
|
||||
kOrigin: Symbol('origin'),
|
||||
kIsMockActive: Symbol('is mock active'),
|
||||
kNetConnect: Symbol('net connect'),
|
||||
kGetNetConnect: Symbol('get net connect'),
|
||||
kConnected: Symbol('connected')
|
||||
kConnected: Symbol('connected'),
|
||||
kIgnoreTrailingSlash: Symbol('ignore trailing slash'),
|
||||
kMockAgentMockCallHistoryInstance: Symbol('mock agent mock call history name'),
|
||||
kMockAgentRegisterCallHistory: Symbol('mock agent register mock call history'),
|
||||
kMockAgentAddCallHistoryLog: Symbol('mock agent add call history log'),
|
||||
kMockAgentIsCallHistoryEnabled: Symbol('mock agent is call history enabled'),
|
||||
kMockCallHistoryAddLog: Symbol('mock call history add log')
|
||||
}
|
||||
|
96
node_modules/undici/lib/mock/mock-utils.js
generated
vendored
96
node_modules/undici/lib/mock/mock-utils.js
generated
vendored
@ -8,13 +8,14 @@ const {
|
||||
kOrigin,
|
||||
kGetNetConnect
|
||||
} = require('./mock-symbols')
|
||||
const { buildURL, nop } = require('../core/util')
|
||||
const { STATUS_CODES } = require('http')
|
||||
const { serializePathWithQuery } = require('../core/util')
|
||||
const { STATUS_CODES } = require('node:http')
|
||||
const {
|
||||
types: {
|
||||
isPromise
|
||||
}
|
||||
} = require('util')
|
||||
} = require('node:util')
|
||||
const { InvalidArgumentError } = require('../core/errors')
|
||||
|
||||
function matchValue (match, value) {
|
||||
if (typeof match === 'string') {
|
||||
@ -96,7 +97,7 @@ function safeUrl (path) {
|
||||
return path
|
||||
}
|
||||
|
||||
const pathSegments = path.split('?')
|
||||
const pathSegments = path.split('?', 3)
|
||||
|
||||
if (pathSegments.length !== 2) {
|
||||
return path
|
||||
@ -118,19 +119,33 @@ function matchKey (mockDispatch, { path, method, body, headers }) {
|
||||
function getResponseData (data) {
|
||||
if (Buffer.isBuffer(data)) {
|
||||
return data
|
||||
} else if (data instanceof Uint8Array) {
|
||||
return data
|
||||
} else if (data instanceof ArrayBuffer) {
|
||||
return data
|
||||
} else if (typeof data === 'object') {
|
||||
return JSON.stringify(data)
|
||||
} else {
|
||||
} else if (data) {
|
||||
return data.toString()
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
function getMockDispatch (mockDispatches, key) {
|
||||
const basePath = key.query ? buildURL(key.path, key.query) : key.path
|
||||
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path
|
||||
const resolvedPath = typeof basePath === 'string' ? safeUrl(basePath) : basePath
|
||||
|
||||
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath)
|
||||
|
||||
// Match path
|
||||
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path }) => matchValue(safeUrl(path), resolvedPath))
|
||||
let matchedMockDispatches = mockDispatches
|
||||
.filter(({ consumed }) => !consumed)
|
||||
.filter(({ path, ignoreTrailingSlash }) => {
|
||||
return ignoreTrailingSlash
|
||||
? matchValue(removeTrailingSlash(safeUrl(path)), resolvedPathWithoutTrailingSlash)
|
||||
: matchValue(safeUrl(path), resolvedPath)
|
||||
})
|
||||
if (matchedMockDispatches.length === 0) {
|
||||
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`)
|
||||
}
|
||||
@ -138,26 +153,27 @@ function getMockDispatch (mockDispatches, key) {
|
||||
// Match method
|
||||
matchedMockDispatches = matchedMockDispatches.filter(({ method }) => matchValue(method, key.method))
|
||||
if (matchedMockDispatches.length === 0) {
|
||||
throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}'`)
|
||||
throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}' on path '${resolvedPath}'`)
|
||||
}
|
||||
|
||||
// Match body
|
||||
matchedMockDispatches = matchedMockDispatches.filter(({ body }) => typeof body !== 'undefined' ? matchValue(body, key.body) : true)
|
||||
if (matchedMockDispatches.length === 0) {
|
||||
throw new MockNotMatchedError(`Mock dispatch not matched for body '${key.body}'`)
|
||||
throw new MockNotMatchedError(`Mock dispatch not matched for body '${key.body}' on path '${resolvedPath}'`)
|
||||
}
|
||||
|
||||
// Match headers
|
||||
matchedMockDispatches = matchedMockDispatches.filter((mockDispatch) => matchHeaders(mockDispatch, key.headers))
|
||||
if (matchedMockDispatches.length === 0) {
|
||||
throw new MockNotMatchedError(`Mock dispatch not matched for headers '${typeof key.headers === 'object' ? JSON.stringify(key.headers) : key.headers}'`)
|
||||
const headers = typeof key.headers === 'object' ? JSON.stringify(key.headers) : key.headers
|
||||
throw new MockNotMatchedError(`Mock dispatch not matched for headers '${headers}' on path '${resolvedPath}'`)
|
||||
}
|
||||
|
||||
return matchedMockDispatches[0]
|
||||
}
|
||||
|
||||
function addMockDispatch (mockDispatches, key, data) {
|
||||
const baseData = { timesInvoked: 0, times: 1, persist: false, consumed: false }
|
||||
function addMockDispatch (mockDispatches, key, data, opts) {
|
||||
const baseData = { timesInvoked: 0, times: 1, persist: false, consumed: false, ...opts }
|
||||
const replyData = typeof data === 'function' ? { callback: data } : { ...data }
|
||||
const newMockDispatch = { ...baseData, ...key, pending: true, data: { error: null, ...replyData } }
|
||||
mockDispatches.push(newMockDispatch)
|
||||
@ -176,8 +192,24 @@ function deleteMockDispatch (mockDispatches, key) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path Path to remove trailing slash from
|
||||
*/
|
||||
function removeTrailingSlash (path) {
|
||||
while (path.endsWith('/')) {
|
||||
path = path.slice(0, -1)
|
||||
}
|
||||
|
||||
if (path.length === 0) {
|
||||
path = '/'
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
function buildKey (opts) {
|
||||
const { path, method, body, headers, query } = opts
|
||||
|
||||
return {
|
||||
path,
|
||||
method,
|
||||
@ -188,11 +220,21 @@ function buildKey (opts) {
|
||||
}
|
||||
|
||||
function generateKeyValues (data) {
|
||||
return Object.entries(data).reduce((keyValuePairs, [key, value]) => [
|
||||
...keyValuePairs,
|
||||
Buffer.from(`${key}`),
|
||||
Array.isArray(value) ? value.map(x => Buffer.from(`${x}`)) : Buffer.from(`${value}`)
|
||||
], [])
|
||||
const keys = Object.keys(data)
|
||||
const result = []
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i]
|
||||
const value = data[key]
|
||||
const name = Buffer.from(`${key}`)
|
||||
if (Array.isArray(value)) {
|
||||
for (let j = 0; j < value.length; ++j) {
|
||||
result.push(name, Buffer.from(`${value[j]}`))
|
||||
}
|
||||
} else {
|
||||
result.push(name, Buffer.from(`${value}`))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,10 +316,10 @@ function mockDispatch (opts, handler) {
|
||||
const responseHeaders = generateKeyValues(headers)
|
||||
const responseTrailers = generateKeyValues(trailers)
|
||||
|
||||
handler.abort = nop
|
||||
handler.onHeaders(statusCode, responseHeaders, resume, getStatusText(statusCode))
|
||||
handler.onData(Buffer.from(responseData))
|
||||
handler.onComplete(responseTrailers)
|
||||
handler.onConnect?.(err => handler.onError(err), null)
|
||||
handler.onHeaders?.(statusCode, responseHeaders, resume, getStatusText(statusCode))
|
||||
handler.onData?.(Buffer.from(responseData))
|
||||
handler.onComplete?.(responseTrailers)
|
||||
deleteMockDispatch(mockDispatches, key)
|
||||
}
|
||||
|
||||
@ -326,9 +368,14 @@ function checkNetConnect (netConnect, origin) {
|
||||
return false
|
||||
}
|
||||
|
||||
function buildMockOptions (opts) {
|
||||
function buildAndValidateMockOptions (opts) {
|
||||
if (opts) {
|
||||
const { agent, ...mockOptions } = opts
|
||||
|
||||
if ('enableCallHistory' in mockOptions && typeof mockOptions.enableCallHistory !== 'boolean') {
|
||||
throw new InvalidArgumentError('options.enableCallHistory must to be a boolean')
|
||||
}
|
||||
|
||||
return mockOptions
|
||||
}
|
||||
}
|
||||
@ -346,6 +393,7 @@ module.exports = {
|
||||
mockDispatch,
|
||||
buildMockDispatch,
|
||||
checkNetConnect,
|
||||
buildMockOptions,
|
||||
getHeaderByName
|
||||
buildAndValidateMockOptions,
|
||||
getHeaderByName,
|
||||
buildHeadersFromArray
|
||||
}
|
||||
|
9
node_modules/undici/lib/mock/pending-interceptors-formatter.js
generated
vendored
9
node_modules/undici/lib/mock/pending-interceptors-formatter.js
generated
vendored
@ -1,7 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
const { Transform } = require('stream')
|
||||
const { Console } = require('console')
|
||||
const { Transform } = require('node:stream')
|
||||
const { Console } = require('node:console')
|
||||
|
||||
const PERSISTENT = process.versions.icu ? '✅' : 'Y '
|
||||
const NOT_PERSISTENT = process.versions.icu ? '❌' : 'N '
|
||||
|
||||
/**
|
||||
* Gets the output of `console.table(…)` as a string.
|
||||
@ -29,7 +32,7 @@ module.exports = class PendingInterceptorsFormatter {
|
||||
Origin: origin,
|
||||
Path: path,
|
||||
'Status code': statusCode,
|
||||
Persistent: persist ? '✅' : '❌',
|
||||
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
||||
Invocations: timesInvoked,
|
||||
Remaining: persist ? Infinity : times - timesInvoked
|
||||
}))
|
||||
|
29
node_modules/undici/lib/mock/pluralizer.js
generated
vendored
29
node_modules/undici/lib/mock/pluralizer.js
generated
vendored
@ -1,29 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const singulars = {
|
||||
pronoun: 'it',
|
||||
is: 'is',
|
||||
was: 'was',
|
||||
this: 'this'
|
||||
}
|
||||
|
||||
const plurals = {
|
||||
pronoun: 'they',
|
||||
is: 'are',
|
||||
was: 'were',
|
||||
this: 'these'
|
||||
}
|
||||
|
||||
module.exports = class Pluralizer {
|
||||
constructor (singular, plural) {
|
||||
this.singular = singular
|
||||
this.plural = plural
|
||||
}
|
||||
|
||||
pluralize (count) {
|
||||
const one = count === 1
|
||||
const keys = one ? singulars : plurals
|
||||
const noun = one ? this.singular : this.plural
|
||||
return { ...keys, count, noun }
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user