diff options
Diffstat (limited to 'testing/web-platform/tests/import-maps/resources')
5 files changed, 251 insertions, 0 deletions
diff --git a/testing/web-platform/tests/import-maps/resources/empty.js b/testing/web-platform/tests/import-maps/resources/empty.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/testing/web-platform/tests/import-maps/resources/empty.js diff --git a/testing/web-platform/tests/import-maps/resources/inject-base.js b/testing/web-platform/tests/import-maps/resources/inject-base.js new file mode 100644 index 0000000000..4d469aec89 --- /dev/null +++ b/testing/web-platform/tests/import-maps/resources/inject-base.js @@ -0,0 +1,3 @@ +const el = document.createElement("base"); +el.href = "{{GET[baseurl]}}"; +document.currentScript.after(el); diff --git a/testing/web-platform/tests/import-maps/resources/log.js b/testing/web-platform/tests/import-maps/resources/log.js new file mode 100644 index 0000000000..a024a29bf2 --- /dev/null +++ b/testing/web-platform/tests/import-maps/resources/log.js @@ -0,0 +1 @@ +log.push("log:{{GET[name]}}"); diff --git a/testing/web-platform/tests/import-maps/resources/log.js.headers b/testing/web-platform/tests/import-maps/resources/log.js.headers new file mode 100644 index 0000000000..cb762eff80 --- /dev/null +++ b/testing/web-platform/tests/import-maps/resources/log.js.headers @@ -0,0 +1 @@ +Access-Control-Allow-Origin: * diff --git a/testing/web-platform/tests/import-maps/resources/test-helper.js b/testing/web-platform/tests/import-maps/resources/test-helper.js new file mode 100644 index 0000000000..f12e84c685 --- /dev/null +++ b/testing/web-platform/tests/import-maps/resources/test-helper.js @@ -0,0 +1,246 @@ +let log = []; + +function expect_log(test, expected_log) { + test.step_func_done(() => { + const actual_log = log; + log = []; + assert_array_equals(actual_log, expected_log, 'fallback log'); + })(); +} + +// Results of resolving a specifier using import maps. +const Result = { + // A failure considered as a fetch error in a module script tree. + // <script>'s error event is fired. + FETCH_ERROR: "fetch_error", + + // A failure considered as a parse error in a module script tree. + // Window's error event is fired. + PARSE_ERROR: "parse_error", + + // The specifier is considered as a relative or absolute URL. + // Specifier Expected log + // ------------------------- ---------------------- + // ...?name=foo log:foo + // data:...log('foo') foo + // Others, e.g. bare/bare relative:bare/bare + // ------------------------- ---------------------- + // (The last case assumes a file `bare/bare` that logs `relative:bare/bare` + // exists) + URL: "URL", +}; + +const Handler = { + // Handlers for <script> element cases. + // Note that on a parse error both WindowErrorEvent and ScriptLoadEvent are + // called. + ScriptLoadEvent: "<script> element's load event handler", + ScriptErrorEvent: "<script> element's error event handler", + WindowErrorEvent: "window's error event handler", + + // Handlers for dynamic imports. + DynamicImportResolve: "dynamic import resolve", + DynamicImportReject: "dynamic import reject", +}; + +// Returns a map with Handler.* as the keys. +function getHandlers(t, specifier, expected) { + let handlers = {}; + handlers[Handler.ScriptLoadEvent] = t.unreached_func("Shouldn't load"); + handlers[Handler.ScriptErrorEvent] = + t.unreached_func("script's error event shouldn't be fired"); + handlers[Handler.WindowErrorEvent] = + t.unreached_func("window's error event shouldn't be fired"); + handlers[Handler.DynamicImportResolve] = + t.unreached_func("dynamic import promise shouldn't be resolved"); + handlers[Handler.DynamicImportReject] = + t.unreached_func("dynamic import promise shouldn't be rejected"); + + if (expected === Result.FETCH_ERROR) { + handlers[Handler.ScriptErrorEvent] = () => expect_log(t, []); + handlers[Handler.DynamicImportReject] = () => expect_log(t, []); + } else if (expected === Result.PARSE_ERROR) { + let error_occurred = false; + handlers[Handler.WindowErrorEvent] = () => { error_occurred = true; }; + handlers[Handler.ScriptLoadEvent] = t.step_func(() => { + // Even if a parse error occurs, load event is fired (after + // window.onerror is called), so trigger the load handler only if + // there was no previous window.onerror call. + assert_true(error_occurred, "window.onerror should be fired"); + expect_log(t, []); + }); + handlers[Handler.DynamicImportReject] = t.step_func(() => { + assert_false(error_occurred, + "window.onerror shouldn't be fired for dynamic imports"); + expect_log(t, []); + }); + } else { + let expected_log; + if (expected === Result.URL) { + const match_data_url = specifier.match(/data:.*log\.push\('(.*)'\)/); + const match_log_js = specifier.match(/name=(.*)/); + if (match_data_url) { + expected_log = [match_data_url[1]]; + } else if (match_log_js) { + expected_log = ["log:" + match_log_js[1]]; + } else { + expected_log = ["relative:" + specifier]; + } + } else { + expected_log = [expected]; + } + handlers[Handler.ScriptLoadEvent] = () => expect_log(t, expected_log); + handlers[Handler.DynamicImportResolve] = () => expect_log(t, expected_log); + } + return handlers; +} + +// Creates an <iframe> and run a test inside the <iframe> +// to separate the module maps and import maps in each test. +function testInIframe(importMapString, importMapBaseURL, testScript) { + const iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + if (!importMapBaseURL) { + importMapBaseURL = document.baseURI; + } + let content = ` + <script src="/resources/testharness.js"></script> + <script src="/import-maps/resources/test-helper.js"></script> + <base href="${importMapBaseURL}"> + <script type="importmap">${importMapString}</script> + <body> + <script> + setup({ allow_uncaught_exception: true }); + ${testScript} + </sc` + `ript> + `; + iframe.contentDocument.write(content); + iframe.contentDocument.close(); + return fetch_tests_from_window(iframe.contentWindow); +} + +function testScriptElement(importMapString, importMapBaseURL, specifier, expected, type) { + return testInIframe(importMapString, importMapBaseURL, ` + const t = async_test("${specifier}: <script src type=${type}>"); + const handlers = getHandlers(t, "${specifier}", "${expected}"); + const script = document.createElement("script"); + script.setAttribute("type", "${type}"); + script.setAttribute("src", "${specifier}"); + script.addEventListener("load", handlers[Handler.ScriptLoadEvent]); + script.addEventListener("error", handlers[Handler.ScriptErrorEvent]); + window.addEventListener("error", handlers[Handler.WindowErrorEvent]); + document.body.appendChild(script); + `); +} + +function testStaticImport(importMapString, importMapBaseURL, specifier, expected) { + return testInIframe(importMapString, importMapBaseURL, ` + const t = async_test("${specifier}: static import"); + const handlers = getHandlers(t, "${specifier}", "${expected}"); + const script = document.createElement("script"); + script.setAttribute("type", "module"); + script.setAttribute("src", + "/import-maps/static-import.py?url=" + + encodeURIComponent("${specifier}")); + script.addEventListener("load", handlers[Handler.ScriptLoadEvent]); + script.addEventListener("error", handlers[Handler.ScriptErrorEvent]); + window.addEventListener("error", handlers[Handler.WindowErrorEvent]); + document.body.appendChild(script); + `); +} + +function testDynamicImport(importMapString, importMapBaseURL, specifier, expected, type) { + return testInIframe(importMapString, importMapBaseURL, ` + const t = async_test("${specifier}: dynamic import (from ${type})"); + const handlers = getHandlers(t, "${specifier}", "${expected}"); + const script = document.createElement("script"); + script.setAttribute("type", "${type}"); + script.innerText = + "import(\\"${specifier}\\")" + + ".then(handlers[Handler.DynamicImportResolve], " + + "handlers[Handler.DynamicImportReject]);"; + script.addEventListener("error", + t.unreached_func("top-level inline script shouldn't error")); + document.body.appendChild(script); + `); +} + +function testInIframeInjectBase(importMapString, importMapBaseURL, testScript) { + const iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + let content = ` + <script src="/resources/testharness.js"></script> + <script src="/import-maps/resources/test-helper.js"></script> + <script src="/import-maps/resources/inject-base.js?pipe=sub&baseurl=${importMapBaseURL}"></script> + <script type="importmap"> + ${importMapString} + </script> + <body> + <script> + setup({ allow_uncaught_exception: true }); + ${testScript} + </sc` + `ript> + `; + iframe.contentDocument.write(content); + iframe.contentDocument.close(); + return fetch_tests_from_window(iframe.contentWindow); +} + +function testStaticImportInjectBase(importMapString, importMapBaseURL, specifier, expected) { + return testInIframeInjectBase(importMapString, importMapBaseURL, ` + const t = async_test("${specifier}: static import with inject <base>"); + const handlers = getHandlers(t, "${specifier}", "${expected}"); + const script = document.createElement("script"); + script.setAttribute("type", "module"); + script.setAttribute("src", + "/import-maps/static-import.py?url=" + + encodeURIComponent("${specifier}")); + script.addEventListener("load", handlers[Handler.ScriptLoadEvent]); + script.addEventListener("error", handlers[Handler.ScriptErrorEvent]); + window.addEventListener("error", handlers[Handler.WindowErrorEvent]); + document.body.appendChild(script); + `); +} + +function testDynamicImportInjectBase(importMapString, importMapBaseURL, specifier, expected, type) { + return testInIframeInjectBase(importMapString, importMapBaseURL, ` + const t = async_test("${specifier}: dynamic import (from ${type}) with inject <base>"); + const handlers = getHandlers(t, "${specifier}", "${expected}"); + const script = document.createElement("script"); + script.setAttribute("type", "${type}"); + script.innerText = + "import(\\"${specifier}\\")" + + ".then(handlers[Handler.DynamicImportResolve], " + + "handlers[Handler.DynamicImportReject]);"; + script.addEventListener("error", + t.unreached_func("top-level inline script shouldn't error")); + document.body.appendChild(script); + `); +} + +function doTests(importMapString, importMapBaseURL, tests) { + promise_setup(function () { + return new Promise((resolve) => { + window.addEventListener("load", async () => { + for (const specifier in tests) { + // <script src> (module scripts) + await testScriptElement(importMapString, importMapBaseURL, specifier, tests[specifier][0], "module"); + + // <script src> (classic scripts) + await testScriptElement(importMapString, importMapBaseURL, specifier, tests[specifier][1], "text/javascript"); + + // static imports. + await testStaticImport(importMapString, importMapBaseURL, specifier, tests[specifier][2]); + + // dynamic imports from a module script. + await testDynamicImport(importMapString, importMapBaseURL, specifier, tests[specifier][3], "module"); + + // dynamic imports from a classic script. + await testDynamicImport(importMapString, importMapBaseURL, specifier, tests[specifier][3], "text/javascript"); + } + done(); + resolve(); + }); + }); + }, { explicit_done: true }); +} |