UNPKG

ngrx-model

Version:

Model classes for integrating ngrx store with a REST API

153 lines (125 loc) 4.47 kB
import { each, isUndefined, isFunction, some, first } from 'lodash'; import { Observable, Subject } from 'rxjs'; import { flushMicrotasks, rlQueueRequest } from './fakeAsync'; import { IMockedPromise, mockPromise } from './mockPromise'; export { IMockedPromise } from './mockPromise'; export interface IMockAsyncService { request<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedRequest<TData>; rejectedRequest<TData>(...params: any[]): IMockedRequest<TData>; promise<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedPromise<TData>; rejectedPromise<TData>(...params: any[]): IMockedPromise<TData>; flushAll(service: any): void; } export interface IMockedRequest<TData> extends Sinon.SinonSpy { (...args: any[]): Observable<TData>; reject(error: any): void; rejected: boolean; flush(): void; share(share?: boolean): void; } interface IMockedObservableInternal<TData> extends IMockedRequest<TData> { rejectParam: any; } class MockAsyncService implements IMockAsyncService { promise<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedPromise<TData> { return mockPromise.promise(result, share); } rejectedPromise<TData>(...params: any[]): IMockedPromise<TData> { return mockPromise.rejectedPromise(...params); } request<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedRequest<TData> { if (isUndefined(share)) { share = false; } if (isFunction(result)) { return this.makeDynamicMockRequest(<{ (...args: any[]): TData }>result, share); } else { return this.makeMockRequest(<TData>result, share); } } rejectedRequest<TData>(error: any): IMockedRequest<TData> { let mocked: IMockedObservableInternal<TData> = this.makeMockRequest(null, false); mocked.rejected = true; mocked.rejectParam = error; return mocked; } flushAll(service: any): void { each(service, (request: IMockedRequest<any>): void => { if (request && isFunction(request.flush)) { request.flush(); } }) } private makeMockRequest<TData>(result: TData, share: boolean): IMockedObservableInternal<TData> { return this.makeDynamicMockRequest(() => result, share); } private makeDynamicMockRequest<TData>(result: { (...args: any[]): TData }, shareParam: boolean): IMockedObservableInternal<TData> { let share: boolean = shareParam; interface IRequestType { resolve: Function; reject: Function; params: any[]; stream: Subject<TData>; observable: Observable<TData>; rejected: boolean; rejectParam: any; pending: boolean; }; let requests: IRequestType[] = []; let mocked: IMockedObservableInternal<TData>; // Return a function that will build a pending promise when called const requestBuilder: any = ((...args: any[]): Observable<TData> => { if (share && some(requests) && first(requests).pending) { return first(requests).observable; } const newRequest: IRequestType = { resolve: null, reject: null, params: args, stream: null, observable: null, rejected: mocked.rejected, rejectParam: mocked.rejectParam, pending: true, }; newRequest.stream = new Subject<TData>(); newRequest.observable = newRequest.stream.asObservable(); requests.push(newRequest); rlQueueRequest(newRequest); return newRequest.observable; }); const spiedBuilder: any = sinon.spy(requestBuilder); mocked = <IMockedObservableInternal<TData>> spiedBuilder; // Mark promise to be rejected mocked.reject = (error: any) => { mocked.rejected = true; mocked.rejectParam = error; }; // Mark promise to be shared in builder mocked.share = (shareParam?: boolean) => { if (isUndefined(shareParam)) { share = true; } share = shareParam; }; // If current request, resolve and clear mocked.flush = (): void => { each(requests, (request: IRequestType): void => { if (!request.pending) { return; } request.pending = false; if (request.rejected) { request.stream.error(request.rejectParam); } else { request.stream.next(result(...request.params)); request.stream.complete(); } }); requests = []; flushMicrotasks(); }; return mocked; } } export const mock: IMockAsyncService = new MockAsyncService();