UNPKG

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