UNPKG

3.49 kBJavaScriptView Raw
1const Promise = require('unexpected-bluebird');
2const oathbreaker = require('./oathbreaker');
3const throwIfNonUnexpectedError = require('./throwIfNonUnexpectedError');
4
5function makePromise(body) {
6 if (typeof body !== 'function') {
7 throw new TypeError(
8 'expect.promise(...) requires a function argument to be supplied.\n' +
9 'See http://unexpected.js.org/api/promise/ for more details.'
10 );
11 }
12
13 if (body.length === 2) {
14 return new Promise(body);
15 }
16
17 return new Promise((resolve, reject) => {
18 let runningTasks = 0;
19 let resolvedValue;
20 let outerFunctionHasReturned = false;
21
22 function fulfillIfDone() {
23 if (outerFunctionHasReturned && runningTasks === 0) {
24 resolve(resolvedValue);
25 }
26 }
27
28 function noteResolvedValue(value) {
29 if (
30 typeof value !== 'undefined' &&
31 typeof resolvedValue === 'undefined'
32 ) {
33 resolvedValue = value;
34 }
35 }
36
37 const runner = fn => {
38 runningTasks += 1;
39 return (...args) => {
40 runningTasks -= 1;
41 let result;
42 try {
43 if (typeof fn === 'function') {
44 result = oathbreaker(fn(...args));
45 if (isPromise(result)) {
46 runningTasks += 1;
47 result.then(value => {
48 noteResolvedValue(value);
49 runningTasks -= 1;
50 fulfillIfDone();
51 }, reject);
52 } else {
53 noteResolvedValue(result);
54 }
55 }
56 } catch (e) {
57 return reject(e);
58 }
59 fulfillIfDone();
60 return result;
61 };
62 };
63
64 try {
65 const result = oathbreaker(body(runner));
66 if (isPromise(result)) {
67 runningTasks += 1;
68 result.then(value => {
69 noteResolvedValue(value);
70 runningTasks -= 1;
71 fulfillIfDone();
72 }, reject);
73 } else {
74 noteResolvedValue(result);
75 }
76 } catch (e) {
77 return reject(e);
78 }
79 outerFunctionHasReturned = true;
80 fulfillIfDone();
81 });
82}
83
84function isPromise(obj) {
85 return obj && typeof obj === 'object' && typeof obj.then === 'function';
86}
87
88function extractPromisesFromObject(obj) {
89 if (isPromise(obj)) {
90 return [obj];
91 } else if (obj && typeof obj === 'object') {
92 const promises = [];
93 // Object or Array
94 Object.keys(obj).forEach(key => {
95 promises.push(...extractPromisesFromObject(obj[key]));
96 });
97 return promises;
98 }
99 return [];
100}
101
102['all', 'any', 'settle'].forEach(staticMethodName => {
103 makePromise[staticMethodName] = obj => {
104 const result = Promise[staticMethodName](extractPromisesFromObject(obj));
105 if (staticMethodName === 'settle') {
106 return result.then(promises => {
107 promises.forEach(promise => {
108 if (promise.isRejected()) {
109 throwIfNonUnexpectedError(promise.reason());
110 }
111 });
112 return promises;
113 });
114 }
115 return result;
116 };
117});
118
119// Expose all of Bluebird's static methods, except the ones related to long stack traces,
120// unhandled rejections and the scheduler, which we need to manage ourselves:
121Object.keys(Promise).forEach(staticMethodName => {
122 if (
123 !/^_|^on|^setScheduler|ongStackTraces/.test(staticMethodName) &&
124 typeof Promise[staticMethodName] === 'function' &&
125 typeof makePromise[staticMethodName] === 'undefined'
126 ) {
127 makePromise[staticMethodName] = Promise[staticMethodName];
128 }
129});
130
131module.exports = makePromise;