mirror of
https://github.com/servo/servo.git
synced 2025-07-11 17:33:47 +01:00
205 lines
7.6 KiB
JavaScript
205 lines
7.6 KiB
JavaScript
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 built-in module (std:blank) is loaded.
|
|
BUILTIN: "builtin",
|
|
|
|
// 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. @std/blank relative:@std/blank
|
|
// ------------------------- ----------------------
|
|
// (The last case assumes a file `@std/blank` that logs `relative:@std/blank`
|
|
// 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.BUILTIN) {
|
|
expected_log = [];
|
|
} else 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}">
|
|
`;
|
|
if (importMapString) {
|
|
content += `
|
|
<script type="importmap">
|
|
${importMapString}
|
|
</sc` + `ript>
|
|
`;
|
|
}
|
|
content += `
|
|
<body>
|
|
<script>
|
|
setup({ allow_uncaught_exception: true });
|
|
${testScript}
|
|
</sc` + `ript>
|
|
`;
|
|
iframe.contentDocument.write(content);
|
|
iframe.contentDocument.close();
|
|
fetch_tests_from_window(iframe.contentWindow);
|
|
}
|
|
|
|
function testScriptElement(importMapString, importMapBaseURL, specifier, expected, type) {
|
|
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) {
|
|
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.js?pipe=sub(none)&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) {
|
|
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 doTests(importMapString, importMapBaseURL, tests) {
|
|
window.addEventListener("load", () => {
|
|
for (const specifier in tests) {
|
|
// <script src> (module scripts)
|
|
testScriptElement(importMapString, importMapBaseURL, specifier,
|
|
tests[specifier][0], "module");
|
|
|
|
// <script src> (classic scripts)
|
|
testScriptElement(importMapString, importMapBaseURL, specifier,
|
|
tests[specifier][1], "text/javascript");
|
|
|
|
// static imports.
|
|
testStaticImport(importMapString, importMapBaseURL, specifier,
|
|
tests[specifier][2]);
|
|
|
|
// dynamic imports from a module script.
|
|
testDynamicImport(importMapString, importMapBaseURL, specifier,
|
|
tests[specifier][3], "module");
|
|
|
|
// dynamic imports from a classic script.
|
|
testDynamicImport(importMapString, importMapBaseURL, specifier,
|
|
tests[specifier][3], "text/javascript");
|
|
}
|
|
});
|
|
}
|