module-namespace.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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 Module syntax tests -- verifies syntax of import and export statements
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. function testModuleScript(source, message, shouldFail = false) {
  8. let testfunc = () => testRunner.LoadModule(source, undefined, shouldFail);
  9. if (shouldFail) {
  10. let caught = false;
  11. // We can't use assert.throws here because the SyntaxError used to construct the thrown error
  12. // is from a different context so it won't be strictly equal to our SyntaxError.
  13. try {
  14. testfunc();
  15. } catch(e) {
  16. caught = true;
  17. // Compare toString output of SyntaxError and other context SyntaxError constructor.
  18. assert.areEqual(e.constructor.toString(), SyntaxError.toString(), message);
  19. }
  20. assert.isTrue(caught, `Expected error not thrown: ${message}`);
  21. } else {
  22. assert.doesNotThrow(testfunc, message);
  23. }
  24. }
  25. var tests = [
  26. {
  27. name: "Issue3249: Namespace object's property attributes",
  28. body: function () {
  29. testModuleScript(`
  30. function verifyPropertyDesc(obj, prop, desc, propName) {
  31. var actualDesc = Object.getOwnPropertyDescriptor(obj, prop);
  32. if (typeof propName === "undefined") { propName = prop; }
  33. assert.areEqual(desc.configurable, actualDesc.configurable, propName+"'s attribute: configurable");
  34. assert.areEqual(desc.enumerable, actualDesc.enumerable, propName+"'s attribute: enumerable");
  35. assert.areEqual(desc.writable, actualDesc.writable, propName+"'s attribute: writable");
  36. }
  37. import * as foo from "ValidExportStatements.js";
  38. assert.areEqual("Module", foo[Symbol.toStringTag], "@@toStringTag is the String value'Module'");
  39. verifyPropertyDesc(foo, Symbol.toStringTag, {configurable:false, enumerable: false, writable: false}, "Symbol.toStringTag");
  40. verifyPropertyDesc(foo, "default", {configurable:false, enumerable: true, writable: true});
  41. verifyPropertyDesc(foo, "var7", {configurable:false, enumerable: true, writable: true});
  42. verifyPropertyDesc(foo, "var6", {configurable:false, enumerable: true, writable: true});
  43. verifyPropertyDesc(foo, "var4", {configurable:false, enumerable: true, writable: true});
  44. verifyPropertyDesc(foo, "var3", {configurable:false, enumerable: true, writable: true});
  45. verifyPropertyDesc(foo, "var2", {configurable:false, enumerable: true, writable: true});
  46. verifyPropertyDesc(foo, "var1", {configurable:false, enumerable: true, writable: true});
  47. verifyPropertyDesc(foo, "foo4", {configurable:false, enumerable: true, writable: true});
  48. verifyPropertyDesc(foo, "bar2", {configurable:false, enumerable: true, writable: true});
  49. verifyPropertyDesc(foo, "foobar", {configurable:false, enumerable: true, writable: true});
  50. verifyPropertyDesc(foo, "foo3", {configurable:false, enumerable: true, writable: true});
  51. verifyPropertyDesc(foo, "baz2", {configurable:false, enumerable: true, writable: true});
  52. verifyPropertyDesc(foo, "foo2", {configurable:false, enumerable: true, writable: true});
  53. verifyPropertyDesc(foo, "baz", {configurable:false, enumerable: true, writable: true});
  54. verifyPropertyDesc(foo, "bar", {configurable:false, enumerable: true, writable: true});
  55. verifyPropertyDesc(foo, "foo", {configurable:false, enumerable: true, writable: true});
  56. verifyPropertyDesc(foo, "const6", {configurable:false, enumerable: true, writable: true});
  57. verifyPropertyDesc(foo, "const5", {configurable:false, enumerable: true, writable: true});
  58. verifyPropertyDesc(foo, "const4", {configurable:false, enumerable: true, writable: true});
  59. verifyPropertyDesc(foo, "const3", {configurable:false, enumerable: true, writable: true});
  60. verifyPropertyDesc(foo, "const2", {configurable:false, enumerable: true, writable: true});
  61. verifyPropertyDesc(foo, "let7", {configurable:false, enumerable: true, writable: true});
  62. verifyPropertyDesc(foo, "let6", {configurable:false, enumerable: true, writable: true});
  63. verifyPropertyDesc(foo, "let5", {configurable:false, enumerable: true, writable: true});
  64. verifyPropertyDesc(foo, "let4", {configurable:false, enumerable: true, writable: true});
  65. verifyPropertyDesc(foo, "let2", {configurable:false, enumerable: true, writable: true});
  66. verifyPropertyDesc(foo, "let1", {configurable:false, enumerable: true, writable: true});
  67. verifyPropertyDesc(foo, "cl2", {configurable:false, enumerable: true, writable: true});
  68. verifyPropertyDesc(foo, "cl1", {configurable:false, enumerable: true, writable: true});
  69. verifyPropertyDesc(foo, "gn2", {configurable:false, enumerable: true, writable: true});
  70. verifyPropertyDesc(foo, "gn1", {configurable:false, enumerable: true, writable: true});
  71. verifyPropertyDesc(foo, "fn2", {configurable:false, enumerable: true, writable: true});
  72. verifyPropertyDesc(foo, "fn1", {configurable:false, enumerable: true, writable: true});
  73. import * as foo1 from "ValidReExportStatements.js";
  74. verifyPropertyDesc(foo1, "foo", {configurable:false, enumerable: true, writable: true});
  75. verifyPropertyDesc(foo1, "bar", {configurable:false, enumerable: true, writable: true});
  76. verifyPropertyDesc(foo1, "baz", {configurable:false, enumerable: true, writable: true});
  77. verifyPropertyDesc(foo1, "foo2", {configurable:false, enumerable: true, writable: true});
  78. verifyPropertyDesc(foo1, "bar2", {configurable:false, enumerable: true, writable: true});
  79. verifyPropertyDesc(foo1, "foo3", {configurable:false, enumerable: true, writable: true});
  80. import * as foo2 from "ModuleComplexReexports.js";
  81. verifyPropertyDesc(foo2, "ModuleComplexReexports_foo", {configurable:false, enumerable: true, writable: true});
  82. verifyPropertyDesc(foo2, "bar2", {configurable:false, enumerable: true, writable: true});
  83. verifyPropertyDesc(foo2, "localfoo2", {configurable:false, enumerable: true, writable: true});
  84. verifyPropertyDesc(foo2, "bar", {configurable:false, enumerable: true, writable: true});
  85. verifyPropertyDesc(foo2, "localfoo", {configurable:false, enumerable: true, writable: true});
  86. verifyPropertyDesc(foo2, "baz", {configurable:false, enumerable: true, writable: true});
  87. verifyPropertyDesc(foo2, "foo", {configurable:false, enumerable: true, writable: true});
  88. `, '', false);
  89. }
  90. },
  91. {
  92. name: "Basic import namespace",
  93. body: function () {
  94. testModuleScript(`
  95. import * as foo from "ValidExportStatements.js";
  96. assert.areEqual("default", foo.default, "default");
  97. assert.areEqual(undefined, foo.var7, "var7");
  98. assert.areEqual(undefined, foo.var6, "var6");
  99. assert.areEqual(undefined, foo.var5, "var5");
  100. assert.areEqual(undefined, foo.var4, "var4");
  101. assert.areEqual(5, foo.var3, "var3");
  102. assert.areEqual(undefined, foo.var2, "var2");
  103. assert.areEqual("string", foo.var1, "var1");
  104. assert.areEqual("function foo() { }", foo.foo4.toString(), "foo4");
  105. assert.areEqual("class bar { }", foo.bar2.toString(), "bar2");
  106. assert.areEqual("function foobar() { }", foo.foobar.toString(), "foobar");
  107. assert.areEqual("function foo() { }", foo.foo3.toString(), "foo3");
  108. assert.areEqual("function* baz() { }", foo.baz2.toString(), "baz2");
  109. assert.areEqual("function foo() { }", foo.foo2.toString(), "foo2");
  110. assert.areEqual("function* baz() { }", foo.baz.toString(), "baz");
  111. assert.areEqual("class bar { }", foo.bar.toString(), "bar");
  112. assert.areEqual("function foo() { }", foo.foo.toString(), "foo");
  113. assert.areEqual([], foo.const6, "const6");
  114. assert.areEqual({}, foo.const5, "const5");
  115. assert.areEqual(4, foo.const4, "const4");
  116. assert.areEqual(3, foo.const3, "const3");
  117. assert.areEqual("str", foo.const2, "const2");
  118. assert.areEqual([], foo.let7, "let7");
  119. assert.areEqual({}, foo.let6, "let6");
  120. assert.areEqual(undefined, foo.let5, "let5");
  121. assert.areEqual(undefined, foo.let4, "let4");
  122. assert.areEqual(undefined, foo.let3, "let3");
  123. assert.areEqual(2, foo.let2, "let2");
  124. assert.areEqual(undefined, foo.let1, "let1");
  125. assert.areEqual("class cl2 { }", foo.cl2.toString(), "cl2");
  126. assert.areEqual("class cl1 { }", foo.cl1.toString(), "cl1");
  127. assert.areEqual("function* gn2() { }", foo.gn2.toString(), "gn2");
  128. assert.areEqual("function* gn1() { }", foo.gn1.toString(), "gn1");
  129. assert.areEqual("function fn2() { }", foo.fn2.toString(), "fn2");
  130. assert.areEqual("function fn1() { }", foo.fn1.toString(), "fn1");
  131. `, '', false);
  132. }
  133. },
  134. {
  135. name: "import namespace with verification",
  136. body: function () {
  137. testModuleScript(`
  138. import * as foo from "moduleExport1.js";
  139. assert.areEqual("default", foo.default, "default");
  140. assert.areEqual(undefined, foo.var7, "var7");
  141. assert.areEqual(undefined, foo.var6, "var6");
  142. assert.areEqual(undefined, foo.var5, "var5");
  143. assert.areEqual(undefined, foo.var4, "var4");
  144. assert.areEqual(5, foo.var3, "var3");
  145. assert.areEqual(undefined, foo.var2, "var2");
  146. assert.areEqual("string", foo.var1, "var1");
  147. assert.areEqual("function foo() { }", foo.foo4.toString(), "foo4");
  148. assert.areEqual("class bar { }", foo.bar2.toString(), "bar2");
  149. assert.areEqual("function foobar() { }", foo.foobar.toString(), "foobar");
  150. assert.areEqual("function foo() { }", foo.foo3.toString(), "foo3");
  151. assert.areEqual("function* baz() { }", foo.baz2.toString(), "baz2");
  152. assert.areEqual("function foo() { }", foo.foo2.toString(), "foo2");
  153. assert.areEqual("function* baz() { }", foo.baz.toString(), "baz");
  154. assert.areEqual("class bar { }", foo.bar.toString(), "bar");
  155. assert.areEqual("function foo() { }", foo.foo.toString(), "foo");
  156. assert.areEqual([], foo.const6, "const6");
  157. assert.areEqual({}, foo.const5, "const5");
  158. assert.areEqual(4, foo.const4, "const4");
  159. assert.areEqual(3, foo.const3, "const3");
  160. assert.areEqual("str", foo.const2, "const2");
  161. assert.areEqual([], foo.let7, "let7");
  162. assert.areEqual({}, foo.let6, "let6");
  163. assert.areEqual(undefined, foo.let5, "let5");
  164. assert.areEqual(undefined, foo.let4, "let4");
  165. assert.areEqual(undefined, foo.let3, "let3");
  166. assert.areEqual(2, foo.let2, "let2");
  167. assert.areEqual(undefined, foo.let1, "let1");
  168. assert.areEqual("class cl2 { }", foo.cl2.toString(), "cl2");
  169. assert.areEqual("class cl1 { }", foo.cl1.toString(), "cl1");
  170. assert.areEqual("function* gn2() { }", foo.gn2.toString(), "gn2");
  171. assert.areEqual("function* gn1() { }", foo.gn1.toString(), "gn1");
  172. assert.areEqual("function fn2() { }", foo.fn2.toString(), "fn2");
  173. assert.areEqual("function fn1() { }", foo.fn1.toString(), "fn1");
  174. foo.verifyNamespace(foo);
  175. foo.changeContext();
  176. foo.verifyNamespace(foo);
  177. `, '', false);
  178. }
  179. },
  180. {
  181. name: "reexport only",
  182. body: function () {
  183. testModuleScript(`
  184. import * as foo from "ValidReExportStatements.js";
  185. assert.areEqual("function foo() { }", foo.foo.toString(), "foo");
  186. assert.areEqual("class bar { }", foo.bar.toString(), "bar");
  187. assert.areEqual("function* baz() { }", foo.baz.toString(), "baz");
  188. assert.areEqual("function foo() { }", foo.foo2.toString(), "foo2");
  189. assert.areEqual("class bar { }", foo.bar2.toString(), "bar2");
  190. assert.areEqual("function foo() { }", foo.foo3.toString(), "foo3");
  191. `, '', false);
  192. }
  193. },
  194. {
  195. name: "complex reexport",
  196. body: function () {
  197. testModuleScript(`import * as fooComplex from "ModuleComplexReexports.js";
  198. assert.areEqual("function bar() { return 'bar'; }", fooComplex.ModuleComplexReexports_foo.toString(), "ModuleComplexReexports_foo");
  199. assert.areEqual(undefined, fooComplex.switch, "switch");
  200. assert.areEqual("function foo() { return 'foo'; }", fooComplex.bar2.toString(), "bar2");
  201. assert.areEqual("function foo() { return 'foo'; }", fooComplex.localfoo2.toString(), "localfoo2");
  202. assert.areEqual("function foo() { return 'foo'; }", fooComplex.bar.toString(), "bar");
  203. assert.areEqual("function foo() { return 'foo'; }", fooComplex.localfoo.toString(), "localfoo");
  204. assert.areEqual("function foo() { return 'foo'; }", fooComplex.baz.toString(), "baz");
  205. assert.areEqual("function foo() { return 'foo'; }", fooComplex.foo.toString(), "foo");
  206. `, '', false);
  207. }
  208. },
  209. {
  210. name: "namespace as prototype",
  211. body: function () {
  212. testModuleScript(`import * as foo from "ValidExportStatements.js";
  213. var childObj = Object.create(foo);
  214. assert.areEqual("default", childObj.default, "default");
  215. assert.areEqual(undefined, childObj.var7, "var7");
  216. assert.areEqual(undefined, childObj.var6, "var6");
  217. assert.areEqual(undefined, childObj.var5, "var5");
  218. assert.areEqual(undefined, childObj.var4, "var4");
  219. assert.areEqual(5, childObj.var3, "var3");
  220. assert.areEqual(undefined, childObj.var2, "var2");
  221. assert.areEqual("string", childObj.var1, "var1");
  222. assert.areEqual("function foo() { }", childObj.foo4.toString(), "foo4");
  223. assert.areEqual("class bar { }", childObj.bar2.toString(), "bar2");
  224. assert.areEqual("function foobar() { }", childObj.foobar.toString(), "foobar");
  225. assert.areEqual("function foo() { }", childObj.foo3.toString(), "foo3");
  226. assert.areEqual("function* baz() { }", childObj.baz2.toString(), "baz2");
  227. assert.areEqual("function foo() { }", childObj.foo2.toString(), "foo2");
  228. assert.areEqual("function* baz() { }", childObj.baz.toString(), "baz");
  229. assert.areEqual("class bar { }", childObj.bar.toString(), "bar");
  230. assert.areEqual("function foo() { }", childObj.foo.toString(), "foo");
  231. assert.areEqual([], childObj.const6, "const6");
  232. assert.areEqual({}, childObj.const5, "const5");
  233. assert.areEqual(4, childObj.const4, "const4");
  234. assert.areEqual(3, childObj.const3, "const3");
  235. assert.areEqual("str", childObj.const2, "const2");
  236. assert.areEqual([], childObj.let7, "let7");
  237. assert.areEqual({}, childObj.let6, "let6");
  238. assert.areEqual(undefined, childObj.let5, "let5");
  239. assert.areEqual(undefined, childObj.let4, "let4");
  240. assert.areEqual(undefined, childObj.let3, "let3");
  241. assert.areEqual(2, childObj.let2, "let2");
  242. assert.areEqual(undefined, childObj.let1, "let1");
  243. assert.areEqual("class cl2 { }", childObj.cl2.toString(), "cl2");
  244. assert.areEqual("class cl1 { }", childObj.cl1.toString(), "cl1");
  245. assert.areEqual("function* gn2() { }", childObj.gn2.toString(), "gn2");
  246. assert.areEqual("function* gn1() { }", childObj.gn1.toString(), "gn1");
  247. assert.areEqual("function fn2() { }", childObj.fn2.toString(), "fn2");
  248. assert.areEqual("function fn1() { }", childObj.fn1.toString(), "fn1");
  249. `, '', false);
  250. }
  251. },
  252. {
  253. name: "namespace internal operations",
  254. body: function () {
  255. let functionBody =
  256. `import * as foo from "ValidExportStatements.js";
  257. assert.areEqual(null, Object.getPrototypeOf(foo), 'namespace prototype is null');
  258. assert.areEqual(false, Object.isExtensible(foo), 'namespace is not extensible');
  259. assert.areEqual(false, Reflect.set(foo, "non_existing", 20), '[[set]] returns false ');
  260. assert.areEqual(undefined, foo.non_existing, 'namespace object is immutable');
  261. assert.areEqual(false, Reflect.set(foo, "4", 20), 'cannot set item in namespace obect');
  262. assert.areEqual(undefined, foo[4], 'cannot export item in namespace obect');
  263. assert.areEqual(false, Reflect.deleteProperty(foo, "var1"), 'cannot delete export in namespace obect');
  264. assert.areEqual(true, Reflect.deleteProperty(foo, "nonevar"), 'cannot delete export in namespace obect');
  265. assert.areEqual(undefined, foo[6], 'cannot get item in namespace obect');
  266. assert.areEqual(false, Reflect.set(foo, Symbol.species, 20), 'no species property');
  267. assert.areEqual(undefined, foo[Symbol.species], 'namespace is not contructor');
  268. assert.areEqual("Module", foo[Symbol.toStringTag], 'namespace toStringTag');
  269. assert.areEqual("[object Module]", Object.prototype.toString.call(foo), 'Object.prototype.toString uses the module namespace @@toStringTag value');
  270. var symbols = Object.getOwnPropertySymbols(foo);
  271. assert.areEqual(1, symbols.length, "one symbol");
  272. assert.areEqual(symbols[0], Symbol.toStringTag, "first symbol is toStringTag");
  273. assert.isFalse(Object.prototype.hasOwnProperty.call(foo, Symbol.iterator), "Module namespace object should not have Symbol.iterator property");
  274. assert.throws( function() {Object.setPrototypeOf(foo, Object)}, TypeError, 'Cannot create property for a non-extensible object');
  275. assert.areEqual(true, Reflect.preventExtensions(foo), '[[PreventExtensions]] for namespace object returns true');`;
  276. testModuleScript(functionBody, "Test importing as different binding identifiers", false);
  277. }
  278. },
  279. {
  280. name: "Issue3246: namespace property names are sorted",
  281. body: function () {
  282. let functionBody =
  283. `
  284. import * as ns from 'ValidExportStatements2.js';
  285. var p = new Proxy(ns, {});
  286. var names = ["sym0","default","$","$$","_","\u03bb","aa","A","a","zz","z","\u03bc","Z","za","__","az","\u03c0"].sort();
  287. var verifyNamespaceOwnProperty = function(obj, objKind) {
  288. assert.areEqual(names, Object.getOwnPropertyNames(obj), objKind+" getOwnPropertyNames()");
  289. var propDesc = Object.getOwnPropertyDescriptors(obj);
  290. assert.areEqual('{"value":"Module","writable":false,"enumerable":false,"configurable":false}', JSON.stringify(propDesc[Symbol.toStringTag]),
  291. objKind+" getOwnPropertyDescriptors() @@toStringTag");
  292. assert.areEqual(names, Object.keys(propDesc), "ModuleNamespace", objKind+" getOwnPropertyDescriptors()");
  293. };
  294. verifyNamespaceOwnProperty(ns, "ModuleNamespace");
  295. verifyNamespaceOwnProperty(p, "Proxy");
  296. var propEn = [];
  297. for (var k in ns) { propEn.push(k); }
  298. assert.areEqual(names, propEn, "ModuleNamespace enumerator");
  299. `;
  300. testModuleScript(functionBody, "Test importing as different binding identifiers", false);
  301. }
  302. },
  303. ];
  304. testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });