diff --git a/docs/writing-tests/testharness.md b/docs/writing-tests/testharness.md index 7cf7f73a868e0a..49060bdd8e6cd7 100644 --- a/docs/writing-tests/testharness.md +++ b/docs/writing-tests/testharness.md @@ -140,6 +140,8 @@ It is possible to customize the set of scopes with a metadata comment, such as // ==> would only run in the window and service worker scope // META: global=dedicatedworker // ==> would run in the default dedicated worker scope +// META: global=dedicatedworker-module +// ==> would run in the dedicated worker scope as a module // META: global=worker // ==> would run in the dedicated, shared, and service worker scopes ``` @@ -149,8 +151,13 @@ are: * `window` (default): to be run at x.any.html * `dedicatedworker` (default): to be run at x.any.worker.html -* `serviceworker`: to be run at x.any.serviceworker.html (`.https` is implied) +* `dedicatedworker-module` to be run at x.any.worker-module.html +* `serviceworker`: to be run at x.any.serviceworker.html (`.https` is + implied) +* `serviceworker-module`: to be run at x.any.serviceworker-module.html + (`.https` is implied) * `sharedworker`: to be run at x.any.sharedworker.html +* `sharedworker-module`: to be run at x.any.sharedworker-module.html * `jsshell`: to be run in a JavaScript shell, without access to the DOM (currently only supported in SpiderMonkey, and skipped in wptrunner) * `worker`: shorthand for the dedicated, shared, and service worker scopes @@ -183,6 +190,10 @@ Use `// META: script=link/to/resource.js` at the beginning of the resource. For can be used to include both the global and a local `utils.js` in a test. +In window environments, the script will be included using a classic ` - - - - - - diff --git a/service-workers/service-worker/no-dynamic-import-in-module.any.js b/service-workers/service-worker/no-dynamic-import-in-module.any.js new file mode 100644 index 00000000000000..84b17629ccddc9 --- /dev/null +++ b/service-workers/service-worker/no-dynamic-import-in-module.any.js @@ -0,0 +1,7 @@ +// META: global=serviceworker-module + +// This is imported to ensure import('./basic-module-2.js') fails even if +// it has been previously statically imported. +import './basic-module-2.js'; + +import './resources/no-dynamic-import.js'; diff --git a/service-workers/service-worker/no-dynamic-import.any.js b/service-workers/service-worker/no-dynamic-import.any.js new file mode 100644 index 00000000000000..25b370b7094bf8 --- /dev/null +++ b/service-workers/service-worker/no-dynamic-import.any.js @@ -0,0 +1,3 @@ +// META: global=serviceworker + +importScripts('resources/no-dynamic-import.js'); diff --git a/service-workers/service-worker/resources/basic-module-2.js b/service-workers/service-worker/resources/basic-module-2.js new file mode 100644 index 00000000000000..189b1c87fee75c --- /dev/null +++ b/service-workers/service-worker/resources/basic-module-2.js @@ -0,0 +1 @@ +export default 'hello again!'; diff --git a/service-workers/service-worker/resources/basic-module.js b/service-workers/service-worker/resources/basic-module.js new file mode 100644 index 00000000000000..789a89bc630847 --- /dev/null +++ b/service-workers/service-worker/resources/basic-module.js @@ -0,0 +1 @@ +export default 'hello!'; diff --git a/service-workers/service-worker/resources/no-dynamic-import.js b/service-workers/service-worker/resources/no-dynamic-import.js new file mode 100644 index 00000000000000..ecedd6c5d75c7d --- /dev/null +++ b/service-workers/service-worker/resources/no-dynamic-import.js @@ -0,0 +1,18 @@ +/** @type {[name: string, url: string][]} */ +const importUrlTests = [ + ["Module URL", "./basic-module.js"], + // In no-dynamic-import-in-module.any.js, this module is also statically imported + ["Another module URL", "./basic-module-2.js"], + [ + "Module data: URL", + "data:text/javascript;charset=utf-8," + + encodeURIComponent(`export default 'hello!';`), + ], +]; + +for (const [name, url] of importUrlTests) { + promise_test( + (t) => promise_rejects_js(t, TypeError, import(url), "Import must reject"), + name + ); +} diff --git a/tools/manifest/sourcefile.py b/tools/manifest/sourcefile.py index 5b99f90e458a29..34e679eb8b73b7 100644 --- a/tools/manifest/sourcefile.py +++ b/tools/manifest/sourcefile.py @@ -84,9 +84,13 @@ def read_script_metadata(f, regexp): _any_variants = { "window": {"suffix": ".any.html"}, "serviceworker": {"force_https": True}, + "serviceworker-module": {"force_https": True}, "sharedworker": {}, + "sharedworker-module": {}, "dedicatedworker": {"suffix": ".any.worker.html"}, + "dedicatedworker-module": {"suffix": ".any.worker-module.html"}, "worker": {"longhand": {"dedicatedworker", "sharedworker", "serviceworker"}}, + "worker-module": {}, "jsshell": {"suffix": ".any.js"}, } # type: Dict[Text, Dict[Text, Any]] diff --git a/tools/serve/serve.py b/tools/serve/serve.py index 644a8a93f704f0..8e1aaa8dc73c1a 100644 --- a/tools/serve/serve.py +++ b/tools/serve/serve.py @@ -227,6 +227,22 @@ class WorkersHandler(HtmlWrapperHandler): """ +class WorkerModulesHandler(HtmlWrapperHandler): + global_type = "dedicatedworker-module" + path_replace = [(".any.worker-module.html", ".any.js", ".any.worker-module.js"), + (".worker.html", ".worker.js")] + wrapper = """ + +%(meta)s + + +
+ +""" + + class WindowHandler(HtmlWrapperHandler): path_replace = [(".window.html", ".window.js")] wrapper = """ @@ -275,6 +291,21 @@ class SharedWorkersHandler(HtmlWrapperHandler): """ +class SharedWorkerModulesHandler(HtmlWrapperHandler): + global_type = "sharedworker-module" + path_replace = [(".any.sharedworker-module.html", ".any.js", ".any.worker-module.js")] + wrapper = """ + +%(meta)s + + +
+ +""" + + class ServiceWorkersHandler(HtmlWrapperHandler): global_type = "serviceworker" path_replace = [(".any.serviceworker.html", ".any.js", ".any.worker.js")] @@ -296,8 +327,54 @@ class ServiceWorkersHandler(HtmlWrapperHandler): """ -class AnyWorkerHandler(WrapperHandler): +class ServiceWorkerModulesHandler(HtmlWrapperHandler): + global_type = "serviceworker-module" + path_replace = [(".any.serviceworker-module.html", + ".any.js", ".any.worker-module.js")] + wrapper = """ + +%(meta)s + + +
+ +""" + + +class BaseWorkerHandler(WrapperHandler): headers = [('Content-Type', 'text/javascript')] + + def _meta_replacement(self, key, value): + return None + + @abc.abstractmethod + def _create_script_import(self, attribute): + # Take attribute (a string URL to a JS script) and return JS source to import the script + # into the worker. + pass + + def _script_replacement(self, key, value): + if key == "script": + attribute = value.replace("\\", "\\\\").replace('"', '\\"') + return self._create_script_import(attribute) + if key == "title": + value = value.replace("\\", "\\\\").replace('"', '\\"') + return 'self.META_TITLE = "%s";' % value + return None + + +class ClassicWorkerHandler(BaseWorkerHandler): path_replace = [(".any.worker.js", ".any.js")] wrapper = """%(meta)s self.GLOBAL = { @@ -310,17 +387,25 @@ class AnyWorkerHandler(WrapperHandler): done(); """ - def _meta_replacement(self, key, value): - return None + def _create_script_import(self, attribute): + return 'importScripts("%s")' % attribute - def _script_replacement(self, key, value): - if key == "script": - attribute = value.replace("\\", "\\\\").replace('"', '\\"') - return 'importScripts("%s")' % attribute - if key == "title": - value = value.replace("\\", "\\\\").replace('"', '\\"') - return 'self.META_TITLE = "%s";' % value - return None + +class ModuleWorkerHandler(BaseWorkerHandler): + path_replace = [(".any.worker-module.js", ".any.js")] + wrapper = """%(meta)s +self.GLOBAL = { + isWindow: function() { return false; }, + isWorker: function() { return true; }, +}; +import "/resources/testharness.js"; +%(script)s +import "%(path)s"; +done(); +""" + + def _create_script_import(self, attribute): + return 'import "%s";' % attribute rewrites = [("GET", "/resources/WebIDLParser.js", "/resources/webidl2/lib/webidl2.js")] @@ -368,11 +453,15 @@ def add_mount_point(self, url_base, path): routes = [ ("GET", "*.worker.html", WorkersHandler), + ("GET", "*.worker-module.html", WorkerModulesHandler), ("GET", "*.window.html", WindowHandler), ("GET", "*.any.html", AnyHtmlHandler), ("GET", "*.any.sharedworker.html", SharedWorkersHandler), + ("GET", "*.any.sharedworker-module.html", SharedWorkerModulesHandler), ("GET", "*.any.serviceworker.html", ServiceWorkersHandler), - ("GET", "*.any.worker.js", AnyWorkerHandler), + ("GET", "*.any.serviceworker-module.html", ServiceWorkerModulesHandler), + ("GET", "*.any.worker.js", ClassicWorkerHandler), + ("GET", "*.any.worker-module.js", ModuleWorkerHandler), ("GET", "*.asis", handlers.AsIsHandler), ("GET", "/.well-known/origin-policy", handlers.PythonScriptHandler), ("*", "*.py", handlers.PythonScriptHandler), diff --git a/tools/wptserve/tests/functional/test_handlers.py b/tools/wptserve/tests/functional/test_handlers.py index 0acfac4d1945f7..1dc2a9ba7bb3e5 100644 --- a/tools/wptserve/tests/functional/test_handlers.py +++ b/tools/wptserve/tests/functional/test_handlers.py @@ -436,12 +436,12 @@ def test_serviceworker_html(self): 'text/html', serve.ServiceWorkersHandler) -class TestAnyWorkerHandler(TestWrapperHandlerUsingServer): +class TestClassicWorkerHandler(TestWrapperHandlerUsingServer): dummy_files = {'bar.any.js': b''} def test_any_work_js(self): self.run_wrapper_test('bar.any.worker.js', 'text/javascript', - serve.AnyWorkerHandler) + serve.ClassicWorkerHandler) if __name__ == '__main__': diff --git a/workers/examples/general.any.js b/workers/examples/general.any.js index 8906350a7e8d4a..cb5d61eafbece7 100644 --- a/workers/examples/general.any.js +++ b/workers/examples/general.any.js @@ -7,7 +7,7 @@ // testharness.js is imported (via importScripts()) by generated glue code by // WPT server. -// See AnyWorkerHandler in +// See ClassicWorkerHandler in // https://github.com/web-platform-tests/wpt/blob/master/tools/serve/serve.py. // ============================================================================ @@ -30,5 +30,5 @@ test(() => { // done() is NOT needed in .any.js tests, as it is called by generated // glue code by the WPT server. -// See AnyWorkerHandler in +// See ClassicWorkerHandler in // https://github.com/web-platform-tests/wpt/blob/master/tools/serve/serve.py.