ES6Promise.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // ES6 Promise tests -- verifies the API shape and basic functionality
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. var tests = [
  8. {
  9. name: "Promise constructor has correct shape",
  10. body: function () {
  11. assert.isTrue(Promise !== undefined, "Promise named global exists");
  12. assert.areEqual('function', typeof Promise, "Type of Promise global is 'function'");
  13. assert.areEqual("[object Promise]", Object.prototype.toString.call(new Promise(() => {})),
  14. "toString of Promise is '[object Promise]'");
  15. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'prototype');
  16. assert.isFalse(descriptor.writable, "Promise.length.writable === false");
  17. assert.isFalse(descriptor.enumerable, "Promise.length.enumerable === false");
  18. assert.isFalse(descriptor.configurable, "Promise.length.configurable === false");
  19. assert.areEqual('object', typeof descriptor.value, "typeof Promise.length === 'object'");
  20. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'length');
  21. assert.isFalse(descriptor.writable, "Promise.length.writable === false");
  22. assert.isFalse(descriptor.enumerable, "Promise.length.enumerable === false");
  23. assert.isFalse(descriptor.configurable, "Promise.length.configurable === false");
  24. assert.areEqual('number', typeof descriptor.value, "typeof Promise.length === 'number'");
  25. assert.areEqual(1, Promise.length, "Promise.length === 1");
  26. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'all');
  27. assert.isTrue(descriptor.writable, "Promise.all.writable === true");
  28. assert.isFalse(descriptor.enumerable, "Promise.all.enumerable === false");
  29. assert.isTrue(descriptor.configurable, "Promise.all.configurable === true");
  30. assert.areEqual('function', typeof descriptor.value, "typeof Promise.all === 'function'");
  31. assert.areEqual(1, Promise.all.length, "Promise.all.length === 1");
  32. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'race');
  33. assert.isTrue(descriptor.writable, "Promise.race.writable === true");
  34. assert.isFalse(descriptor.enumerable, "Promise.race.enumerable === false");
  35. assert.isTrue(descriptor.configurable, "Promise.race.configurable === true");
  36. assert.areEqual('function', typeof descriptor.value, "typeof Promise.race === 'function'");
  37. assert.areEqual(1, Promise.race.length, "Promise.race.length === 1");
  38. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'reject');
  39. assert.isTrue(descriptor.writable, "Promise.reject.writable === true");
  40. assert.isFalse(descriptor.enumerable, "Promise.reject.enumerable === false");
  41. assert.isTrue(descriptor.configurable, "Promise.reject.configurable === true");
  42. assert.areEqual('function', typeof descriptor.value, "typeof Promise.reject === 'function'");
  43. assert.areEqual(1, Promise.reject.length, "Promise.reject.length === 1");
  44. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'resolve');
  45. assert.isTrue(descriptor.writable, "Promise.resolve.writable === true");
  46. assert.isFalse(descriptor.enumerable, "Promise.resolve.enumerable === false");
  47. assert.isTrue(descriptor.configurable, "Promise.resolve.configurable === true");
  48. assert.areEqual('function', typeof descriptor.value, "typeof Promise.resolve === 'function'");
  49. assert.areEqual(1, Promise.resolve.length, "Promise.resolve.length === 1");
  50. }
  51. },
  52. {
  53. name: "Promise prototype has correct shape",
  54. body: function () {
  55. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, 'constructor');
  56. assert.isTrue(descriptor.writable, "Promise.prototype.constructor.writable === true");
  57. assert.isFalse(descriptor.enumerable, "Promise.prototype.constructor.enumerable === false");
  58. assert.isTrue(descriptor.configurable, "Promise.prototype.constructor.configurable === true");
  59. assert.areEqual('function', typeof descriptor.value, "typeof Promise.prototype.constructor === 'function'");
  60. assert.areEqual(1, Promise.prototype.constructor.length, "Promise.prototype.constructor.length === 1");
  61. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, 'catch');
  62. assert.isTrue(descriptor.writable, "Promise.prototype.catch.writable === true");
  63. assert.isFalse(descriptor.enumerable, "Promise.prototype.catch.enumerable === false");
  64. assert.isTrue(descriptor.configurable, "Promise.prototype.catch.configurable === true");
  65. assert.areEqual('function', typeof descriptor.value, "typeof Promise.prototype.catch === 'function'");
  66. assert.areEqual(1, Promise.prototype.catch.length, "Promise.prototype.catch.length === 1");
  67. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, 'then');
  68. assert.isTrue(descriptor.writable, "Promise.prototype.then.writable === true");
  69. assert.isFalse(descriptor.enumerable, "Promise.prototype.then.enumerable === false");
  70. assert.isTrue(descriptor.configurable, "Promise.prototype.then.configurable === true");
  71. assert.areEqual('function', typeof descriptor.value, "typeof Promise.prototype.then === 'function'");
  72. assert.areEqual(2, Promise.prototype.then.length, "Promise.prototype.then.length === 2");
  73. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, Symbol.toStringTag);
  74. assert.isFalse(descriptor.writable, "Promise.prototype[@@toStringTag].writable === false");
  75. assert.isFalse(descriptor.enumerable, "Promise.prototype[@@toStringTag].enumerable === false");
  76. assert.isTrue(descriptor.configurable, "Promise.prototype[@@toStringTag].configurable === true");
  77. assert.areEqual('string', typeof descriptor.value, "typeof Promise.prototype[@@toStringTag] === 'string'");
  78. assert.areEqual('Promise', Promise.prototype[Symbol.toStringTag], "Promise.prototype[@@toStringTag] === 'Promise'");
  79. }
  80. },
  81. {
  82. name: "Promise constructor throwing behavior",
  83. body: function () {
  84. assert.throws(function() { Promise.call(); }, TypeError, "Promise throws when not called as a new expression with no this parameter", "Promise: cannot be called without the new keyword");
  85. assert.throws(function() { Promise.call(undefined); }, TypeError, "Promise throws when not called as a new expression if the this parameter is undefined", "Promise: cannot be called without the new keyword");
  86. assert.throws(function() { Promise.call(null); }, TypeError, "Promise throws when not called as a new expression if the this parameter is null", "Promise: cannot be called without the new keyword");
  87. assert.throws(function() { Promise.call({}); }, TypeError, "Promise throws when not called as a new expression if the this parameter is not a promise", "Promise: cannot be called without the new keyword");
  88. assert.throws(function() { new Promise(); }, TypeError, "new Promise throws when called with no parameter", "Promise: argument is not a Function object");
  89. assert.throws(function() { new Promise(undefined); }, TypeError, "new Promise throws when called with an undefined parameter", "Promise: argument is not a Function object");
  90. assert.throws(function() { new Promise(null); }, TypeError, "new Promise throws when called with a null parameter", "Promise: argument is not a Function object");
  91. assert.throws(function() { new Promise({}); }, TypeError, "new Promise throws when called with a non-function parameter", "Promise: argument is not a Function object");
  92. var promise = new Promise(function() { } );
  93. assert.throws(function() { Promise.call(promise); }, TypeError, "Promise throws when not called as a new expression if the executor argument is not passed", "Promise: cannot be called without the new keyword");
  94. assert.throws(function() { Promise.call(promise, undefined); }, TypeError, "Promise throws when not called as a new expression if the executor argument is undefined", "Promise: cannot be called without the new keyword");
  95. assert.throws(function() { Promise.call(promise, null); }, TypeError, "Promise throws when not called as a new expression if the executor argument is null", "Promise: cannot be called without the new keyword");
  96. assert.throws(function() { Promise.call(promise, {}); }, TypeError, "Promise throws when not called as a new expression if the executor argument is non-callable", "Promise: cannot be called without the new keyword");
  97. assert.throws(function() { Promise.call(promise, function() { }); }, TypeError, "Promise throws when not called as a new expression if the this parameter is an initialized promise object", "Promise: cannot be called without the new keyword");
  98. }
  99. },
  100. {
  101. name: "Promise.prototype.then throwing behavior",
  102. body: function () {
  103. assert.throws(function() { Promise.prototype.then.call(); }, TypeError, "Promise.prototype.then throws when called with no this parameter", "Promise.prototype.then: 'this' is not a Promise object");
  104. assert.throws(function() { Promise.prototype.then.call(undefined); }, TypeError, "Promise.prototype.then throws when called with undefined this parameter", "Promise.prototype.then: 'this' is not a Promise object");
  105. assert.throws(function() { Promise.prototype.then.call(null); }, TypeError, "Promise.prototype.then throws when called with null this parameter", "Promise.prototype.then: 'this' is not a Promise object");
  106. assert.throws(function() { Promise.prototype.then.call({}); }, TypeError, "Promise.prototype.then throws when called with non-promise this parameter", "Promise.prototype.then: 'this' is not a Promise object");
  107. }
  108. },
  109. {
  110. name: "Promise.prototype.catch throwing behavior",
  111. body: function () {
  112. assert.throws(function() { Promise.prototype.catch.call(); }, TypeError, "Promise.prototype.catch throws when called with no this parameter", "Promise.prototype.catch: 'this' is not an Object");
  113. assert.throws(function() { Promise.prototype.catch.call(undefined); }, TypeError, "Promise.prototype.catch throws when called with undefined this parameter", "Promise.prototype.catch: 'this' is not an Object");
  114. assert.throws(function() { Promise.prototype.catch.call(null); }, TypeError, "Promise.prototype.catch throws when called with null this parameter", "Promise.prototype.catch: 'this' is not an Object");
  115. assert.throws(function() { Promise.prototype.catch.call({}); }, TypeError, "Promise.prototype.catch throws when called with a this parameter which doesn't have a then property", "Promise.prototype.catch: argument is not a Function object");
  116. assert.throws(function() { Promise.prototype.catch.call({ then: undefined }); }, TypeError, "Promise.prototype.catch throws when called with a this parameter which has a then property with undefined value", "Promise.prototype.catch: argument is not a Function object");
  117. assert.throws(function() { Promise.prototype.catch.call({ then: null }); }, TypeError, "Promise.prototype.catch throws when called with a this parameter which has a then property with null value", "Promise.prototype.catch: argument is not a Function object");
  118. assert.throws(function() { Promise.prototype.catch.call({ then: {} }); }, TypeError, "Promise.prototype.catch throws when called with a this parameter which has a then property with non-function value", "Promise.prototype.catch: argument is not a Function object");
  119. assert.throws(function() { Promise.prototype.catch.call({ get then() { throw new TypeError('error!'); } }); }, TypeError, "Promise.prototype.catch throws if the then property of the this argument throws", "error!");
  120. assert.throws(function() { Promise.prototype.catch.call({ then: function() { throw new TypeError('error!'); } }); }, TypeError, "Promise.prototype.catch throws if the then property of the this argument throws", "error!");
  121. }
  122. },
  123. {
  124. name: "Promise.resolve throwing behavior",
  125. body: function () {
  126. assert.throws(function() { Promise.resolve.call(); }, TypeError, "Promise.resolve throws when called with no this parameter", "Promise.resolve: 'this' is not an Object");
  127. assert.throws(function() { Promise.resolve.call(undefined); }, TypeError, "Promise.resolve throws when this parameter is undefined", "Promise.resolve: 'this' is not an Object");
  128. assert.throws(function() { Promise.resolve.call(null); }, TypeError, "Promise.resolve throws when this parameter is null", "Promise.resolve: 'this' is not an Object");
  129. assert.throws(function() { Promise.resolve.call({}); }, TypeError, "Promise.resolve throws when this parameter is non-callable", "Function expected");
  130. assert.throws(function() { Promise.resolve.call(Math.sin); }, TypeError, "Promise.resolve throws when this parameter is a non-constructor", "Function expected");
  131. }
  132. },
  133. {
  134. name: "Promise.reject throwing behavior",
  135. body: function () {
  136. assert.throws(function() { Promise.reject.call(); }, TypeError, "Promise.reject throws when called with no this parameter", "Promise.reject: 'this' is not an Object");
  137. assert.throws(function() { Promise.reject.call(undefined); }, TypeError, "Promise.reject throws when called when this parameter is undefined", "Promise.reject: 'this' is not an Object");
  138. assert.throws(function() { Promise.reject.call(null); }, TypeError, "Promise.reject throws when called when this parameter is null", "Promise.reject: 'this' is not an Object");
  139. assert.throws(function() { Promise.reject.call({}); }, TypeError, "Promise.reject throws when called when this parameter is non-callable", "Function expected");
  140. assert.throws(function() { Promise.reject.call(Math.sin); }, TypeError, "Promise.reject throws when this parameter is a non-constructor", "Function expected");
  141. }
  142. },
  143. {
  144. name: "Promise.race throwing behavior",
  145. body: function () {
  146. assert.throws(function() { Promise.race.call(); }, TypeError, "Promise.race throws when called with no this parameter", "Promise.race: 'this' is not an Object");
  147. assert.throws(function() { Promise.race.call(undefined); }, TypeError, "Promise.race throws when called when this parameter is undefined", "Promise.race: 'this' is not an Object");
  148. assert.throws(function() { Promise.race.call(null); }, TypeError, "Promise.race throws when called when this parameter is null", "Promise.race: 'this' is not an Object");
  149. assert.throws(function() { Promise.race.call({}); }, TypeError, "Promise.race throws when called when this parameter is non-callable", "Function expected");
  150. assert.throws(function() { Promise.race.call(Math.sin); }, TypeError, "Promise.race throws when this parameter is a non-constructor", "Function expected");
  151. }
  152. },
  153. {
  154. name: "Promise.all throwing behavior",
  155. body: function () {
  156. assert.throws(function() { Promise.all.call(); }, TypeError, "Promise.all throws when called with no this parameter", "Promise.all: 'this' is not an Object");
  157. assert.throws(function() { Promise.all.call(undefined); }, TypeError, "Promise.all throws when called when this parameter is undefined", "Promise.all: 'this' is not an Object");
  158. assert.throws(function() { Promise.all.call(null); }, TypeError, "Promise.all throws when called when this parameter is null", "Promise.all: 'this' is not an Object");
  159. assert.throws(function() { Promise.all.call({}); }, TypeError, "Promise.all throws when called when this parameter is non-callable", "Function expected");
  160. assert.throws(function() { Promise.all.call(Math.sin); }, TypeError, "Promise.all throws when this parameter is a non-constructor", "Function expected");
  161. }
  162. },
  163. {
  164. name: "Promise.prototype.then to access constructor through [@@species]",
  165. body: function () {
  166. var p = new Promise(function(resolve, reject) { });
  167. p.constructor = undefined;
  168. assert.doesNotThrow(function() { p.then(function(result) {}, function(err) {}); }, "");
  169. }
  170. },
  171. {
  172. name: "Promise.resolve checks the 'constructor' property of the argument if it's a promise",
  173. body: function () {
  174. let x = new Promise(function(resolve, reject) { });
  175. assert.isTrue(x === Promise.resolve(x), "Promise.resolve called with a promise object, x, returns that promise if 'this' === x.constructor");
  176. let xConstructor = {foo: 'my constructor'};
  177. x.constructor = xConstructor;
  178. assert.isTrue(x === Promise.resolve.call(xConstructor, x), "Promise.resolve called with a promise object, x, returns that promise if 'this' === x.constructor");
  179. assert.isFalse(x === Promise.resolve(x), "Promise.resolve called with a promise object, x, returns a new promise if 'this' !== x.constructor");
  180. }
  181. },
  182. {
  183. name: "Promise resolve / reject functions handed to the executor function",
  184. body: function () {
  185. var resolveFunction = undefined;
  186. var rejectFunction = undefined;
  187. new Promise(function(resolve, reject) {
  188. resolveFunction = resolve;
  189. rejectFunction = reject;
  190. });
  191. assert.isFalse(resolveFunction === undefined, "new Promise should provide a resolve function");
  192. assert.isFalse(rejectFunction === undefined, "new Promise should provide a reject function");
  193. assert.areEqual(1, resolveFunction.length, "Resolve function should have length 1");
  194. assert.areEqual('function', typeof resolveFunction, "Resolve function is a function type");
  195. assert.isTrue(Object.isExtensible(resolveFunction), "Resolve function is an extensible object");
  196. assert.areEqual(Object.getPrototypeOf(resolveFunction), Function.prototype, "Resolve function has __proto__ set to Function.prototype");
  197. assert.throws(() => { new resolveFunction(); }, TypeError, "Resolve function is an anonymous built-in but not a constructor", "Function is not a constructor");
  198. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveFunction, "prototype"), "Resolve function does not have 'prototype' own property");
  199. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveFunction, "name"), "Resolve function does not have 'name' own property");
  200. assert.areEqual(1, rejectFunction.length, "Reject function should have length 1");
  201. assert.areEqual('function', typeof rejectFunction, "Reject function is a function type");
  202. assert.isTrue(Object.isExtensible(rejectFunction), "Reject function is an extensible object");
  203. assert.areEqual(Object.getPrototypeOf(rejectFunction), Function.prototype, "Reject function has __proto__ set to Function.prototype");
  204. assert.throws(() => { new rejectFunction(); }, TypeError, "Reject function is an anonymous built-in but not a constructor", "Function is not a constructor");
  205. assert.isFalse(Object.prototype.hasOwnProperty.call(rejectFunction, "prototype"), "Reject function does not have 'prototype' own property");
  206. assert.isFalse(Object.prototype.hasOwnProperty.call(rejectFunction, "name"), "Reject function does not have 'name' own property");
  207. }
  208. },
  209. {
  210. name: "Promise.all resolve / reject functions",
  211. body: function () {
  212. let isCalled = false;
  213. let p = new Promise(function(resolve, reject) { resolve(); });
  214. p.then = function(resolve, reject) {
  215. assert.areEqual(1, resolve.length, "Resolve function should have length 1");
  216. assert.areEqual('function', typeof resolve, "Resolve function is a function type");
  217. assert.areEqual(1, reject.length, "Reject function should have length 1");
  218. assert.areEqual('function', typeof reject, "Reject function is a function type");
  219. isCalled = true;
  220. };
  221. Promise.all([p]);
  222. assert.isTrue(isCalled, "The then function was actually called");
  223. }
  224. },
  225. {
  226. name: "Executor function passed to Promise constructor via NewPromiseCapability",
  227. body: function () {
  228. let isCalled = false;
  229. let p = new Promise(function(resolve, reject) { resolve(); });
  230. let test_ctor = function(executor) {
  231. assert.isTrue(this instanceof test_ctor, "The 'this' argument is an instance of the ctor function");
  232. assert.areEqual(2, executor.length, "Executor function should have length 2");
  233. assert.areEqual('function', typeof executor, "Executor function is a function type");
  234. isCalled = true;
  235. executor(function(){}, function(){});
  236. }
  237. Promise.resolve.call(test_ctor, p);
  238. assert.isTrue(isCalled, "The constructor function was actually called");
  239. }
  240. },
  241. {
  242. name: "Promise.all calls thenable.then with correct resolve / reject handlers",
  243. body: function () {
  244. var resolveElementFunction = undefined;
  245. var rejectElementFunction = undefined;
  246. var thenable = {
  247. then: function(fulfill, reject) {
  248. resolveElementFunction = fulfill;
  249. rejectElementFunction = reject;
  250. }
  251. };
  252. function myResolveFunction() {
  253. throw 'should not call this function';
  254. }
  255. function myRejectFunction() {
  256. throw 'should not call this function';
  257. }
  258. function NotPromise(executor) {
  259. executor(myResolveFunction, myRejectFunction);
  260. }
  261. NotPromise.resolve = function(v) { return v; };
  262. Promise.all.call(NotPromise, [thenable]);
  263. assert.isFalse(resolveElementFunction === undefined, "Promise.all should have called thenable.then with a resolve callback");
  264. assert.isFalse(rejectElementFunction === undefined, "Promise.all should have called thenable.then with a reject callback");
  265. assert.isFalse(myResolveFunction === resolveElementFunction, "Resolve function should not be the one we passed to the promise executor");
  266. assert.areEqual(myRejectFunction, rejectElementFunction, "Promise.all should call thenable.then with a PromiseAllResolve function and the reject handler we initialized the promise with");
  267. assert.areEqual(1, resolveElementFunction.length, "Resolve function should have length 1");
  268. assert.areEqual('function', typeof resolveElementFunction, "Resolve function is a function type");
  269. assert.isTrue(Object.isExtensible(resolveElementFunction), "Resolve function is an extensible object");
  270. assert.areEqual(Object.getPrototypeOf(resolveElementFunction), Function.prototype, "Resolve function has __proto__ set to Function.prototype");
  271. assert.throws(() => { new resolveElementFunction(); }, TypeError, "Resolve function is an anonymous built-in but not a constructor", "Function is not a constructor");
  272. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveElementFunction, "prototype"), "Resolve function does not have 'prototype' own property");
  273. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveElementFunction, "name"), "Resolve function does not have 'name' own property");
  274. }
  275. },
  276. {
  277. name: "Shape of executor function passed to Promise constructor",
  278. body: function () {
  279. var executorFunction = undefined;
  280. function NotPromise2(executor) {
  281. executorFunction = executor;
  282. executor(() => {}, () => {});
  283. }
  284. Promise.resolve.call(NotPromise2);
  285. assert.isFalse(executorFunction === undefined, "Promise.resolve should have tried to new NotPromise2");
  286. assert.areEqual(2, executorFunction.length, "Executor function should have length 1");
  287. assert.areEqual('function', typeof executorFunction, "Executor function is a function type");
  288. assert.isTrue(Object.isExtensible(executorFunction), "Executor function is an extensible object");
  289. assert.areEqual(Object.getPrototypeOf(executorFunction), Function.prototype, "Executor function has __proto__ set to Function.prototype");
  290. assert.throws(() => { new executorFunction(); }, TypeError, "Executor function is an anonymous built-in but not a constructor", "Function is not a constructor");
  291. assert.isFalse(Object.prototype.hasOwnProperty.call(executorFunction, "prototype"), "Executor function does not have 'prototype' own property");
  292. assert.isFalse(Object.prototype.hasOwnProperty.call(executorFunction, "name"), "Executor function does not have 'name' own property");
  293. }
  294. },
  295. {
  296. name: "Test calling capabilities executor function with different arguments",
  297. body: function () {
  298. assert.throws(() => {
  299. Promise.resolve.call(function(executor) {
  300. });
  301. }, TypeError, "We didn't set the resolve callback, Promise.resolve tried to call it which should throw", "'Promise' is not a function");
  302. assert.throws(() => {
  303. Promise.resolve.call(function(executor) {
  304. assert.doesNotThrow(() => { executor(); }, "Calling executor with no arguments will set the promise capability resolve and reject callbacks to undefined");
  305. assert.doesNotThrow(() => { executor(); }, "Calling executor with no arguments again works because the promise capability resolve and reject callbacks are still undefined");
  306. });
  307. }, TypeError, "We set the resolve callback to undefined, Promise.resolve tried to call it which should throw", "'Promise' is not a function");
  308. assert.throws(() => {
  309. Promise.resolve.call(function(executor) {
  310. assert.doesNotThrow(() => { executor('string', 12345); }, "Calling executor with non-function arguments will set the promise capability resolve and reject callbacks");
  311. assert.throws(() => { executor(); }, TypeError, "Callbacks of promise capability are already set. Calling executor again throws", "Promise: an unexpected failure occurred while trying to obtain metadata information");
  312. });
  313. }, TypeError, "We set the resolve and reject callbacks to non-functions, Promise.resolve tried to call resolve which should throw", "'Promise' is not a function");
  314. assert.throws(() => {
  315. Promise.resolve.call(function(executor) {
  316. assert.doesNotThrow(() => { executor(undefined, () => {}); }, "Calling executor with only a reject callback function works but Promise.resolve will throw");
  317. assert.throws(() => { executor(); }, TypeError, "Reject handler of promise capability is already set. Calling executor again throws", "Promise: an unexpected failure occurred while trying to obtain metadata information");
  318. });
  319. }, TypeError, "We set the reject callback to a real function but didn't set the resolve callback which Promise.resolve tries to call", "'Promise' is not a function");
  320. assert.throws(() => {
  321. Promise.resolve.call(function(executor) {
  322. assert.doesNotThrow(() => { executor(() => {}, undefined); }, "Calling executor with only a resolve callback function works but Promise.resolve will throw");
  323. assert.throws(() => { executor(); }, TypeError, "Resolve handler of promise capability is already set. Calling executor again throws", "Promise: an unexpected failure occurred while trying to obtain metadata information");
  324. });
  325. }, TypeError, "We set the resolve callback to a real function but didn't set the reject callback which NewPromiseCapability checks to see if callable", "'Promise' is not a function");
  326. assert.doesNotThrow(() => {
  327. var isCalled = false;
  328. Promise.resolve.call(function(executor) {
  329. assert.doesNotThrow(() => { executor(() => { isCalled = true; },() => { throw 'not called'; }); }, "Calling executor with callback functions works");
  330. assert.throws(() => { executor(); }, TypeError, "Callbacks of promise capability are already set. Calling executor again throws", "Promise: an unexpected failure occurred while trying to obtain metadata information");
  331. });
  332. assert.isTrue(isCalled, "We actually called the resolve callback handler");
  333. }, "We set the resolve callback to a real function which is called by Promise.resolve");
  334. }
  335. },
  336. {
  337. name: "Promise.prototype.then constructs return value via this.constructor[@@species]",
  338. body: function () {
  339. var promise = new Promise(function(resolve) { resolve(42); });
  340. var FakePromise1 = function(exec) { exec(function(){}, function(){}); };
  341. promise.constructor = FakePromise1;
  342. var FakePromise2 = function(exec) { exec(function(){}, function(){}); };
  343. Object.defineProperty(FakePromise1, Symbol.species, { value: FakePromise2 });
  344. assert.isTrue(promise.then(function(){}) instanceof FakePromise2, "Promise.prototype.then uses this.constructor[Symbol.species] to construct the object it returns");
  345. }
  346. },
  347. {
  348. name: "Subclass of Promise should return instances of the subclass from Promise methods",
  349. body: function () {
  350. class MyPromise extends Promise { }
  351. var myPromise = new MyPromise(function(resolve, reject) { resolve(42); });
  352. var thenPromise = myPromise.then(function() {});
  353. var catchPromise = myPromise.catch(function() {});
  354. assert.isTrue(thenPromise instanceof MyPromise, "Subclass of Promise is returned from Promise.prototype.then called with subclass of Promise object as this");
  355. assert.isTrue(catchPromise instanceof MyPromise, "Subclass of Promise is returned from Promise.prototype.catch called with subclass of Promise object as this");
  356. assert.isTrue(MyPromise.race([]) instanceof MyPromise, "Subclass of Promise inherits Promise.race which uses 'this' argument as constructor for return object");
  357. assert.isTrue(MyPromise.all([]) instanceof MyPromise, "Subclass of Promise inherits Promise.all which uses 'this' argument as constructor for return object");
  358. assert.isTrue(MyPromise.resolve(42) instanceof MyPromise, "Subclass of Promise inherits Promise.resolve which uses 'this' argument as constructor for return object");
  359. assert.isTrue(MyPromise.reject(42) instanceof MyPromise, "Subclass of Promise inherits Promise.reject which uses 'this' argument as constructor for return object");
  360. }
  361. },
  362. ];
  363. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });