forked from sinonjs/sinon
/
promise.js
84 lines (74 loc) · 2.5 KB
/
promise.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
"use strict";
var fake = require("./fake");
var isRestorable = require("./util/core/is-restorable");
var STATUS_PENDING = "pending";
var STATUS_RESOLVED = "resolved";
var STATUS_REJECTED = "rejected";
/**
* Returns a fake for a given function or undefined. If no function is given, a
* new fake is returned. If the given function is already a fake, it is
* returned as is. Otherwise the given function is wrapped in a new fake.
*
* @param {Function} [executor] The optional executor function.
* @returns {Function}
*/
function getFakeExecutor(executor) {
if (isRestorable(executor)) {
return executor;
}
if (executor) {
return fake(executor);
}
return fake();
}
/**
* Returns a new promise that exposes it's internal `status`, `resolvedValue`
* and `rejectedValue` and can be resolved or rejected from the outside by
* calling `resolve(value)` or `reject(reason)`.
*
* @param {Function} [executor] The optional executor function.
* @returns {Promise}
*/
function promise(executor) {
var fakeExecutor = getFakeExecutor(executor);
var sinonPromise = new Promise(fakeExecutor);
sinonPromise.status = STATUS_PENDING;
sinonPromise
.then(function (value) {
sinonPromise.status = STATUS_RESOLVED;
sinonPromise.resolvedValue = value;
})
.catch(function (reason) {
sinonPromise.status = STATUS_REJECTED;
sinonPromise.rejectedValue = reason;
});
/**
* Resolves or rejects the promise with the given status and value.
*
* @param {string} status
* @param {*} value
* @param {Function} callback
*/
function finalize(status, value, callback) {
if (sinonPromise.status !== STATUS_PENDING) {
throw new Error(`Promise already ${sinonPromise.status}`);
}
sinonPromise.status = status;
callback(value);
}
sinonPromise.resolve = function (value) {
finalize(STATUS_RESOLVED, value, fakeExecutor.firstCall.args[0]);
// Return the promise so that callers can await it:
return sinonPromise;
};
sinonPromise.reject = function (reason) {
finalize(STATUS_REJECTED, reason, fakeExecutor.firstCall.args[1]);
// Return a new promise that resolves when the sinon promise was
// rejected, so that callers can await it:
return new Promise(function (resolve) {
sinonPromise.catch(() => resolve());
});
};
return sinonPromise;
}
module.exports = promise;