UNPKG

mappersmith

Version:

It is a lightweight rest client for node.js and the browser

236 lines (206 loc) 5.72 kB
import { configs } from '../mappersmith' import MockRequest from './mock-request' import Request from '../request' const VALUE_NOT_MATCHED = '<MAPPERSMITH_VALUE_NOT_MATCHED>' /** * @param {Integer} id * @param {Object} client - the client generated by {@link forge} */ function MockResource(id, client) { if (!client || !client._manifest) { throw new Error('[Mappersmith Test] "mockClient" received an invalid client') } this.id = id this.manifest = client._manifest this.resourceName = null this.methodName = null this.requestParams = {} this.responseData = null this.responseHandler = null this.responseHeaders = {} this.responseStatus = 200 this.responseStatusHandler = null this.mockRequest = null this.asyncFinalRequest = null this.pendingMiddlewareExecution = true } MockResource.prototype = { /** * @return {MockResource} */ resource(resourceName) { this.resourceName = resourceName return this }, /** * @return {MockResource} */ method(methodName) { this.methodName = methodName return this }, /** * @return {MockResource} */ with(requestParams) { this.requestParams = requestParams return this }, /** * @return {MockResource} */ headers(responseHeaders) { this.responseHeaders = responseHeaders return this }, /** * @return {MockResource} */ status(responder) { if (typeof responder === 'function') { this.responseStatusHandler = responder } else { this.responseStatus = responder } return this }, /** * @return {MockResource} */ response(responder) { if (typeof responder === 'function') { this.responseHandler = responder } else { this.responseData = responder } return this }, /** * @return {Promise<MockAssert>} */ assertObjectAsync() { return this.createAsyncRequest().then((finalRequest) => { this.asyncFinalRequest = finalRequest this.pendingMiddlewareExecution = false return this.toMockRequest().assertObject() }) }, /** * @return {MockAssert} */ assertObject() { // The middleware "prepareRequest" phase is always async, so the middleware // stack will never run when assertObject is used return this.toMockRequest().assertObject() }, /** * @return {MockRequest} */ toMockRequest() { const finalRequest = this.asyncFinalRequest ? this.asyncFinalRequest : this.createRequest() const responseStatus = this.responseStatusHandler || this.responseStatus if (!this.mockRequest) { this.mockRequest = new MockRequest(this.id, { method: finalRequest.method(), url: this.generateUrlMatcher(finalRequest), body: finalRequest.body(), headers: finalRequest.headers(), response: { status: responseStatus, headers: this.responseHeaders, body: this.responseData, handler: this.responseHandler, }, }) } return this.mockRequest }, /** * @private */ generateUrlMatcher(finalRequest) { const params = finalRequest.params() const hasParamMatchers = Object.keys(params).find((key) => typeof params[key] === 'function') if (!hasParamMatchers) { return finalRequest.url() } const urlMatcher = (requestUrl, requestParams) => { const additionalParams = this.evaluateParamMatchers(params, requestParams) const testRequest = finalRequest.enhance({ params: additionalParams }) return testRequest.url() === requestUrl } return urlMatcher }, /** * @private */ executeMiddlewareStack() { return this.createAsyncRequest().then((finalRequest) => { this.asyncFinalRequest = finalRequest if (this.mockRequest) { const urlMatcher = this.generateUrlMatcher(finalRequest) this.mockRequest.url = urlMatcher this.mockRequest.body = finalRequest.body() this.pendingMiddlewareExecution = false } }) }, /** * @private */ evaluateParamMatchers(mockParams, requestParams) { return Object.keys(mockParams).reduce((obj, key) => { const matcher = mockParams[key] if (typeof matcher !== 'function') { return obj } const value = requestParams[key] // Only evaluate if key was provided in request params. // Otherwise we always consider it not to match. if (key in requestParams && matcher(value)) { obj[key] = value } else { obj[key] = VALUE_NOT_MATCHED } return obj }, {}) }, /** * @private * It never runs the middleware stack */ createRequest() { const methodDescriptor = this.manifest.createMethodDescriptor( this.resourceName, this.methodName ) return new Request(methodDescriptor, this.requestParams) }, /** * @private * Always runs the middleware stack */ createAsyncRequest() { const methodDescriptor = this.manifest.createMethodDescriptor( this.resourceName, this.methodName ) const initialRequest = new Request(methodDescriptor, this.requestParams) const middleware = this.manifest.createMiddleware({ resourceName: this.resourceName, resourceMethod: this.methodName, mockRequest: true, }) const abort = (error) => { throw error } const getInitialRequest = () => configs.Promise.resolve(initialRequest) const prepareRequest = middleware.reduce( (next, middleware) => () => configs.Promise.resolve().then(() => middleware.prepareRequest(next, abort)), getInitialRequest ) return prepareRequest() }, } export default MockResource