ES6Promise.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
  4. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  5. //-------------------------------------------------------------------------------------------------------
  6. // ES6 Promise tests -- verifies the API shape and basic functionality
  7. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  8. var tests = [
  9. {
  10. name: "Promise constructor has correct shape",
  11. body: function () {
  12. assert.isTrue(Promise !== undefined, "Promise named global exists");
  13. assert.areEqual('function', typeof Promise, "Type of Promise global is 'function'");
  14. assert.areEqual("[object Promise]", Object.prototype.toString.call(new Promise(() => {})),
  15. "toString of Promise is '[object Promise]'");
  16. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'prototype');
  17. assert.isFalse(descriptor.writable, "Promise.length.writable === false");
  18. assert.isFalse(descriptor.enumerable, "Promise.length.enumerable === false");
  19. assert.isFalse(descriptor.configurable, "Promise.length.configurable === false");
  20. assert.areEqual('object', typeof descriptor.value, "typeof Promise.length === 'object'");
  21. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'length');
  22. assert.isFalse(descriptor.writable, "Promise.length.writable === false");
  23. assert.isFalse(descriptor.enumerable, "Promise.length.enumerable === false");
  24. assert.isTrue(descriptor.configurable, "Promise.length.configurable === true");
  25. assert.areEqual('number', typeof descriptor.value, "typeof Promise.length === 'number'");
  26. assert.areEqual(1, Promise.length, "Promise.length === 1");
  27. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'all');
  28. assert.isTrue(descriptor.writable, "Promise.all.writable === true");
  29. assert.isFalse(descriptor.enumerable, "Promise.all.enumerable === false");
  30. assert.isTrue(descriptor.configurable, "Promise.all.configurable === true");
  31. assert.areEqual('function', typeof descriptor.value, "typeof Promise.all === 'function'");
  32. assert.areEqual(1, Promise.all.length, "Promise.all.length === 1");
  33. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'allSettled');
  34. assert.isTrue(descriptor.writable, "Promise.allSettled.writable === true");
  35. assert.isFalse(descriptor.enumerable, "Promise.allSettled.enumerable === false");
  36. assert.isTrue(descriptor.configurable, "Promise.allSettled.configurable === true");
  37. assert.areEqual('function', typeof descriptor.value, "typeof Promise.allSettled === 'function'");
  38. assert.areEqual(1, Promise.allSettled.length, "Promise.allSettled.length === 1");
  39. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'any');
  40. assert.isTrue(descriptor.writable, "Promise.any.writable === true");
  41. assert.isFalse(descriptor.enumerable, "Promise.any.enumerable === false");
  42. assert.isTrue(descriptor.configurable, "Promise.any.configurable === true");
  43. assert.areEqual('function', typeof descriptor.value, "typeof Promise.any === 'function'");
  44. assert.areEqual(1, Promise.any.length, "Promise.any.length === 1");
  45. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'race');
  46. assert.isTrue(descriptor.writable, "Promise.race.writable === true");
  47. assert.isFalse(descriptor.enumerable, "Promise.race.enumerable === false");
  48. assert.isTrue(descriptor.configurable, "Promise.race.configurable === true");
  49. assert.areEqual('function', typeof descriptor.value, "typeof Promise.race === 'function'");
  50. assert.areEqual(1, Promise.race.length, "Promise.race.length === 1");
  51. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'reject');
  52. assert.isTrue(descriptor.writable, "Promise.reject.writable === true");
  53. assert.isFalse(descriptor.enumerable, "Promise.reject.enumerable === false");
  54. assert.isTrue(descriptor.configurable, "Promise.reject.configurable === true");
  55. assert.areEqual('function', typeof descriptor.value, "typeof Promise.reject === 'function'");
  56. assert.areEqual(1, Promise.reject.length, "Promise.reject.length === 1");
  57. var descriptor = Object.getOwnPropertyDescriptor(Promise, 'resolve');
  58. assert.isTrue(descriptor.writable, "Promise.resolve.writable === true");
  59. assert.isFalse(descriptor.enumerable, "Promise.resolve.enumerable === false");
  60. assert.isTrue(descriptor.configurable, "Promise.resolve.configurable === true");
  61. assert.areEqual('function', typeof descriptor.value, "typeof Promise.resolve === 'function'");
  62. assert.areEqual(1, Promise.resolve.length, "Promise.resolve.length === 1");
  63. }
  64. },
  65. {
  66. name: "Promise prototype has correct shape",
  67. body: function () {
  68. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, 'constructor');
  69. assert.isTrue(descriptor.writable, "Promise.prototype.constructor.writable === true");
  70. assert.isFalse(descriptor.enumerable, "Promise.prototype.constructor.enumerable === false");
  71. assert.isTrue(descriptor.configurable, "Promise.prototype.constructor.configurable === true");
  72. assert.areEqual('function', typeof descriptor.value, "typeof Promise.prototype.constructor === 'function'");
  73. assert.areEqual(1, Promise.prototype.constructor.length, "Promise.prototype.constructor.length === 1");
  74. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, 'catch');
  75. assert.isTrue(descriptor.writable, "Promise.prototype.catch.writable === true");
  76. assert.isFalse(descriptor.enumerable, "Promise.prototype.catch.enumerable === false");
  77. assert.isTrue(descriptor.configurable, "Promise.prototype.catch.configurable === true");
  78. assert.areEqual('function', typeof descriptor.value, "typeof Promise.prototype.catch === 'function'");
  79. assert.areEqual(1, Promise.prototype.catch.length, "Promise.prototype.catch.length === 1");
  80. assert.areEqual("catch", Promise.prototype.catch.name, "Promise.prototype.catch.name === 'catch'");
  81. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, 'then');
  82. assert.isTrue(descriptor.writable, "Promise.prototype.then.writable === true");
  83. assert.isFalse(descriptor.enumerable, "Promise.prototype.then.enumerable === false");
  84. assert.isTrue(descriptor.configurable, "Promise.prototype.then.configurable === true");
  85. assert.areEqual('function', typeof descriptor.value, "typeof Promise.prototype.then === 'function'");
  86. assert.areEqual(2, Promise.prototype.then.length, "Promise.prototype.then.length === 2");
  87. assert.areEqual("then", Promise.prototype.then.name, "Promise.prototype.then.name === 'then'");
  88. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, 'finally');
  89. assert.isTrue(descriptor.writable, "Promise.prototype.finally.writable === true");
  90. assert.isFalse(descriptor.enumerable, "Promise.prototype.finally.enumerable === false");
  91. assert.isTrue(descriptor.configurable, "Promise.prototype.finally.configurable === true");
  92. assert.areEqual('function', typeof descriptor.value, "typeof Promise.prototype.finally === 'function'");
  93. assert.areEqual(1, Promise.prototype.finally.length, "Promise.prototype.finally.length === 1");
  94. assert.areEqual("finally", Promise.prototype.finally.name, "Promise.prototype.finally.name === 'finally'");
  95. var descriptor = Object.getOwnPropertyDescriptor(Promise.prototype, Symbol.toStringTag);
  96. assert.isFalse(descriptor.writable, "Promise.prototype[@@toStringTag].writable === false");
  97. assert.isFalse(descriptor.enumerable, "Promise.prototype[@@toStringTag].enumerable === false");
  98. assert.isTrue(descriptor.configurable, "Promise.prototype[@@toStringTag].configurable === true");
  99. assert.areEqual('string', typeof descriptor.value, "typeof Promise.prototype[@@toStringTag] === 'string'");
  100. assert.areEqual('Promise', Promise.prototype[Symbol.toStringTag], "Promise.prototype[@@toStringTag] === 'Promise'");
  101. }
  102. },
  103. {
  104. name: "Promise constructor throwing behavior",
  105. body: function () {
  106. 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");
  107. 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");
  108. 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");
  109. 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");
  110. assert.throws(function() { new Promise(); }, TypeError, "new Promise throws when called with no parameter", "Promise: argument is not a Function object");
  111. assert.throws(function() { new Promise(undefined); }, TypeError, "new Promise throws when called with an undefined parameter", "Promise: argument is not a Function object");
  112. assert.throws(function() { new Promise(null); }, TypeError, "new Promise throws when called with a null parameter", "Promise: argument is not a Function object");
  113. assert.throws(function() { new Promise({}); }, TypeError, "new Promise throws when called with a non-function parameter", "Promise: argument is not a Function object");
  114. var promise = new Promise(function() { } );
  115. 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");
  116. 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");
  117. 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");
  118. 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");
  119. 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");
  120. }
  121. },
  122. {
  123. name: "Promise.prototype.then throwing behavior",
  124. body: function () {
  125. 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");
  126. 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");
  127. 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");
  128. 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");
  129. }
  130. },
  131. {
  132. name: "Promise.prototype.catch throwing behavior",
  133. body: function () {
  134. 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");
  135. 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");
  136. 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");
  137. 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");
  138. 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");
  139. 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");
  140. 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");
  141. 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!");
  142. 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!");
  143. }
  144. },
  145. {
  146. name: "Promise.prototype.finally throwing behavior",
  147. body: function () {
  148. assert.throws(function() { Promise.prototype.finally.call(); }, TypeError, "Promise.prototype.finally throws when called with no this parameter", "Promise.prototype.finally: 'this' is not an Object");
  149. assert.throws(function() { Promise.prototype.finally.call(undefined); }, TypeError, "Promise.prototype.finally throws when called with undefined this parameter", "Promise.prototype.finally: 'this' is not an Object");
  150. assert.throws(function() { Promise.prototype.finally.call(null); }, TypeError, "Promise.prototype.finally throws when called with null this parameter", "Promise.prototype.finally: 'this' is not an Object");
  151. assert.throws(function() { Promise.prototype.finally.call({}); }, TypeError, "Promise.prototype.finally throws when called with a this parameter which doesn't have a then property", "Promise.prototype.finally: argument is not a Function object");
  152. assert.throws(function() { Promise.prototype.finally.call({ then: undefined }); }, TypeError, "Promise.prototype.finally throws when called with a this parameter which has a then property with undefined value", "Promise.prototype.finally: argument is not a Function object");
  153. assert.throws(function() { Promise.prototype.finally.call({ then: null }); }, TypeError, "Promise.prototype.finally throws when called with a this parameter which has a then property with null value", "Promise.prototype.finally: argument is not a Function object");
  154. assert.throws(function() { Promise.prototype.finally.call({ then: {} }); }, TypeError, "Promise.prototype.finally throws when called with a this parameter which has a then property with non-function value", "Promise.prototype.finally: argument is not a Function object");
  155. assert.throws(function() { Promise.prototype.finally.call({ get then() { throw new TypeError('error!'); } }); }, TypeError, "Promise.prototype.finally throws if the then property of the this argument throws", "error!");
  156. assert.throws(function() { Promise.prototype.finally.call({ then: function() { throw new TypeError('error!'); } }); }, TypeError, "Promise.prototype.finally throws if the then property of the this argument throws", "error!");
  157. }
  158. },
  159. {
  160. name: "Promise.resolve throwing behavior",
  161. body: function () {
  162. assert.throws(function() { Promise.resolve.call(); }, TypeError, "Promise.resolve throws when called with no this parameter", "Promise.resolve: 'this' is not an Object");
  163. assert.throws(function() { Promise.resolve.call(undefined); }, TypeError, "Promise.resolve throws when this parameter is undefined", "Promise.resolve: 'this' is not an Object");
  164. assert.throws(function() { Promise.resolve.call(null); }, TypeError, "Promise.resolve throws when this parameter is null", "Promise.resolve: 'this' is not an Object");
  165. assert.throws(function() { Promise.resolve.call({}); }, TypeError, "Promise.resolve throws when this parameter is non-callable", "Function expected");
  166. assert.throws(function() { Promise.resolve.call(Math.sin); }, TypeError, "Promise.resolve throws when this parameter is a non-constructor", "Function expected");
  167. }
  168. },
  169. {
  170. name: "Promise.reject throwing behavior",
  171. body: function () {
  172. assert.throws(function() { Promise.reject.call(); }, TypeError, "Promise.reject throws when called with no this parameter", "Promise.reject: 'this' is not an Object");
  173. 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");
  174. 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");
  175. assert.throws(function() { Promise.reject.call({}); }, TypeError, "Promise.reject throws when called when this parameter is non-callable", "Function expected");
  176. assert.throws(function() { Promise.reject.call(Math.sin); }, TypeError, "Promise.reject throws when this parameter is a non-constructor", "Function expected");
  177. }
  178. },
  179. {
  180. name: "Promise.race throwing behavior",
  181. body: function () {
  182. assert.throws(function() { Promise.race.call(); }, TypeError, "Promise.race throws when called with no this parameter", "Promise.race: 'this' is not an Object");
  183. 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");
  184. 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");
  185. assert.throws(function() { Promise.race.call({}); }, TypeError, "Promise.race throws when called when this parameter is non-callable", "Function expected");
  186. assert.throws(function() { Promise.race.call(Math.sin); }, TypeError, "Promise.race throws when this parameter is a non-constructor", "Function expected");
  187. }
  188. },
  189. {
  190. name: "Promise.all throwing behavior",
  191. body: function () {
  192. assert.throws(function() { Promise.all.call(); }, TypeError, "Promise.all throws when called with no this parameter", "Promise.all: 'this' is not an Object");
  193. 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");
  194. 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");
  195. assert.throws(function() { Promise.all.call({}); }, TypeError, "Promise.all throws when called when this parameter is non-callable", "Function expected");
  196. assert.throws(function() { Promise.all.call(Math.sin); }, TypeError, "Promise.all throws when this parameter is a non-constructor", "Function expected");
  197. }
  198. },
  199. {
  200. name: "Promise.allSettled throwing behavior",
  201. body: function () {
  202. assert.throws(function() { Promise.allSettled.call(); }, TypeError, "Promise.allSettled throws when called with no this parameter", "Promise.allSettled: 'this' is not an Object");
  203. assert.throws(function() { Promise.allSettled.call(undefined); }, TypeError, "Promise.allSettled throws when called when this parameter is undefined", "Promise.allSettled: 'this' is not an Object");
  204. assert.throws(function() { Promise.allSettled.call(null); }, TypeError, "Promise.allSettled throws when called when this parameter is null", "Promise.allSettled: 'this' is not an Object");
  205. assert.throws(function() { Promise.allSettled.call({}); }, TypeError, "Promise.allSettled throws when called when this parameter is non-callable", "Function expected");
  206. assert.throws(function() { Promise.allSettled.call(Math.sin); }, TypeError, "Promise.allSettled throws when this parameter is a non-constructor", "Function expected");
  207. }
  208. },
  209. {
  210. name: "Promise.any throwing behavior",
  211. body: function () {
  212. assert.throws(function() { Promise.any.call(); }, TypeError, "Promise.any throws when called with no this parameter", "Function expected");
  213. assert.throws(function() { Promise.any.call(undefined); }, TypeError, "Promise.any throws when called when this parameter is undefined", "Function expected");
  214. assert.throws(function() { Promise.any.call(null); }, TypeError, "Promise.any throws when called when this parameter is null", "Function expected");
  215. assert.throws(function() { Promise.any.call({}); }, TypeError, "Promise.any throws when called when this parameter is non-callable", "Function expected");
  216. assert.throws(function() { Promise.any.call(Math.sin); }, TypeError, "Promise.any throws when this parameter is a non-constructor", "Function expected");
  217. assert.throws(function() { Promise.any.call(5); }, TypeError, "Promise.any throws when this parameter is a integer", "Function expected");
  218. assert.throws(function() { Promise.any.call(5.0); }, TypeError, "Promise.any throws when this parameter is a float", "Function expected");
  219. assert.throws(function() { Promise.any.call("literal"); }, TypeError, "Promise.any throws when this parameter is a string literal", "Function expected");
  220. }
  221. },
  222. {
  223. name: "Promise.prototype.then to access constructor through [@@species]",
  224. body: function () {
  225. var p = new Promise(function(resolve, reject) { });
  226. p.constructor = undefined;
  227. assert.doesNotThrow(function() { p.then(function(result) {}, function(err) {}); }, "");
  228. }
  229. },
  230. {
  231. name: "Promise.resolve checks the 'constructor' property of the argument if it's a promise",
  232. body: function () {
  233. let x = new Promise(function(resolve, reject) { });
  234. assert.isTrue(x === Promise.resolve(x), "Promise.resolve called with a promise object, x, returns that promise if 'this' === x.constructor");
  235. let xConstructor = {foo: 'my constructor'};
  236. x.constructor = xConstructor;
  237. assert.isTrue(x === Promise.resolve.call(xConstructor, x), "Promise.resolve called with a promise object, x, returns that promise if 'this' === x.constructor");
  238. assert.isFalse(x === Promise.resolve(x), "Promise.resolve called with a promise object, x, returns a new promise if 'this' !== x.constructor");
  239. }
  240. },
  241. {
  242. name: "Promise resolve / reject functions handed to the executor function",
  243. body: function () {
  244. var resolveFunction = undefined;
  245. var rejectFunction = undefined;
  246. new Promise(function(resolve, reject) {
  247. resolveFunction = resolve;
  248. rejectFunction = reject;
  249. });
  250. assert.isFalse(resolveFunction === undefined, "new Promise should provide a resolve function");
  251. assert.isFalse(rejectFunction === undefined, "new Promise should provide a reject function");
  252. assert.areEqual(1, resolveFunction.length, "Resolve function should have length 1");
  253. assert.areEqual('function', typeof resolveFunction, "Resolve function is a function type");
  254. assert.isTrue(Object.isExtensible(resolveFunction), "Resolve function is an extensible object");
  255. assert.areEqual(Object.getPrototypeOf(resolveFunction), Function.prototype, "Resolve function has __proto__ set to Function.prototype");
  256. assert.throws(() => { new resolveFunction(); }, TypeError, "Resolve function is an anonymous built-in but not a constructor", "Function is not a constructor");
  257. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveFunction, "prototype"), "Resolve function does not have 'prototype' own property");
  258. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveFunction, "name"), "Resolve function does not have 'name' own property");
  259. assert.areEqual(1, rejectFunction.length, "Reject function should have length 1");
  260. assert.areEqual('function', typeof rejectFunction, "Reject function is a function type");
  261. assert.isTrue(Object.isExtensible(rejectFunction), "Reject function is an extensible object");
  262. assert.areEqual(Object.getPrototypeOf(rejectFunction), Function.prototype, "Reject function has __proto__ set to Function.prototype");
  263. assert.throws(() => { new rejectFunction(); }, TypeError, "Reject function is an anonymous built-in but not a constructor", "Function is not a constructor");
  264. assert.isFalse(Object.prototype.hasOwnProperty.call(rejectFunction, "prototype"), "Reject function does not have 'prototype' own property");
  265. assert.isFalse(Object.prototype.hasOwnProperty.call(rejectFunction, "name"), "Reject function does not have 'name' own property");
  266. }
  267. },
  268. {
  269. name: "Promise.all resolve / reject functions",
  270. body: function () {
  271. let isCalled = false;
  272. let p = new Promise(function(resolve, reject) { resolve(); });
  273. p.then = function(resolve, reject) {
  274. assert.areEqual(1, resolve.length, "Resolve function should have length 1");
  275. assert.areEqual('function', typeof resolve, "Resolve function is a function type");
  276. assert.areEqual(1, reject.length, "Reject function should have length 1");
  277. assert.areEqual('function', typeof reject, "Reject function is a function type");
  278. isCalled = true;
  279. };
  280. Promise.all([p]);
  281. assert.isTrue(isCalled, "The then function was actually called");
  282. }
  283. },
  284. {
  285. name: "Promise.all uses iterator next correctly",
  286. body: function () {
  287. let calledNext = 0;
  288. const bar = {
  289. [Symbol.iterator]() { return this; },
  290. next () {
  291. this.next = function (){ throw new Error ("Next should have been cached so this should not be called") };
  292. return {value : Promise.resolve(0), done : (++calledNext > 2)}
  293. }
  294. }
  295. Promise.all(bar);
  296. assert.areEqual(3, calledNext, "Promise.all should use the iterator protocol, and next should be cached");
  297. }
  298. },
  299. {
  300. name: "Promise.allSettled uses iterator next correctly",
  301. body: function () {
  302. let calledNext = 0;
  303. const bar = {
  304. [Symbol.iterator]() { return this; },
  305. next () {
  306. this.next = function (){ throw new Error ("Next should have been cached so this should not be called") };
  307. return {value : Promise.resolve(0), done : (++calledNext > 2)}
  308. }
  309. }
  310. Promise.allSettled(bar);
  311. assert.areEqual(3, calledNext, "Promise.allSettled should use the iterator protocol, and next should be cached");
  312. }
  313. },
  314. {
  315. name: "Promise.any uses iterator next correctly",
  316. body: function () {
  317. let calledNext = 0;
  318. const bar = {
  319. [Symbol.iterator]() { return this; },
  320. next () {
  321. this.next = function (){ throw new Error ("Next should have been cached so this should not be called") };
  322. return {value : Promise.resolve(0), done : (++calledNext > 2)}
  323. }
  324. }
  325. Promise.any(bar);
  326. assert.areEqual(3, calledNext, "Promise.any should use the iterator protocol, and next should be cached");
  327. }
  328. },
  329. {
  330. name: "Promise.race uses iterator next correctly",
  331. body: function () {
  332. let calledNext = 0;
  333. const bar = {
  334. [Symbol.iterator]() { return this; },
  335. next () {
  336. this.next = function (){ throw new Error ("Next should have been cached so this should not be called") };
  337. return {value : Promise.resolve(0), done : (++calledNext > 2)}
  338. }
  339. }
  340. Promise.race(bar);
  341. assert.areEqual(3, calledNext, "Promise.race should use the iterator protocol, and next should be cached");
  342. }
  343. },
  344. {
  345. name: "Executor function passed to Promise constructor via NewPromiseCapability",
  346. body: function () {
  347. let isCalled = false;
  348. let p = new Promise(function(resolve, reject) { resolve(); });
  349. let test_ctor = function(executor) {
  350. assert.isTrue(this instanceof test_ctor, "The 'this' argument is an instance of the ctor function");
  351. assert.areEqual(2, executor.length, "Executor function should have length 2");
  352. assert.areEqual('function', typeof executor, "Executor function is a function type");
  353. isCalled = true;
  354. executor(function(){}, function(){});
  355. }
  356. Promise.resolve.call(test_ctor, p);
  357. assert.isTrue(isCalled, "The constructor function was actually called");
  358. }
  359. },
  360. {
  361. name: "Promise.all calls thenable.then with correct resolve / reject handlers",
  362. body: function () {
  363. var resolveElementFunction = undefined;
  364. var rejectElementFunction = undefined;
  365. var thenable = {
  366. then: function(fulfill, reject) {
  367. resolveElementFunction = fulfill;
  368. rejectElementFunction = reject;
  369. }
  370. };
  371. function myResolveFunction() {
  372. throw 'should not call this function';
  373. }
  374. function myRejectFunction() {
  375. throw 'should not call this function';
  376. }
  377. function NotPromise(executor) {
  378. executor(myResolveFunction, myRejectFunction);
  379. }
  380. NotPromise.resolve = function(v) { return v; };
  381. Promise.all.call(NotPromise, [thenable]);
  382. assert.isFalse(resolveElementFunction === undefined, "Promise.all should have called thenable.then with a resolve callback");
  383. assert.isFalse(rejectElementFunction === undefined, "Promise.all should have called thenable.then with a reject callback");
  384. assert.isFalse(myResolveFunction === resolveElementFunction, "Resolve function should not be the one we passed to the promise executor");
  385. assert.areEqual(myRejectFunction, rejectElementFunction, "Promise.all should call thenable.then with a PromiseAllResolve function and the reject handler we initialized the promise with");
  386. assert.areEqual(1, resolveElementFunction.length, "Resolve function should have length 1");
  387. assert.areEqual('function', typeof resolveElementFunction, "Resolve function is a function type");
  388. assert.isTrue(Object.isExtensible(resolveElementFunction), "Resolve function is an extensible object");
  389. assert.areEqual(Object.getPrototypeOf(resolveElementFunction), Function.prototype, "Resolve function has __proto__ set to Function.prototype");
  390. assert.throws(() => { new resolveElementFunction(); }, TypeError, "Resolve function is an anonymous built-in but not a constructor", "Function is not a constructor");
  391. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveElementFunction, "prototype"), "Resolve function does not have 'prototype' own property");
  392. assert.isFalse(Object.prototype.hasOwnProperty.call(resolveElementFunction, "name"), "Resolve function does not have 'name' own property");
  393. }
  394. },
  395. {
  396. name: "Shape of executor function passed to Promise constructor",
  397. body: function () {
  398. var executorFunction = undefined;
  399. function NotPromise2(executor) {
  400. executorFunction = executor;
  401. executor(() => {}, () => {});
  402. }
  403. Promise.resolve.call(NotPromise2);
  404. assert.isFalse(executorFunction === undefined, "Promise.resolve should have tried to new NotPromise2");
  405. assert.areEqual(2, executorFunction.length, "Executor function should have length 1");
  406. assert.areEqual('function', typeof executorFunction, "Executor function is a function type");
  407. assert.isTrue(Object.isExtensible(executorFunction), "Executor function is an extensible object");
  408. assert.areEqual(Object.getPrototypeOf(executorFunction), Function.prototype, "Executor function has __proto__ set to Function.prototype");
  409. assert.throws(() => { new executorFunction(); }, TypeError, "Executor function is an anonymous built-in but not a constructor", "Function is not a constructor");
  410. assert.isFalse(Object.prototype.hasOwnProperty.call(executorFunction, "prototype"), "Executor function does not have 'prototype' own property");
  411. assert.isFalse(Object.prototype.hasOwnProperty.call(executorFunction, "name"), "Executor function does not have 'name' own property");
  412. }
  413. },
  414. {
  415. name: "Test calling capabilities executor function with different arguments",
  416. body: function () {
  417. assert.throws(() => {
  418. Promise.resolve.call(function(executor) {
  419. });
  420. }, TypeError, "We didn't set the resolve callback, Promise.resolve tried to call it which should throw", "'Promise' is not a function");
  421. assert.throws(() => {
  422. Promise.resolve.call(function(executor) {
  423. assert.doesNotThrow(() => { executor(); }, "Calling executor with no arguments will set the promise capability resolve and reject callbacks to undefined");
  424. assert.doesNotThrow(() => { executor(); }, "Calling executor with no arguments again works because the promise capability resolve and reject callbacks are still undefined");
  425. });
  426. }, TypeError, "We set the resolve callback to undefined, Promise.resolve tried to call it which should throw", "'Promise' is not a function");
  427. assert.throws(() => {
  428. Promise.resolve.call(function(executor) {
  429. assert.doesNotThrow(() => { executor('string', 12345); }, "Calling executor with non-function arguments will set the promise capability resolve and reject callbacks");
  430. 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");
  431. });
  432. }, 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");
  433. assert.throws(() => {
  434. Promise.resolve.call(function(executor) {
  435. assert.doesNotThrow(() => { executor(undefined, () => {}); }, "Calling executor with only a reject callback function works but Promise.resolve will throw");
  436. 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");
  437. });
  438. }, 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");
  439. assert.throws(() => {
  440. Promise.resolve.call(function(executor) {
  441. assert.doesNotThrow(() => { executor(() => {}, undefined); }, "Calling executor with only a resolve callback function works but Promise.resolve will throw");
  442. 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");
  443. });
  444. }, 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");
  445. assert.doesNotThrow(() => {
  446. var isCalled = false;
  447. Promise.resolve.call(function(executor) {
  448. assert.doesNotThrow(() => { executor(() => { isCalled = true; },() => { throw 'not called'; }); }, "Calling executor with callback functions works");
  449. 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");
  450. });
  451. assert.isTrue(isCalled, "We actually called the resolve callback handler");
  452. }, "We set the resolve callback to a real function which is called by Promise.resolve");
  453. }
  454. },
  455. {
  456. name: "Promise.prototype.then constructs return value via this.constructor[@@species]",
  457. body: function () {
  458. var promise = new Promise(function(resolve) { resolve(42); });
  459. var FakePromise1 = function(exec) { exec(function(){}, function(){}); };
  460. promise.constructor = FakePromise1;
  461. var FakePromise2 = function(exec) { exec(function(){}, function(){}); };
  462. Object.defineProperty(FakePromise1, Symbol.species, { value: FakePromise2 });
  463. assert.isTrue(promise.then(function(){}) instanceof FakePromise2, "Promise.prototype.then uses this.constructor[Symbol.species] to construct the object it returns");
  464. }
  465. },
  466. {
  467. name: "Promise.prototype.finally uses modified then",
  468. body: function (index) {
  469. var calledThen = false;
  470. var p = new Promise(function() {});
  471. p.then = function() { calledThen = true; }
  472. p.finally("test");
  473. assert.isTrue(calledThen, "Promise.prototype.finally uses the modified then function");
  474. }
  475. },
  476. {
  477. name: "Promise.prototype.finally creates anonymous ThenFinally function",
  478. body: function (index) {
  479. class TestPromise extends Promise {
  480. then (a, b)
  481. {
  482. this.first = a;
  483. this.second = b;
  484. this.argCount = arguments.length;
  485. }
  486. }
  487. var p = new TestPromise(function() {});
  488. p.finally(function() {});
  489. assert.areEqual(p.first.name, "", "Promise.prototype.finally creates anonymous resolve handler");
  490. assert.areEqual(p.first.length, 1, "Promise.prototype.finally creates resolve handler with length 1");
  491. assert.areEqual(p.second.name, "", "Promise.prototype.finally creates anonymous reject handler");
  492. assert.areEqual(p.second.length, 1, "Promise.prototype.finally creates reject handler with length 1");
  493. assert.areEqual(p.argCount, 2, "Promise.prototype.finally invokes then with exactly 2 arguments");
  494. }
  495. },
  496. {
  497. name: "Promise.prototype.finally with non-callable argument",
  498. body: function (index) {
  499. class TestPromise extends Promise {
  500. then (a, b)
  501. {
  502. this.first = a;
  503. this.second = b;
  504. this.argCount = arguments.length;
  505. }
  506. }
  507. let p = new TestPromise(r => r());
  508. p.finally("not callable");
  509. assert.areEqual(p.first, "not callable", "Promise.prototype.finally passes through value when not callable");
  510. assert.areEqual(p.second, "not callable", "Promise.prototype.finally passes through value when not callable");
  511. }
  512. },
  513. {
  514. name: "Promise.prototype.finally called with non-promise this value throws",
  515. body: function (index) {
  516. let final = Promise.prototype.finally;
  517. assert.throws(()=>{final.call(new Number(5), "test")}, TypeError, "finally throws when called with non-promise object");
  518. assert.throws(()=>{final.call(new Array(5), "test")}, TypeError, "finally throws when called with non-promise object");
  519. assert.throws(()=>{final.call(new Object(5), "test")}, TypeError, "finally throws when called with non-promise object");
  520. assert.throws(()=>{final.call(5, "test")}, TypeError, "finally throws when called with non-promise object");
  521. assert.throws(()=>{final.call({a:5, b:6, c:7}, "test")}, TypeError, "finally throws when called with non-promise object");
  522. assert.throws(()=>{final.call([2,3,4], "test")}, TypeError, "finally throws when called with non-promise object");
  523. assert.throws(()=>{final.call("test", "test")}, TypeError, "finally throws when called with non-promise object");
  524. assert.throws(()=>{final.call(new String("test"), "test")}, TypeError, "finally throws when called with non-promise object");
  525. }
  526. },
  527. {
  528. name: "Anonymous thenFinally function doesn't throw",
  529. body: function (index) {
  530. let count = 0;
  531. class TestPromise extends Promise {
  532. then (a, b) {
  533. ++count;
  534. assert.doesNotThrow(()=>a(), "anonymous then finally function does not throw");
  535. if(count == 1) assert.doesNotThrow(()=>b(), "anonymous catchFinally function does not throw");
  536. }
  537. }
  538. new TestPromise(function() {}).finally(()=>{});
  539. }
  540. },
  541. {
  542. name: "Subclass of Promise should return instances of the subclass from Promise methods",
  543. body: function () {
  544. class MyPromise extends Promise { }
  545. var myPromise = new MyPromise(function(resolve, reject) { resolve(42); });
  546. var thenPromise = myPromise.then(function() {});
  547. var catchPromise = myPromise.catch(function() {});
  548. var finallyPromise = myPromise.finally(function () {});
  549. assert.isTrue(thenPromise instanceof MyPromise, "Subclass of Promise is returned from Promise.prototype.then called with subclass of Promise object as this");
  550. assert.isTrue(catchPromise instanceof MyPromise, "Subclass of Promise is returned from Promise.prototype.catch called with subclass of Promise object as this");
  551. assert.isTrue(finallyPromise instanceof MyPromise, "Subclass of Promise is returned from Promise.prototype.finally called with subclass of Promise object as this");
  552. assert.isTrue(MyPromise.race([]) instanceof MyPromise, "Subclass of Promise inherits Promise.race which uses 'this' argument as constructor for return object");
  553. assert.isTrue(MyPromise.all([]) instanceof MyPromise, "Subclass of Promise inherits Promise.all which uses 'this' argument as constructor for return object");
  554. assert.isTrue(MyPromise.any([]) instanceof MyPromise, "Subclass of Promise inherits Promise.any which uses 'this' argument as constructor for return object");
  555. assert.isTrue(MyPromise.resolve(42) instanceof MyPromise, "Subclass of Promise inherits Promise.resolve which uses 'this' argument as constructor for return object");
  556. assert.isTrue(MyPromise.reject(42) instanceof MyPromise, "Subclass of Promise inherits Promise.reject which uses 'this' argument as constructor for return object");
  557. }
  558. },
  559. ];
  560. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });