@fruitsjs/http
Version:
FruitsJS Generic Http Module
215 lines (180 loc) • 7.53 kB
text/typescript
import {Http} from './http';
import {HttpResponse} from './httpResponse';
import {HttpError} from './httpError';
class HttpMock implements Http {
public static ForAll = '__all';
constructor() {
this.reset();
}
_replyFunctions: object = HttpMock.initialReplyFunctions();
private static initialReplyFunctions(): object {
return {
get: {},
post: {},
put: {},
delete: {}
};
}
private createReplyFn(status: number, data: any): () => Promise<HttpResponse> {
return () => Promise.resolve(new HttpResponse(status, data));
}
private createErrorFn(requestUrl: string, status: number, message: string, data: any = null): () => {} {
return () => {
throw new HttpError(requestUrl, status, message, data);
};
}
public reset(): void {
this._replyFunctions = HttpMock.initialReplyFunctions();
}
public registerResponse(method: string, url: string, status: number, data: any) : void {
// @ts-ignore
this._replyFunctions[method][url] = this.createReplyFn(status, data);
}
public registerError(method: string, url: string, status: number, message: string, data: any) : void {
// @ts-ignore
this._replyFunctions[method][url] = this.createErrorFn(url, status, message, data);
}
public get(url: string): Promise<HttpResponse> {
return this.request('get', url);
}
public delete(url: string): Promise<HttpResponse> {
return this.request('delete', url);
}
public post(url: string, payload: any): Promise<HttpResponse> {
return this.request('post', url); // ignore payload...
}
public put(url: string, payload: any): Promise<HttpResponse> {
return this.request('put', url); // ignore payload...
}
private request(method: string, url: string): Promise<HttpResponse> {
// @ts-ignore
const replyFn = this._replyFunctions[method][url] || this._replyFunctions[method][HttpMock.ForAll];
if (!replyFn) {
throw new Error(`Could not find any mocked function for method ${method.toUpperCase()} url ${url}`);
}
return replyFn();
}
}
/**
* Http Mocker Builder for easy to http testing
*
* Example:
* ```
const mockedHttp = HttpMockBuilder
.create()
.onGetReply(200, {foo: 'get'})
.onPostThrowError(500, 'Post Error', {e: 'post'})
.onPutThrowError(404, 'Put Error', {e: 'put'})
.onDeleteThrowError(403, 'Delete Error', {e: 'delete'})
.build();
const response = await mockedHttp.get('/url');
await mockedHttp.post('/url/post', {faz: 'post'}); // will throw exception
* ```
*
* @module http
*/
export class HttpMockBuilder {
private readonly _httpMock: HttpMock;
private constructor() {
this._httpMock = new HttpMock();
}
/**
* Creates a builder instance
* @return {HttpMockBuilder} the builder
*/
public static create(): HttpMockBuilder {
return new HttpMockBuilder();
}
private onReply(method: string, status: number, data: any, url: string = HttpMock.ForAll): HttpMockBuilder {
this._httpMock.registerResponse(method, url, status, data);
return this;
}
private onThrowError(method: string, status: number, errorMessage: string, data: any, url: string = HttpMock.ForAll): HttpMockBuilder {
this._httpMock.registerError(method, url, status, errorMessage, data);
return this;
}
/**
* Mocks responses for get methods
* You may pass a specific endpoint as parameter to mock only selected endpoints.
* This is very useful, when having methods that do several Http requests,
* so you can mock them one on one.
*
* The following code returns the same content on _every_ get call
* ```
* HttpMockBuilder
* .create()
* .onGetReply(200, {response: 'foo}) // mocks all get requests
* .onPostReply(201, {response: 'foo}) // mocks all post requests
* .build()
* ```
*
* The next code returns the different content depending on the passed endpoint
* ```
* HttpMockBuilder
* .create()
* .onGetReply(200, {response: 'foo}, '/url/specific') // mocks get request for '/url/specific'
* .build()
* ```
* @param status {number} The status to be returned
* @param data The data to be returned
* @param url {string?} If given, the mock applies for that specific url, other for all method calls
* @return {HttpMockBuilder} The builder instance (Fluent API)
*/
public onGetReply(status: number, data: any, url?: string): HttpMockBuilder {
return this.onReply('get', status, data, url);
}
/**
* Mocks response exceptions for get methods. It works like onGetReply(), but throws an HttpError instead
* @param status {number} The status to be returned in exception object
* @param errorMessage {string} The error message
* @param data {any?} Eventual data carried with the error object
* @param url {string?} The specific url for which the exception should be thrown
* @return {HttpMockBuilder} The builder instance (Fluent API)
*/
public onGetThrowError(status: number, errorMessage: string, data: any = null, url: string = HttpMock.ForAll): HttpMockBuilder {
return this.onThrowError('get', status, errorMessage, data, url);
}
/**
* Mocks post requests. Works analog to onGetReply().
*/
public onPostReply(status: number, data: any, url?: string): HttpMockBuilder {
return this.onReply('post', status, data, url);
}
/**
* Mocks response exceptions for post methods. It works like onPostReply(), but throws an HttpError instead
*/
public onPostThrowError(status: number, errorMessage: string, data: any, url: string = HttpMock.ForAll): HttpMockBuilder {
return this.onThrowError('post', status, errorMessage, data, url);
}
/**
* Mocks put requests. Works analog to onGetReply().
*/
public onPutReply(status: number, data: any, url?: string): HttpMockBuilder {
return this.onReply('put', status, data, url);
}
/**
* Mocks response exceptions for put methods. It works like onPutReply(), but throws an HttpError instead
*/
public onPutThrowError(status: number, errorMessage: string, data: any, url: string = HttpMock.ForAll): HttpMockBuilder {
return this.onThrowError('put', status, errorMessage, data, url);
}
/**
* Mocks delete requests. Works analog to onGetReply().
*/
public onDeleteReply(status: number, data: any, url?: string): HttpMockBuilder {
return this.onReply('delete', status, data, url);
}
/**
* Mocks response exceptions for delete methods. It works like onDeleteReply(), but throws an HttpError instead
*/
public onDeleteThrowError(status: number, errorMessage: string, data: any, url: string = HttpMock.ForAll): HttpMockBuilder {
return this.onThrowError('delete', status, errorMessage, data, url);
}
/**
* Builds the Http mock.
* @return {Http} The mocked Http implementation
*/
public build(): Http {
return this._httpMock;
}
}