Skip to content

Commit

Permalink
mock: improve mock interceptor (#3062)
Browse files Browse the repository at this point in the history
  • Loading branch information
Uzlopak committed Apr 7, 2024
1 parent d399b3d commit ad3fac5
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 20 deletions.
35 changes: 18 additions & 17 deletions lib/mock/mock-interceptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class MockInterceptor {
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 }
Expand All @@ -99,43 +99,40 @@ 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' || responseOptions === null) {
if (typeof replyParameters.responseOptions !== 'object' || replyParameters.responseOptions === null) {
throw new InvalidArgumentError('responseOptions must be an object')
}
}

/**
* 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)
}
}

Expand All @@ -148,11 +145,15 @@ 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 dispatchData = this.createMockScopeDispatchData(replyParameters)
const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], dispatchData)
return new MockScope(newMockDispatch)
}
Expand Down
20 changes: 17 additions & 3 deletions test/mock-interceptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ describe('MockInterceptor - reply options callback', () => {
})

test('should error if passed options invalid', async (t) => {
t = tspl(t, { plan: 3 })
t = tspl(t, { plan: 4 })

const baseUrl = 'http://localhost:9999'
const mockAgent = new MockAgent()
Expand All @@ -116,10 +116,15 @@ describe('MockInterceptor - reply options callback', () => {
const mockPool = mockAgent.get(baseUrl)

mockPool.intercept({
path: '/test',
path: '/test-return-undefined',
method: 'GET'
}).reply(() => { })

mockPool.intercept({
path: '/test-return-null',
method: 'GET'
}).reply(() => { return null })

mockPool.intercept({
path: '/test3',
method: 'GET'
Expand All @@ -138,7 +143,16 @@ describe('MockInterceptor - reply options callback', () => {
}))

t.throws(() => mockPool.dispatch({
path: '/test',
path: '/test-return-undefined',
method: 'GET'
}, {
onHeaders: () => { },
onData: () => { },
onComplete: () => { }
}), new InvalidArgumentError('reply options callback must return an object'))

t.throws(() => mockPool.dispatch({
path: '/test-return-null',
method: 'GET'
}, {
onHeaders: () => { },
Expand Down

0 comments on commit ad3fac5

Please sign in to comment.