top-level-await.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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. const promises = [];
  6. let resolveOne, resolveTwo;
  7. let counter = 0;
  8. const firstPromise = new Promise(r => { resolveOne = r});
  9. const secondPromise = new Promise(r => { resolveTwo = function(a)
  10. {
  11. if (counter > 0) throw new Error("should only be called once");
  12. ++ counter;
  13. r(a);
  14. }});
  15. export default resolveOne;
  16. export {resolveTwo};
  17. // async tests without a baseline by using an array of promises
  18. function AddPromise(test, promise, result, shouldFail = false)
  19. {
  20. const resultPromise = shouldFail ?
  21. promise.then(
  22. ()=>{throw new Error(`${test} failed - promise should have been rejected`);},
  23. (x)=>{if (result !== x) {throw new Error(`${test} failed - ${JSON.stringify(x)} should equal ${JSON.stringify(result)}`);}}
  24. ) :
  25. promise.then(
  26. (x)=>{if (result !== x) {throw new Error(`${test} failed - ${JSON.stringify(x)} should equal ${JSON.stringify(result)}`);}},
  27. (x)=>{throw new Error(`${test} failed - ${x}`);}
  28. );
  29. promises.push(resultPromise);
  30. }
  31. const tests = [
  32. {
  33. name : "Load a single async module",
  34. body(test) {
  35. WScript.RegisterModuleSource("Single1", `
  36. export default 5;
  37. await 0;
  38. `);
  39. AddPromise(test, import("Single1").then(x => x.default), 5, false);
  40. }
  41. },
  42. {
  43. name : "Syntax in an async module",
  44. body(test) {
  45. WScript.RegisterModuleSource("Syntax1", '(await 0) = 1;');
  46. WScript.RegisterModuleSource("Syntax2", 'await = 1;');
  47. WScript.RegisterModuleSource("Syntax3", 'await import "Syntax1"');
  48. WScript.RegisterModuleSource("Syntax4", 'await + 5;');
  49. WScript.RegisterModuleSource("Syntax5", 'import await "bar";');
  50. WScript.RegisterModuleSource("Syntax6", 'await 0; function bar () { await 0; }');
  51. WScript.RegisterModuleSource("Syntax7", 'await 0; yield 5;');
  52. WScript.RegisterModuleSource("Syntax8", 'function foo() { await 0; }');
  53. WScript.RegisterModuleSource("Syntax9", 'function* foo() { await 0; }');
  54. AddPromise(test, import("Syntax1").catch(x => (x instanceof SyntaxError)), true, false);
  55. AddPromise(test, import("Syntax2").catch(x => (x instanceof SyntaxError)), true, false);
  56. AddPromise(test, import("Syntax3").catch(x => (x instanceof SyntaxError)), true, false);
  57. AddPromise(test, import("Syntax4").then(x => x.default), undefined, false);
  58. AddPromise(test, import("Syntax5").catch(x => (x instanceof SyntaxError)), true, false);
  59. AddPromise(test, import("Syntax6").catch(x => (x instanceof SyntaxError)), true, false);
  60. AddPromise(test, import("Syntax7").catch(x => (x instanceof SyntaxError)), true, false);
  61. AddPromise(test, import("Syntax8").catch(x => (x instanceof SyntaxError)), true, false);
  62. AddPromise(test, import("Syntax9").catch(x => (x instanceof SyntaxError)), true, false);
  63. }
  64. },
  65. {
  66. name : "Basic Async load order",
  67. body(test) {
  68. WScript.RegisterModuleSource("LoadOrder1", 'export default [];');
  69. WScript.RegisterModuleSource("LoadOrder2", `
  70. import arr from 'LoadOrder1';
  71. export {arr as default};
  72. arr.push("LO2a1");
  73. await 0;
  74. arr.push("LO2a2");
  75. await 0;
  76. await 0;
  77. arr.push("LO2a3");
  78. await 0;
  79. await 0;
  80. await 0;
  81. arr.push("LO2a4");
  82. await 0;
  83. arr.push("LO2a5");
  84. await 0;
  85. await 0;
  86. await 0;
  87. arr.push("LO2a6");
  88. `);
  89. WScript.RegisterModuleSource("LoadOrder3", `
  90. import arr from 'LoadOrder1';
  91. export {arr as default};
  92. arr.push("LO3a1");
  93. await 0;
  94. arr.push("LO3a2");
  95. `);
  96. WScript.RegisterModuleSource("LoadOrder4", `
  97. import arr from 'LoadOrder2';
  98. import 'LoadOrder3'
  99. export {arr as default};
  100. arr.push("LO4");
  101. `);
  102. WScript.RegisterModuleSource("LoadOrder5", `
  103. import arr from 'LoadOrder3';
  104. export {arr as default};
  105. arr.push("LO5a1");
  106. await 0;
  107. arr.push("LO5a2");
  108. `);
  109. WScript.RegisterModuleSource("LoadOrder6", `
  110. import arr from 'LoadOrder5';
  111. export {arr as default};
  112. arr.push("LO6");
  113. `);
  114. WScript.RegisterModuleSource("LoadOrder7", `
  115. import arr from 'LoadOrder6';
  116. import 'LoadOrder4';
  117. export {arr as default};
  118. arr.push("LO7");
  119. `);
  120. import('LoadOrder4');
  121. AddPromise(test, import('LoadOrder1').then(() => import('LoadOrder7').then(x => x.default.toString())),
  122. "LO2a1,LO3a1,LO2a2,LO3a2,LO2a3,LO5a1,LO2a4,LO5a2,LO2a5,LO6,LO2a6,LO4,LO7", false);
  123. }
  124. },
  125. {
  126. name : "Cyclic load order",
  127. body(test) {
  128. WScript.RegisterModuleSource("CyclicOrder1", 'export default [];');
  129. WScript.RegisterModuleSource("CyclicOrder2", `
  130. import arr from 'CyclicOrder1';
  131. import {testFunc} from 'CyclicOrder4';
  132. testFunc();
  133. arr.push("CO2a1");
  134. await 0;
  135. arr.push("CO2a2");
  136. `);
  137. WScript.RegisterModuleSource("CyclicOrder3", `
  138. import arr from 'CyclicOrder1';
  139. import 'CyclicOrder2';
  140. arr.push("CO3a1");
  141. await 0;
  142. arr.push("CO3a2");
  143. `);
  144. WScript.RegisterModuleSource("CyclicOrder4", `
  145. import arr from 'CyclicOrder1';
  146. export {arr as default};
  147. export function testFunc () { arr.push("testFunc");}
  148. import 'CyclicOrder3';
  149. arr.push("CO4a1");
  150. await 0;
  151. arr.push("CO4a2");
  152. `);
  153. AddPromise(test, import('CyclicOrder4').then(x => x.default.toString()), "testFunc,CO2a1,CO2a2,CO3a1,CO3a2,CO4a1,CO4a2", false);
  154. }
  155. },
  156. {
  157. name : "Double Cyclic load order",
  158. body(test) {
  159. WScript.RegisterModuleSource('CyclicDouble1', 'export default [];');
  160. WScript.RegisterModuleSource('CyclicDouble2', `
  161. import arr from 'CyclicDouble1';
  162. import 'CyclicDouble4';
  163. arr.push("CD2a1");
  164. await 0;
  165. arr.push("CD2a2");
  166. `);
  167. WScript.RegisterModuleSource('CyclicDouble3', `
  168. import arr from 'CyclicDouble1';
  169. import 'CyclicDouble2'
  170. arr.push("CD3a1");
  171. await 0;
  172. arr.push("CD3a2");
  173. `);
  174. WScript.RegisterModuleSource('CyclicDouble4', `
  175. import arr from 'CyclicDouble1';
  176. import 'CyclicDouble3'
  177. arr.push("CD4a1");
  178. await 0;
  179. arr.push("CD4a2");
  180. `);
  181. WScript.RegisterModuleSource('CyclicDouble5', `
  182. import arr from 'CyclicDouble1';
  183. arr.push("CD5");
  184. `);
  185. WScript.RegisterModuleSource('CyclicDouble6', `
  186. import arr from 'CyclicDouble1';
  187. import 'CyclicDouble5'
  188. import 'CyclicDouble3'
  189. export {arr as default};
  190. arr.push("CD6a1");
  191. await 0;
  192. arr.push("CD6a2");
  193. `);
  194. import ('CyclicDouble4');
  195. AddPromise(test, import ('CyclicDouble1').then(() => import('CyclicDouble6').then(x => x.default.toString())), "CD2a1,CD2a2,CD3a1,CD3a2,CD5,CD4a1,CD6a1,CD4a2,CD6a2", false);
  196. }
  197. },
  198. {
  199. name : "Rejections",
  200. body (test) {
  201. WScript.RegisterModuleSource("Rejection1", 'await 0; throw new Error("rejection")');
  202. WScript.RegisterModuleSource("Rejection2", 'import "Rejection1"');
  203. AddPromise(test, import('Rejection1').catch(x => (x instanceof Error && x.message === "rejection")), true, false);
  204. AddPromise(test, import('Rejection2').catch(x => (x instanceof Error && x.message === "rejection")), true, false);
  205. WScript.RegisterModuleSource("CyclicRejection1", 'export default [];');
  206. WScript.RegisterModuleSource("CyclicRejection2", `
  207. import arr from 'CyclicRejection1';
  208. import 'CyclicRejection3';
  209. arr.push("CR1a1");
  210. await 0;
  211. arr.push("CR1a2");
  212. `);
  213. WScript.RegisterModuleSource("CyclicRejection3", `
  214. import arr from 'CyclicRejection1';
  215. import 'CyclicRejection2';
  216. arr.push("CR2a1");
  217. await Promise.reject('REJECTED');
  218. arr.push("CR2a2");
  219. `);
  220. AddPromise(test, import('CyclicRejection3'), "REJECTED", true);
  221. AddPromise(test, import('CyclicRejection3').catch(() => import('CyclicRejection1').then(x => x.default.toString())), "CR1a1,CR1a2,CR2a1", false);
  222. }
  223. },
  224. {
  225. name : "Test static loading",
  226. body (test) {
  227. WScript.RegisterModuleSource("Static", `
  228. import resolve from 'top-level-await.js';
  229. await 0;
  230. resolve("static pass");
  231. `);
  232. WScript.LoadScriptFile("Static", "module");
  233. AddPromise(test, firstPromise, "static pass", false);
  234. }
  235. },
  236. {
  237. name : "Root and dynamic",
  238. body (test) {
  239. WScript.RegisterModuleSource("Dynamic Root", `
  240. export let bar = 0;
  241. import {resolveTwo} from 'top-level-await.js';
  242. await 0;
  243. resolveTwo("other pass");
  244. `);
  245. WScript.LoadScriptFile("Dynamic Root", "module");
  246. AddPromise(test, import("Dynamic Root").then(x => x.bar), 0, false);
  247. AddPromise(test, secondPromise, "other pass", false);
  248. }
  249. },
  250. {
  251. name : "For-await-of in module",
  252. body (test) {
  253. WScript.RegisterModuleSource("for-await-of", `
  254. let out = 0;
  255. for await (const bar of [2,3,4]) {
  256. out += bar;
  257. }
  258. export default out;
  259. `);
  260. AddPromise(test, import('for-await-of').then (x => x.default), 9, false);
  261. }
  262. }
  263. ];
  264. for(let i = 0; i < tests.length; ++i)
  265. {
  266. const test = tests[i];
  267. test.body(`Test ${i + 1}: ${test.name}`);
  268. }
  269. Promise.all(promises).then(x => print("pass"), x => print (x));