basic-modules.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // Because you can't easily load modules directly we load them via here and check
  2. // if they passed by checking the result
  3. function validTestModule(filename) {
  4. if (!filename.endsWith(".mjs") || !filename.startsWith("./")) {
  5. throw new ExpectationError(
  6. `Expected module name to start with './' and end with '.mjs' but got '${filename}'`
  7. );
  8. }
  9. }
  10. function expectModulePassed(filename, options = undefined) {
  11. validTestModule(filename);
  12. let moduleLoaded = false;
  13. let moduleResult = null;
  14. let thrownError = null;
  15. import(filename, options)
  16. .then(result => {
  17. moduleLoaded = true;
  18. moduleResult = result;
  19. expect(moduleResult).toHaveProperty("passed", true);
  20. })
  21. .catch(error => {
  22. thrownError = error;
  23. });
  24. runQueuedPromiseJobs();
  25. if (thrownError) {
  26. throw thrownError;
  27. }
  28. expect(moduleLoaded).toBeTrue();
  29. return moduleResult;
  30. }
  31. function expectedModuleToThrowSyntaxError(filename, message) {
  32. validTestModule(filename);
  33. let moduleLoaded = false;
  34. let thrownError = null;
  35. import(filename)
  36. .then(() => {
  37. moduleLoaded = true;
  38. })
  39. .catch(error => {
  40. thrownError = error;
  41. });
  42. runQueuedPromiseJobs();
  43. if (thrownError) {
  44. expect(() => {
  45. throw thrownError;
  46. }).toThrowWithMessage(SyntaxError, message);
  47. } else {
  48. throw new ExpectationError(
  49. `Expected module: '${filename}' to fail to load with a syntax error but did not throw.`
  50. );
  51. }
  52. }
  53. describe("testing behavior", () => {
  54. // To ensure the other tests are interpreter correctly we first test the underlying
  55. // mechanisms so these tests don't use expectModulePassed.
  56. test("can load a module", () => {
  57. let passed = false;
  58. let error = null;
  59. import("./empty.mjs")
  60. .then(() => {
  61. passed = true;
  62. })
  63. .catch(err => {
  64. error = err;
  65. });
  66. runQueuedPromiseJobs();
  67. if (error) throw error;
  68. expect(passed).toBeTrue();
  69. });
  70. test("can load a module twice", () => {
  71. let passed = false;
  72. let error = null;
  73. import("./empty.mjs")
  74. .then(() => {
  75. passed = true;
  76. })
  77. .catch(err => {
  78. error = err;
  79. });
  80. runQueuedPromiseJobs();
  81. if (error) throw error;
  82. expect(passed).toBeTrue();
  83. });
  84. test("can retrieve exported value", () => {
  85. async function getValue(filename) {
  86. const imported = await import(filename);
  87. expect(imported).toHaveProperty("passed", true);
  88. }
  89. let passed = false;
  90. let error = null;
  91. getValue("./single-const-export.mjs")
  92. .then(obj => {
  93. passed = true;
  94. })
  95. .catch(err => {
  96. error = err;
  97. });
  98. runQueuedPromiseJobs();
  99. if (error) throw error;
  100. expect(passed).toBeTrue();
  101. });
  102. test("expectModulePassed works", () => {
  103. expectModulePassed("./single-const-export.mjs");
  104. });
  105. test("can call expectModulePassed with options", () => {
  106. expectModulePassed("./single-const-export.mjs", { key: "value" });
  107. expectModulePassed("./single-const-export.mjs", { key1: "value1", key2: "value2" });
  108. });
  109. });
  110. describe("in- and exports", () => {
  111. test("variable and lexical declarations", () => {
  112. const result = expectModulePassed("./basic-export-types.mjs");
  113. expect(result).not.toHaveProperty("default", null);
  114. expect(result).toHaveProperty("constValue", 1);
  115. expect(result).toHaveProperty("letValue", 2);
  116. expect(result).toHaveProperty("varValue", 3);
  117. expect(result).toHaveProperty("namedConstValue", 1 + 3);
  118. expect(result).toHaveProperty("namedLetValue", 2 + 3);
  119. expect(result).toHaveProperty("namedVarValue", 3 + 3);
  120. });
  121. test("default exports", () => {
  122. const result = expectModulePassed("./module-with-default.mjs");
  123. expect(result).toHaveProperty("defaultValue");
  124. expect(result.default).toBe(result.defaultValue);
  125. });
  126. test("declaration exports which can be used in the module it self", () => {
  127. expectModulePassed("./declarations-tests.mjs");
  128. });
  129. test("string '*' is not a full namespace import", () => {
  130. expectModulePassed("./string-import-names.mjs");
  131. });
  132. test("can combine string and default exports", () => {
  133. expectModulePassed("./string-import-namespace.mjs");
  134. });
  135. test("can re export string names", () => {
  136. expectModulePassed("./string-import-namespace-indirect.mjs");
  137. });
  138. test("re exporting all-but-default does not export a default value", () => {
  139. expectedModuleToThrowSyntaxError(
  140. "./indirect-export-without-default.mjs",
  141. "Invalid or ambiguous export entry 'default'"
  142. );
  143. });
  144. test("can import with (useless) assertions", () => {
  145. expectModulePassed("./import-with-assertions.mjs");
  146. });
  147. });
  148. describe("loops", () => {
  149. test("import and export from own file", () => {
  150. expectModulePassed("./loop-self.mjs");
  151. });
  152. test("import something which imports a cycle", () => {
  153. expectModulePassed("./loop-entry.mjs");
  154. });
  155. });