Bug 1240072 - Test code for loading JS module from chrome r=sicking
authorJon Coppeard <jcoppeard@mozilla.com>
Sat, 07 May 2016 12:46:39 +0100
changeset 337545 61120e909d9aab88a411ce1fe6252e7631637339
parent 337544 a17704b72dd7051a82ef5cd4b522f4529b72bf94
child 337546 6b064f9f6e10b25bf2edc916b1b9a8b78cff0465
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs1240072
milestone49.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1240072 - Test code for loading JS module from chrome r=sicking
dom/base/test/jsmodules/chrome.ini
dom/base/test/jsmodules/mochitest.ini
dom/base/test/jsmodules/module_badImport.js
dom/base/test/jsmodules/module_badSyntax.js
dom/base/test/jsmodules/module_cyclic1.js
dom/base/test/jsmodules/module_cyclic2.js
dom/base/test/jsmodules/module_cyclic3.js
dom/base/test/jsmodules/module_large1.js
dom/base/test/jsmodules/module_large2.js
dom/base/test/jsmodules/module_large3.js
dom/base/test/jsmodules/module_multiImports.js
dom/base/test/jsmodules/module_multiLargeImports.js
dom/base/test/jsmodules/module_setRan.js
dom/base/test/jsmodules/module_simple1.js
dom/base/test/jsmodules/module_simple2.js
dom/base/test/jsmodules/module_simple3.js
dom/base/test/jsmodules/module_simpleExport.js
dom/base/test/jsmodules/module_simpleImport.js
dom/base/test/jsmodules/module_testSyntax.js
dom/base/test/jsmodules/moz.build
dom/base/test/jsmodules/script_simple2.js
dom/base/test/jsmodules/test_asyncInlineModules.html
dom/base/test/jsmodules/test_cyclicImport.html
dom/base/test/jsmodules/test_importNotFound.html
dom/base/test/jsmodules/test_importResolveFailed.html
dom/base/test/jsmodules/test_importedModuleMemoization.html
dom/base/test/jsmodules/test_moduleNotFound.html
dom/base/test/jsmodules/test_moduleParsedAsModule.html
dom/base/test/jsmodules/test_moduleScriptsNotRun.html
dom/base/test/jsmodules/test_moduleScriptsRun.html
dom/base/test/jsmodules/test_multiAsyncImports.html
dom/base/test/jsmodules/test_multiModuleImports.html
dom/base/test/jsmodules/test_multiModuleLargeImports.html
dom/base/test/jsmodules/test_multiTopLevelImports.html
dom/base/test/jsmodules/test_multiTopLevelLargeImports.html
dom/base/test/jsmodules/test_scriptInsertedModule.html
dom/base/test/jsmodules/test_scriptModuleOrder.html
dom/base/test/jsmodules/test_scriptNotParsedAsModule.html
dom/base/test/jsmodules/test_simpleImport.html
dom/base/test/jsmodules/test_syntaxError.html
dom/base/test/jsmodules/test_syntaxErrorAsync.html
dom/base/test/jsmodules/test_syntaxErrorInline.html
dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html
dom/base/test/jsmodules/test_toplevelModuleMemoization.html
dom/base/test/jsmodules/test_typeAttrCaseInsensitive.html
dom/base/test/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/chrome.ini
@@ -0,0 +1,44 @@
+[DEFAULT]
+support-files =
+  module_setRan.js
+  module_testSyntax.js
+  module_badSyntax.js
+  module_simpleImport.js
+  module_simpleExport.js
+  module_badImport.js
+  module_simple1.js
+  module_simple2.js
+  module_simple3.js
+  module_cyclic1.js
+  module_cyclic2.js
+  module_cyclic3.js
+  module_multiImports.js
+  module_multiLargeImports.js
+  script_simple2.js
+  module_large1.js
+  module_large2.js
+  module_large3.js
+
+[test_moduleScriptsRun.html]
+[test_moduleParsedAsModule.html]
+[test_scriptNotParsedAsModule.html]
+[test_typeAttrCaseInsensitive.html]
+[test_moduleNotFound.html]
+[test_importNotFound.html]
+[test_syntaxError.html]
+[test_syntaxErrorAsync.html]
+[test_syntaxErrorInline.html]
+[test_syntaxErrorInlineAsync.html]
+[test_simpleImport.html]
+[test_cyclicImport.html]
+[test_importResolveFailed.html]
+[test_multiTopLevelImports.html]
+[test_multiModuleImports.html]
+[test_multiAsyncImports.html]
+[test_scriptModuleOrder.html]
+[test_toplevelModuleMemoization.html]
+[test_importedModuleMemoization.html]
+[test_multiTopLevelLargeImports.html]
+[test_multiModuleLargeImports.html]
+[test_asyncInlineModules.html]
+[test_scriptInsertedModule.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/mochitest.ini
@@ -0,0 +1,5 @@
+[DEFAULT]
+support-files =
+  module_setRan.js
+
+[test_moduleScriptsNotRun.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_badImport.js
@@ -0,0 +1,1 @@
+import "invalid specifier";
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_badSyntax.js
@@ -0,0 +1,3 @@
+// Module with a syntax error.
+some invalid js syntax;
+wasRun = true;
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_cyclic1.js
@@ -0,0 +1,7 @@
+import { func2 } from "./module_cyclic2.js";
+
+export function func1(x, y) {
+    if (x <= 0)
+        return y;
+    return func2(x - 1, y + "1");
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_cyclic2.js
@@ -0,0 +1,7 @@
+import { func3 } from "./module_cyclic3.js";
+
+export function func2(x, y) {
+    if (x <= 0)
+        return y;
+    return func3(x - 1, y + "2");
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_cyclic3.js
@@ -0,0 +1,7 @@
+import { func1 } from "./module_cyclic1.js";
+
+export function func3(x, y) {
+    if (x <= 0)
+        return y;
+    return func1(x - 1, y + "3");
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_large1.js
@@ -0,0 +1,78 @@
+/*
+ * Scripts larger than 5KB may be compiled off main thread.  This is such a
+ * script.
+ *
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ */
+
+results.push(1);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_large2.js
@@ -0,0 +1,78 @@
+/*
+ * Scripts larger than 5KB may be compiled off main thread.  This is such a
+ * script.
+ *
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ */
+
+results.push(2);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_large3.js
@@ -0,0 +1,78 @@
+/*
+ * Scripts larger than 5KB may be compiled off main thread.  This is such a
+ * script.
+ *
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ * large large large large large large large large large large large large
+ */
+
+results.push(3);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_multiImports.js
@@ -0,0 +1,4 @@
+import "./module_simple1.js";
+import "./module_simple2.js";
+import "./module_simple3.js";
+results.push(4);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_multiLargeImports.js
@@ -0,0 +1,4 @@
+import "./module_large1.js";
+import "./module_large2.js";
+import "./module_large3.js";
+results.push(4);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_setRan.js
@@ -0,0 +1,2 @@
+// Set a global flag to indicate that this module was executed.
+moduleRan = true;
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simple1.js
@@ -0,0 +1,1 @@
+results.push(1);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simple2.js
@@ -0,0 +1,1 @@
+results.push(2);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simple3.js
@@ -0,0 +1,1 @@
+results.push(3);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simpleExport.js
@@ -0,0 +1,1 @@
+export let x = 42;
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_simpleImport.js
@@ -0,0 +1,2 @@
+import { x } from "./module_simpleExport.js"
+result = x;
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/module_testSyntax.js
@@ -0,0 +1,3 @@
+// Module that throws a syntax error if parsed as a script.
+export default 1;
+wasRun = true;
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOCHITEST_MANIFESTS += [
+    'mochitest.ini'
+]
+
+MOCHITEST_CHROME_MANIFESTS += [
+    'chrome.ini'
+]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/script_simple2.js
@@ -0,0 +1,1 @@
+results.push(2);
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_asyncInlineModules.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test async inline modules</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results.sort(), [1, 2, 3]), 'Check modules imported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" async>
+  results.push(1);
+</script>
+<script type="module" async>
+  import "./module_simple2.js";
+</script>
+<script type="module" async>
+  results.push(3);
+</script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_cyclicImport.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test cyclic module imports</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var result;
+
+  SimpleTest.waitForExplicitFinish();
+
+  function testLoaded() {
+    SimpleTest.finish();
+  }
+</script>
+<script type="module">
+  import { func1 } from "./module_cyclic1.js";
+  ok(func1(5, "") == "12312");
+</script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_importNotFound.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test what happens when a module import is not found</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var errorCount = 0;
+  var eventCount = 0;
+
+  SimpleTest.waitForExplicitFinish();
+
+  window.onerror = function(message, url, line, column, error) {
+    errorCount++;
+  }
+
+  function testError() {
+    ok(!wasRun, 'Check script was not run');
+    ok(eventCount == 1, 'Check that an error event was fired');
+    ok(errorCount == 0, 'Check that no error was reported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" onerror="eventCount++">
+import "./nonExistentModule.js";
+wasRun = true;
+</script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_importResolveFailed.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test error thrown when an import cannot be resolved</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var hadTypeError = false;
+
+  SimpleTest.waitForExplicitFinish();
+  window.onerror = handleError;
+
+  function handleError(message, url, line, column, error) {
+    hadTypeError = error instanceof TypeError;
+  }
+
+  function testError() {
+    ok(hadTypeError, 'Check that a TypeError was thrown');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_badImport.js"></script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_importedModuleMemoization.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test imported modules are momoized and only loaded once</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results, [1, 2, 3, 4]), 'Check modules only evaluated once');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_multiImports.js"></script>
+<script type="module" src="module_multiImports.js"></script>
+<script type="module" src="module_multiImports.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_moduleNotFound.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test what happens when a top-level module is not found</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var errorCount = 0;
+  var eventCount = 0;
+
+  SimpleTest.waitForExplicitFinish();
+
+  window.onerror = function(message, url, line, column, error) {
+    errorCount++;
+  }
+
+  function testError() {
+    ok(eventCount == 1, 'Check that an error event was fired');
+    ok(errorCount == 0, 'Check that no error was reported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="./nonExistentModule.js" onerror="eventCount++">
+</script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_moduleParsedAsModule.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test module script parsed as module</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var hadSyntaxError = false;
+
+  SimpleTest.waitForExplicitFinish();
+  window.onerror = handleError;
+
+  function handleError(message, url, line, column, error) {
+    hadSyntaxError = error instanceof SyntaxError;
+  }
+
+  function testError() {
+    ok(wasRun, 'Check module was run');
+    ok(!hadSyntaxError, 'Check that no SyntaxError was thrown');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_testSyntax.js"></script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_moduleScriptsNotRun.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test script elements with type="module" are not run for content HTML</title>
+<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var inlineModuleRan = false;
+  var moduleRan = false;
+
+  SimpleTest.waitForExplicitFinish();
+
+  function testLoaded() {
+    ok(!moduleRan, "Check module script was not run");
+    ok(!inlineModuleRan, "Check inline module script was not run");
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_setRan.js"></script>
+<script type="module">inlineModuleRan = true;</script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_moduleScriptsRun.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test script elements with type="module" are run for chrome HTML</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var inlineModuleRan = false;
+  var moduleRan = false;
+
+  SimpleTest.waitForExplicitFinish();
+
+  function testLoaded() {
+    ok(moduleRan, 'Check module script was run');
+    ok(inlineModuleRan, 'Check inline module script was run');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_setRan.js"></script>
+<script type="module">inlineModuleRan = true;</script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiAsyncImports.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a loading multiple modules with the async attribute from top level</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results.sort(), [1, 2, 3]), 'Check modules imported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_simple1.js" async></script>
+<script type="module" src="module_simple2.js" async></script>
+<script type="module" src="module_simple3.js" async></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiModuleImports.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a importing multiple modules from a module</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results, [1, 2, 3, 4]), 'Check modules imported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_multiImports.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiModuleLargeImports.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test importing multiple large modules which may be compiled off main thread from a module</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results, [1, 2, 3, 4]), 'Check modules imported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_multiLargeImports.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiTopLevelImports.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test importing multiple modules from top level</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results, [1, 2, 3]), 'Check modules imported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_simple1.js"></script>
+<script type="module" src="module_simple2.js"></script>
+<script type="module" src="module_simple3.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_multiTopLevelLargeImports.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a importing large modules which may be compiled off main thread</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results, [1, 2, 3]), 'Check modules imported');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_large1.js"></script>
+<script type="module" src="module_simple2.js"></script>
+<script type="module" src="module_large3.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_scriptInsertedModule.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a script-inserted module</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var result;
+
+  let script = document.createElement("script");
+  script.type = "module";
+  script.src = "./module_simpleImport.js";
+  document.head.appendChild(script);
+
+  SimpleTest.waitForExplicitFinish();
+
+  function testLoaded() {
+    ok(result == 42);
+    SimpleTest.finish();
+  }
+</script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_scriptModuleOrder.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test execution order of deferred scripts and modules </title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results, [1, 2, 3]), 'Check execution order');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_simple1.js"></script>
+<script defer src="script_simple2.js"></script>
+<script type="module" src="module_simple3.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_scriptNotParsedAsModule.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test classic script not parsed as module</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var hadSyntaxError = false;
+
+  SimpleTest.waitForExplicitFinish();
+  window.onerror = handleError;
+
+  function handleError(message, url, line, column, error) {
+    hadSyntaxError = error instanceof SyntaxError;
+  }
+
+  function testError() {
+    ok(!wasRun, 'Check script was not run');
+    ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
+    SimpleTest.finish();
+  }
+</script>
+<script src="module_testSyntax.js"></script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_simpleImport.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test a simple module import</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var result;
+
+  SimpleTest.waitForExplicitFinish();
+
+  function testLoaded() {
+    ok(result == 42, 'Check imported value');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_simpleImport.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxError.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing a module are reported</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var hadSyntaxError = false;
+
+  SimpleTest.waitForExplicitFinish();
+  window.onerror = handleError;
+
+  function handleError(message, url, line, column, error) {
+    hadSyntaxError = error instanceof SyntaxError;
+  }
+
+  function testError() {
+    ok(!wasRun, 'Check script was not run');
+    ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_badSyntax.js"></script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxErrorAsync.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing an async module are reported</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var hadSyntaxError = false;
+
+  SimpleTest.waitForExplicitFinish();
+  window.onerror = handleError;
+
+  function handleError(message, url, line, column, error) {
+    hadSyntaxError = error instanceof SyntaxError;
+  }
+
+  function testError() {
+    ok(!wasRun, 'Check script was not run');
+    ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_badSyntax.js" async></script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxErrorInline.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing an inline module are reported</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var hadSyntaxError = false;
+
+  SimpleTest.waitForExplicitFinish();
+  window.onerror = handleError;
+
+  function handleError(message, url, line, column, error) {
+    hadSyntaxError = error instanceof SyntaxError;
+  }
+
+  function testError() {
+    ok(!wasRun, 'Check script was not run');
+    ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module">
+// Module with a syntax error.
+some invalid js syntax;
+wasRun = true;
+</script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_syntaxErrorInlineAsync.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test syntax errors parsing an inline async module are reported</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var wasRun = false;
+  var hadSyntaxError = false;
+
+  SimpleTest.waitForExplicitFinish();
+  window.onerror = handleError;
+
+  function handleError(message, url, line, column, error) {
+    hadSyntaxError = error instanceof SyntaxError;
+  }
+
+  function testError() {
+    ok(!wasRun, 'Check script was not run');
+    ok(hadSyntaxError, 'Check that a SyntaxError was thrown');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" async>
+// Module with a syntax error.
+some invalid js syntax;
+wasRun = true;
+</script>
+<body onload='testError()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_toplevelModuleMemoization.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test toplevel modules are momoized and only loaded once</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var results = [];
+
+  SimpleTest.waitForExplicitFinish();
+
+  function arrayEquals(a, b) {
+    if (a.length != b.length) {
+      return false;
+    }
+    for (let i = 0; i < a.length; i++) {
+      if (a[i] != b[i]) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  function testLoaded() {
+    ok(arrayEquals(results, [1]), 'Check execution order');
+    SimpleTest.finish();
+  }
+</script>
+<script type="module" src="module_simple1.js"></script>
+<script type="module" src="module_simple1.js"></script>
+<script type="module" src="module_simple1.js"></script>
+<body onload='testLoaded()'></body>
new file mode 100644
--- /dev/null
+++ b/dom/base/test/jsmodules/test_typeAttrCaseInsensitive.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Test script element's type attribute comparision is case-insensitive</title>
+<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+<script>
+  var inlineModuleRan = false;
+  var moduleRan = false;
+
+  SimpleTest.waitForExplicitFinish();
+
+  function testLoaded() {
+    ok(moduleRan, 'Check module script was run');
+    ok(inlineModuleRan, 'Check inline module script was run');
+    SimpleTest.finish();
+  }
+</script>
+<script type="MODULE" src="module_setRan.js"></script>
+<script type="mOdUlE">inlineModuleRan = true;</script>
+<body onload='testLoaded()'></body>
--- a/dom/base/test/moz.build
+++ b/dom/base/test/moz.build
@@ -33,16 +33,17 @@ MOCHITEST_CHROME_MANIFESTS += [
 ]
 
 BROWSER_CHROME_MANIFESTS += [
     'browser.ini',
 ]
 
 TEST_DIRS += [
     'gtest',
+    'jsmodules'
 ]
 
 TEST_HARNESS_FILES.testing.mochitest.tests.dom.base.test.chrome += [
     'chrome/bug421622-referer.sjs',
     'chrome/nochrome_bug765993.html',
     'chrome/nochrome_bug765993.js',
     'chrome/nochrome_bug765993.js^headers^',
 ]