UNPKG

4.5 kBPlain TextView Raw
1import { each, isUndefined, isFunction, some, first } from 'lodash';
2import { Observable, Subject } from 'rxjs';
3import { SinonSpy } from 'sinon';
4import { flushMicrotasks, rlQueueRequest } from './fakeAsync';
5import { IMockedPromise, mockPromise } from './mockPromise';
6
7export { IMockedPromise } from './mockPromise';
8
9export interface IMockAsyncService {
10 request<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedRequest<TData>;
11 rejectedRequest<TData>(...params: any[]): IMockedRequest<TData>;
12 promise<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedPromise<TData>;
13 rejectedPromise<TData>(...params: any[]): IMockedPromise<TData>;
14 flushAll(service: any): void;
15}
16
17export interface IMockedRequest<TData> extends SinonSpy {
18 (...args: any[]): Observable<TData>;
19 reject(error: any): void;
20 rejected: boolean;
21 flush(): void;
22 share(share?: boolean): void;
23}
24
25interface IMockedObservableInternal<TData> extends IMockedRequest<TData> {
26 rejectParam: any;
27}
28
29class MockAsyncService implements IMockAsyncService {
30 promise<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedPromise<TData> {
31 return mockPromise.promise(result, share);
32 }
33
34 rejectedPromise<TData>(...params: any[]): IMockedPromise<TData> {
35 return mockPromise.rejectedPromise(...params);
36 }
37
38 request<TData>(result?: TData | { (...args: any[]): TData }, share?: boolean): IMockedRequest<TData> {
39 if (isUndefined(share)) {
40 share = false;
41 }
42
43 if (isFunction(result)) {
44 return this.makeDynamicMockRequest(<{ (...args: any[]): TData }>result, share);
45 } else {
46 return this.makeMockRequest(<TData>result, share);
47 }
48 }
49
50 rejectedRequest<TData>(error: any): IMockedRequest<TData> {
51 let mocked: IMockedObservableInternal<TData> = this.makeMockRequest(null, false);
52 mocked.rejected = true;
53 mocked.rejectParam = error;
54 return mocked;
55 }
56
57 flushAll(service: any): void {
58 each(service, (request: IMockedRequest<any>): void => {
59 if (request && isFunction(request.flush)) {
60 request.flush();
61 }
62 })
63 }
64
65 private makeMockRequest<TData>(result: TData, share: boolean): IMockedObservableInternal<TData> {
66 return this.makeDynamicMockRequest(() => result, share);
67 }
68
69 private makeDynamicMockRequest<TData>(result: { (...args: any[]): TData }, shareParam: boolean): IMockedObservableInternal<TData> {
70 let share: boolean = shareParam;
71 interface IRequestType {
72 resolve: Function;
73 reject: Function;
74 params: any[];
75 stream: Subject<TData>;
76 observable: Observable<TData>;
77 rejected: boolean;
78 rejectParam: any;
79 pending: boolean;
80 };
81
82 let requests: IRequestType[] = [];
83 let mocked: IMockedObservableInternal<TData>;
84
85 // Return a function that will build a pending promise when called
86 const requestBuilder: any = ((...args: any[]): Observable<TData> => {
87 if (share && some(requests) && first(requests).pending) {
88 return first(requests).observable;
89 }
90
91 const newRequest: IRequestType = {
92 resolve: null,
93 reject: null,
94 params: args,
95 stream: null,
96 observable: null,
97 rejected: mocked.rejected,
98 rejectParam: mocked.rejectParam,
99 pending: true,
100 };
101
102 newRequest.stream = new Subject<TData>();
103 newRequest.observable = newRequest.stream.asObservable();
104
105 requests.push(newRequest);
106
107 rlQueueRequest(newRequest);
108
109 return newRequest.observable;
110 });
111
112 const spiedBuilder: any = sinon.spy(requestBuilder);
113 mocked = <IMockedObservableInternal<TData>> spiedBuilder;
114
115 // Mark promise to be rejected
116 mocked.reject = (error: any) => {
117 mocked.rejected = true;
118 mocked.rejectParam = error;
119 };
120
121 // Mark promise to be shared in builder
122 mocked.share = (shareParam?: boolean) => {
123 if (isUndefined(shareParam)) {
124 share = true;
125 }
126
127 share = shareParam;
128 };
129
130 // If current request, resolve and clear
131 mocked.flush = (): void => {
132 each(requests, (request: IRequestType): void => {
133 if (!request.pending) {
134 return;
135 }
136
137 request.pending = false;
138 if (request.rejected) {
139 request.stream.error(request.rejectParam);
140 } else {
141 request.stream.next(result(...request.params));
142 request.stream.complete();
143 }
144 });
145 requests = [];
146 flushMicrotasks();
147 };
148
149 return mocked;
150 }
151}
152
153export const mock: IMockAsyncService = new MockAsyncService();