1 | var Promise = require('unexpected-bluebird');
|
2 | var oathbreaker = require('./oathbreaker');
|
3 | var throwIfNonUnexpectedError = require('./throwIfNonUnexpectedError');
|
4 |
|
5 | function 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(function (resolve, reject) {
|
18 | var runningTasks = 0;
|
19 | var resolvedValue;
|
20 | var 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 | var runner = function (fn) {
|
38 | runningTasks += 1;
|
39 | return function () {
|
40 | var args = [], len = arguments.length;
|
41 | while ( len-- ) args[ len ] = arguments[ len ];
|
42 |
|
43 | runningTasks -= 1;
|
44 | var result;
|
45 | try {
|
46 | if (typeof fn === 'function') {
|
47 | result = oathbreaker(fn.apply(void 0, args));
|
48 | if (isPromise(result)) {
|
49 | runningTasks += 1;
|
50 | result.then(function (value) {
|
51 | noteResolvedValue(value);
|
52 | runningTasks -= 1;
|
53 | fulfillIfDone();
|
54 | }, reject);
|
55 | } else {
|
56 | noteResolvedValue(result);
|
57 | }
|
58 | }
|
59 | } catch (e) {
|
60 | return reject(e);
|
61 | }
|
62 | fulfillIfDone();
|
63 | return result;
|
64 | };
|
65 | };
|
66 |
|
67 | try {
|
68 | var result = oathbreaker(body(runner));
|
69 | if (isPromise(result)) {
|
70 | runningTasks += 1;
|
71 | result.then(function (value) {
|
72 | noteResolvedValue(value);
|
73 | runningTasks -= 1;
|
74 | fulfillIfDone();
|
75 | }, reject);
|
76 | } else {
|
77 | noteResolvedValue(result);
|
78 | }
|
79 | } catch (e) {
|
80 | return reject(e);
|
81 | }
|
82 | outerFunctionHasReturned = true;
|
83 | fulfillIfDone();
|
84 | });
|
85 | }
|
86 |
|
87 | function isPromise(obj) {
|
88 | return obj && typeof obj === 'object' && typeof obj.then === 'function';
|
89 | }
|
90 |
|
91 | function extractPromisesFromObject(obj) {
|
92 | if (isPromise(obj)) {
|
93 | return [obj];
|
94 | } else if (obj && typeof obj === 'object') {
|
95 | var promises = [];
|
96 |
|
97 | Object.keys(obj).forEach(function (key) {
|
98 | promises.push.apply(promises, extractPromisesFromObject(obj[key]));
|
99 | });
|
100 | return promises;
|
101 | }
|
102 | return [];
|
103 | }
|
104 |
|
105 | ['all', 'any', 'settle'].forEach(function (staticMethodName) {
|
106 | makePromise[staticMethodName] = function (obj) {
|
107 | var result = Promise[staticMethodName](extractPromisesFromObject(obj));
|
108 | if (staticMethodName === 'settle') {
|
109 | return result.then(function (promises) {
|
110 | promises.forEach(function (promise) {
|
111 | if (promise.isRejected()) {
|
112 | throwIfNonUnexpectedError(promise.reason());
|
113 | }
|
114 | });
|
115 | return promises;
|
116 | });
|
117 | }
|
118 | return result;
|
119 | };
|
120 | });
|
121 |
|
122 |
|
123 |
|
124 | Object.keys(Promise).forEach(function (staticMethodName) {
|
125 | if (
|
126 | !/^_|^on|^setScheduler|ongStackTraces/.test(staticMethodName) &&
|
127 | typeof Promise[staticMethodName] === 'function' &&
|
128 | typeof makePromise[staticMethodName] === 'undefined'
|
129 | ) {
|
130 | makePromise[staticMethodName] = Promise[staticMethodName];
|
131 | }
|
132 | });
|
133 |
|
134 | module.exports = makePromise;
|