Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No dynamic import in service worker #27699

Merged
merged 10 commits into from
Feb 24, 2021
13 changes: 12 additions & 1 deletion docs/writing-tests/testharness.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand All @@ -149,8 +151,13 @@ are:

* `window` (default): to be run at <code><var>x</var>.any.html</code>
* `dedicatedworker` (default): to be run at <code><var>x</var>.any.worker.html</code>
* `serviceworker`: to be run at <code><var>x</var>.any.serviceworker.html</code> (`.https` is implied)
* `dedicatedworker-module` to be run at <code><var>x</var>.any.worker-module.html</code>
* `serviceworker`: to be run at <code><var>x</var>.any.serviceworker.html</code> (`.https` is
implied)
* `serviceworker-module`: to be run at <code><var>x</var>.any.serviceworker-module.html</code>
(`.https` is implied)
* `sharedworker`: to be run at <code><var>x</var>.any.sharedworker.html</code>
* `sharedworker-module`: to be run at <code><var>x</var>.any.sharedworker-module.html</code>
* `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
Expand Down Expand Up @@ -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 `<script>` tag. In classic
worker environments, the script will be imported using `importScripts()`. In module worker
environments, the script will be imported using a static `import`.

### Specifying a timeout of long

Use `// META: timeout=long` at the beginning of the resource.
Expand Down
39 changes: 0 additions & 39 deletions service-workers/service-worker/import-module-scripts.https.html

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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';
jakearchibald marked this conversation as resolved.
Show resolved Hide resolved

import './resources/no-dynamic-import.js';
3 changes: 3 additions & 0 deletions service-workers/service-worker/no-dynamic-import.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// META: global=serviceworker

importScripts('resources/no-dynamic-import.js');
1 change: 1 addition & 0 deletions service-workers/service-worker/resources/basic-module-2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'hello again!';
1 change: 1 addition & 0 deletions service-workers/service-worker/resources/basic-module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default 'hello!';
18 changes: 18 additions & 0 deletions service-workers/service-worker/resources/no-dynamic-import.js
Original file line number Diff line number Diff line change
@@ -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
);
}
4 changes: 4 additions & 0 deletions tools/manifest/sourcefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]]

Expand Down
113 changes: 101 additions & 12 deletions tools/serve/serve.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = """<!doctype html>
<meta charset=utf-8>
%(meta)s
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
fetch_tests_from_worker(new Worker("%(path)s%(query)s", { type: "module" }));
</script>
"""


class WindowHandler(HtmlWrapperHandler):
path_replace = [(".window.html", ".window.js")]
wrapper = """<!doctype html>
Expand Down Expand Up @@ -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 = """<!doctype html>
<meta charset=utf-8>
%(meta)s
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
fetch_tests_from_worker(new SharedWorker("%(path)s%(query)s", { type: "module" }));
</script>
"""


class ServiceWorkersHandler(HtmlWrapperHandler):
global_type = "serviceworker"
path_replace = [(".any.serviceworker.html", ".any.js", ".any.worker.js")]
Expand All @@ -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 = """<!doctype html>
<meta charset=utf-8>
%(meta)s
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
(async function() {
const scope = 'does/not/exist';
let reg = await navigator.serviceWorker.getRegistration(scope);
if (reg) await reg.unregister();
reg = await navigator.serviceWorker.register(
"%(path)s%(query)s",
{ scope, type: 'module' },
);
fetch_tests_from_worker(reg.installing);
})();
</script>
"""


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 = {
Expand All @@ -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")]
Expand Down Expand Up @@ -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),
Expand Down
4 changes: 2 additions & 2 deletions tools/wptserve/tests/functional/test_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__':
Expand Down
4 changes: 2 additions & 2 deletions workers/examples/general.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.

// ============================================================================
Expand All @@ -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.