summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibJS/Tests/modules
diff options
context:
space:
mode:
authordavidot <davidot@serenityos.org>2022-01-18 19:39:36 +0100
committerLinus Groh <mail@linusgroh.de>2022-01-22 01:21:18 +0000
commit7cbf4b90e872776adcd05ac9150b6f745606aaae (patch)
tree6622fc7fef053fdf810fbc7d2d4a331c7c1bf435 /Userland/Libraries/LibJS/Tests/modules
parent023968a489fdc281ec2bd7f1f04a8bc5a1065cbc (diff)
downloadserenity-7cbf4b90e872776adcd05ac9150b6f745606aaae.zip
LibJS: Implement ImportCall and HostImportModuleDynamically
This allows us to load modules from scripts. This can be dangerous as it can load arbitrary files. Because of that it fails and throws by default. Currently, only js and JavaScriptTestRunner enable the default hook. This also adds tests to test-js which test module code. Because we form a spec perspective can't "enter" a module this is the easiest way to run tests without having to modify test-js to have special cases for modules. To specify modules in test-js we use the extension '.mjs' this is to ensure the files are not executed. We do still want to lint these files so the prettier scripts have changed to look for '.mjs' files as well.
Diffstat (limited to 'Userland/Libraries/LibJS/Tests/modules')
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/basic-export-types.mjs13
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/basic-modules.js144
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/declarations-tests.mjs28
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/empty.mjs0
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/loop-a.mjs3
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/loop-b.mjs3
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/loop-entry.mjs3
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/loop-self.mjs5
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/module-with-default.mjs7
-rw-r--r--Userland/Libraries/LibJS/Tests/modules/single-const-export.mjs1
10 files changed, 207 insertions, 0 deletions
diff --git a/Userland/Libraries/LibJS/Tests/modules/basic-export-types.mjs b/Userland/Libraries/LibJS/Tests/modules/basic-export-types.mjs
new file mode 100644
index 0000000000..68f45e2342
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/basic-export-types.mjs
@@ -0,0 +1,13 @@
+export const constValue = 1;
+
+export let letValue = 2;
+
+export var varValue = 3;
+
+const namedConstValue = 4;
+let namedLetValue = 5;
+var namedVarValue = 6;
+
+export { namedConstValue, namedLetValue, namedVarValue };
+
+export const passed = true;
diff --git a/Userland/Libraries/LibJS/Tests/modules/basic-modules.js b/Userland/Libraries/LibJS/Tests/modules/basic-modules.js
new file mode 100644
index 0000000000..7693b1df14
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/basic-modules.js
@@ -0,0 +1,144 @@
+// Because you can't easily load modules directly we load them via here and check
+// if they passed by checking the result
+
+function expectModulePassed(filename) {
+ if (!filename.endsWith(".mjs") || !filename.startsWith("./")) {
+ throw new ExpectationError(
+ "Expected module name to start with './' " +
+ "and end with '.mjs' but got '" +
+ filename +
+ "'"
+ );
+ }
+
+ async function getModule() {
+ return import(filename);
+ }
+
+ let moduleLoaded = false;
+ let moduleResult = null;
+ let thrownError = null;
+
+ getModule()
+ .then(result => {
+ moduleLoaded = true;
+ moduleResult = result;
+ expect(moduleResult).toHaveProperty("passed", true);
+ })
+ .catch(error => {
+ thrownError = error;
+ });
+
+ runQueuedPromiseJobs();
+
+ if (thrownError) {
+ throw thrownError;
+ }
+
+ expect(moduleLoaded).toBeTrue();
+
+ return moduleResult;
+}
+
+describe("testing behavior", () => {
+ // To ensure the other tests are interpreter correctly we first test the underlying
+ // mechanisms so these tests don't use expectModulePassed.
+
+ test("can load a module", () => {
+ let passed = false;
+ let error = null;
+
+ import("./empty.mjs")
+ .then(() => {
+ passed = true;
+ })
+ .catch(err => {
+ error = err;
+ });
+
+ runQueuedPromiseJobs();
+ if (error) throw error;
+
+ expect(passed).toBeTrue();
+ });
+
+ test("can load a module twice", () => {
+ let passed = false;
+ let error = null;
+
+ import("./empty.mjs")
+ .then(() => {
+ passed = true;
+ })
+ .catch(err => {
+ error = err;
+ });
+
+ runQueuedPromiseJobs();
+ if (error) throw error;
+
+ expect(passed).toBeTrue();
+ });
+
+ test("can retrieve exported value", () => {
+ async function getValue(filename) {
+ const imported = await import(filename);
+ expect(imported).toHaveProperty("passed", true);
+ }
+
+ let passed = false;
+ let error = null;
+
+ getValue("./single-const-export.mjs")
+ .then(obj => {
+ passed = true;
+ })
+ .catch(err => {
+ error = err;
+ });
+
+ runQueuedPromiseJobs();
+
+ if (error) throw error;
+
+ expect(passed).toBeTrue();
+ });
+
+ test("expectModulePassed works", () => {
+ expectModulePassed("./single-const-export.mjs");
+ });
+});
+
+describe("in- and exports", () => {
+ test("variable and lexical declarations", () => {
+ const result = expectModulePassed("./basic-export-types.mjs");
+ expect(result).not.toHaveProperty("default", null);
+ expect(result).toHaveProperty("constValue", 1);
+ expect(result).toHaveProperty("letValue", 2);
+ expect(result).toHaveProperty("varValue", 3);
+
+ expect(result).toHaveProperty("namedConstValue", 1 + 3);
+ expect(result).toHaveProperty("namedLetValue", 2 + 3);
+ expect(result).toHaveProperty("namedVarValue", 3 + 3);
+ });
+
+ test("default exports", () => {
+ const result = expectModulePassed("./module-with-default.mjs");
+ expect(result).toHaveProperty("defaultValue");
+ expect(result.default).toBe(result.defaultValue);
+ });
+
+ test("declaration exports which can be used in the module it self", () => {
+ expectModulePassed("./declarations-tests.mjs");
+ });
+});
+
+describe("loops", () => {
+ test("import and export from own file", () => {
+ expectModulePassed("./loop-self.mjs");
+ });
+
+ test("import something which imports a cycle", () => {
+ expectModulePassed("./loop-entry.mjs");
+ });
+});
diff --git a/Userland/Libraries/LibJS/Tests/modules/declarations-tests.mjs b/Userland/Libraries/LibJS/Tests/modules/declarations-tests.mjs
new file mode 100644
index 0000000000..1cccb86b8b
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/declarations-tests.mjs
@@ -0,0 +1,28 @@
+export function returnsOne() {
+ return 1;
+}
+
+export class hasStaticFieldTwo {
+ static two = 2;
+}
+
+const expectedValue = 10;
+const didNotHoistClass = (() => {
+ try {
+ new ShouldNotBeHoisted();
+ } catch (e) {
+ if (e instanceof ReferenceError) return 4;
+ }
+ return 0;
+})();
+
+export const passed =
+ returnsOne() + hasStaticFieldTwo.two + shouldBeHoisted() + didNotHoistClass === expectedValue;
+
+export function shouldBeHoisted() {
+ return 3;
+}
+
+export class ShouldNotBeHoisted {
+ static no = 5;
+}
diff --git a/Userland/Libraries/LibJS/Tests/modules/empty.mjs b/Userland/Libraries/LibJS/Tests/modules/empty.mjs
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/empty.mjs
diff --git a/Userland/Libraries/LibJS/Tests/modules/loop-a.mjs b/Userland/Libraries/LibJS/Tests/modules/loop-a.mjs
new file mode 100644
index 0000000000..fc994711f7
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/loop-a.mjs
@@ -0,0 +1,3 @@
+export { bValue } from "./loop-b.mjs";
+
+export const aValue = 1;
diff --git a/Userland/Libraries/LibJS/Tests/modules/loop-b.mjs b/Userland/Libraries/LibJS/Tests/modules/loop-b.mjs
new file mode 100644
index 0000000000..68151b4d85
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/loop-b.mjs
@@ -0,0 +1,3 @@
+import "./loop-a.mjs";
+
+export const bValue = 2;
diff --git a/Userland/Libraries/LibJS/Tests/modules/loop-entry.mjs b/Userland/Libraries/LibJS/Tests/modules/loop-entry.mjs
new file mode 100644
index 0000000000..c5e7f77ee7
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/loop-entry.mjs
@@ -0,0 +1,3 @@
+import { aValue, bValue } from "./loop-a.mjs";
+
+export const passed = aValue < bValue;
diff --git a/Userland/Libraries/LibJS/Tests/modules/loop-self.mjs b/Userland/Libraries/LibJS/Tests/modules/loop-self.mjs
new file mode 100644
index 0000000000..a37da73982
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/loop-self.mjs
@@ -0,0 +1,5 @@
+import { value as importValue } from "./loop-self.mjs";
+
+export const value = "loop de loop whooo";
+
+export const passed = value === importValue;
diff --git a/Userland/Libraries/LibJS/Tests/modules/module-with-default.mjs b/Userland/Libraries/LibJS/Tests/modules/module-with-default.mjs
new file mode 100644
index 0000000000..bcce016479
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/module-with-default.mjs
@@ -0,0 +1,7 @@
+const value = "Well hello importer :^)";
+
+export const defaultValue = value;
+
+export default value;
+
+export const passed = true;
diff --git a/Userland/Libraries/LibJS/Tests/modules/single-const-export.mjs b/Userland/Libraries/LibJS/Tests/modules/single-const-export.mjs
new file mode 100644
index 0000000000..58c9069908
--- /dev/null
+++ b/Userland/Libraries/LibJS/Tests/modules/single-const-export.mjs
@@ -0,0 +1 @@
+export const passed = true;