mirror of
https://github.com/mozilla-firefox/firefox
synced 2026-08-12 20:45:22 +00:00
Automatic update from web-platform-tests Add tests for text modules This is to support the spec changes in: - https://github.com/tc39/proposal-import-text - https://github.com/whatwg/html/pull/11933 - https://github.com/whatwg/fetch/pull/1898 - https://github.com/w3c/webappsec-csp/pull/794 -- wpt-commits: 5419f98d72f4b1ae49980581a6a66710d6a3dee7 wpt-pr: 56812
440 lines
18 KiB
HTML
440 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<meta name="timeout" content="long">
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="/common/get-host-info.sub.js"></script>
|
|
<body>
|
|
<script>
|
|
host_info = get_host_info();
|
|
|
|
function verifyNumberOfDownloads(url, number, allowTransferSizeOfZero = false) {
|
|
let numDownloads = 0;
|
|
const absoluteURL = new URL(url, location.href).href;
|
|
performance.getEntriesByName(absoluteURL).forEach(entry => {
|
|
if (entry.transferSize > 0 || allowTransferSizeOfZero) {
|
|
numDownloads++;
|
|
}
|
|
});
|
|
assert_equals(numDownloads, number, url);
|
|
}
|
|
|
|
function attachAndWaitForLoad(element) {
|
|
return new Promise((resolve, reject) => {
|
|
element.onload = resolve;
|
|
element.onerror = reject;
|
|
document.body.appendChild(element);
|
|
});
|
|
}
|
|
|
|
function attachAndWaitForError(element) {
|
|
return new Promise((resolve, reject) => {
|
|
element.onload = reject;
|
|
element.onerror = resolve;
|
|
document.body.appendChild(element);
|
|
});
|
|
}
|
|
|
|
function attachAndWaitForTimeout(element, t) {
|
|
return new Promise((resolve, reject) => {
|
|
element.onload = reject;
|
|
element.onerror = reject;
|
|
t.step_timeout(resolve, 1000);
|
|
document.body.appendChild(element);
|
|
});
|
|
}
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/dummy-module.js?unique';
|
|
return attachAndWaitForLoad(link).then(() => {
|
|
verifyNumberOfDownloads('resources/dummy-module.js?unique', 1);
|
|
|
|
// Verify that <script> doesn't fetch the module again.
|
|
const script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.src = 'resources/dummy-module.js?unique';
|
|
return attachAndWaitForLoad(script);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads('resources/dummy-module.js?unique', 1, true);
|
|
});
|
|
}, "link rel=modulepreload with script shares a cache with <script> tags");
|
|
|
|
/**
|
|
* Begin tests to ensure crossorigin value behaves the same on
|
|
* link rel=modulepreload as it does script elements.
|
|
*/
|
|
promise_test(t => {
|
|
document.cookie = 'same=1';
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.crossOrigin = 'anonymous';
|
|
link.href = 'resources/dummy-module.js?sameOriginAnonymous';
|
|
return attachAndWaitForLoad(link).then(() => {
|
|
verifyNumberOfDownloads('resources/dummy-module.js?sameOriginAnonymous', 1);
|
|
|
|
// Verify that <script> doesn't fetch the module again.
|
|
const script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.crossOrigin = 'anonymous';
|
|
script.src = 'resources/dummy-module.js?sameOriginAnonymous';
|
|
return attachAndWaitForLoad(script);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads('resources/dummy-module.js?sameOriginAnonymous', 1, true);
|
|
});
|
|
}, 'same-origin link rel=modulepreload crossorigin=anonymous');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.crossOrigin = 'use-credentials';
|
|
link.href = 'resources/dummy-module.js?sameOriginUseCredentials';
|
|
return attachAndWaitForLoad(link).then(() => {
|
|
verifyNumberOfDownloads('resources/dummy-module.js?sameOriginUseCredentials', 1);
|
|
|
|
// Verify that <script> doesn't fetch the module again.
|
|
const script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.crossOrigin = 'use-credentials';
|
|
script.src = 'resources/dummy-module.js?sameOriginUseCredentials';
|
|
return attachAndWaitForLoad(script);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads('resources/dummy-module.js?sameOriginUseCredentials', 1, true);
|
|
});
|
|
}, 'same-origin link rel=modulepreload crossorigin=use-credentials');
|
|
|
|
promise_test(t => {
|
|
const setCookiePromise = fetch(
|
|
`${host_info.HTTP_REMOTE_ORIGIN}/cookies/resources/set-cookie.py?name=cross&path=/preload/`,
|
|
{
|
|
mode: 'no-cors',
|
|
credentials: 'include',
|
|
});
|
|
|
|
return setCookiePromise.then(() => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = `${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginNone`;
|
|
return attachAndWaitForLoad(link);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads(`${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginNone`, 1, true);
|
|
|
|
// Verify that <script> doesn't fetch the module again.
|
|
const script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.src = `${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginNone`;
|
|
return attachAndWaitForLoad(script);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads(`${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginNone`, 1, true);
|
|
});
|
|
}, 'cross-origin link rel=modulepreload');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.crossOrigin = 'anonymous';
|
|
link.href = `${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginAnonymous`;
|
|
return attachAndWaitForLoad(link).then(() => {
|
|
verifyNumberOfDownloads(`${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginAnonymous`, 1, true);
|
|
|
|
// Verify that <script> doesn't fetch the module again.
|
|
const script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.crossOrigin = 'anonymous';
|
|
script.src = `${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginAnonymous`;
|
|
return attachAndWaitForLoad(script);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads(`${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginAnonymous`, 1, true);
|
|
});
|
|
}, 'cross-origin link rel=modulepreload crossorigin=anonymous');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.crossOrigin = 'use-credentials';
|
|
link.href = `${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginUseCredentials`;
|
|
return attachAndWaitForLoad(link).then(() => {
|
|
verifyNumberOfDownloads(`${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginUseCredentials`, 1, true);
|
|
|
|
// Verify that <script> doesn't fetch the module again.
|
|
const script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.crossOrigin = 'use-credentials';
|
|
script.src = `${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginUseCredentials`;
|
|
return attachAndWaitForLoad(script);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads(`${host_info.HTTP_REMOTE_ORIGIN}/preload/resources/cross-origin-module.py?crossOriginUseCredentials`, 1, true);
|
|
});
|
|
}, 'cross-origin link rel=modulepreload crossorigin=use-credentials');
|
|
/**
|
|
* End link rel=modulepreload crossorigin attribute tests.
|
|
*/
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?submodule';
|
|
return attachAndWaitForLoad(link).then(() => {
|
|
verifyNumberOfDownloads('resources/module1.js?submodule', 1);
|
|
// The load event fires before (optional) submodules fetch.
|
|
verifyNumberOfDownloads('resources/module2.js', 0);
|
|
|
|
const script = document.createElement('script');
|
|
script.type = 'module';
|
|
script.src = 'resources/module1.js?submodule';
|
|
return attachAndWaitForLoad(script);
|
|
}).then(() => {
|
|
verifyNumberOfDownloads('resources/module1.js?submodule', 1);
|
|
verifyNumberOfDownloads('resources/module2.js', 1);
|
|
});
|
|
}, 'link rel=modulepreload with submodules');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = null;
|
|
return attachAndWaitForError(link);
|
|
}, 'link rel=modulepreload with bad href attribute');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?as-script';
|
|
link.as = 'script'
|
|
return attachAndWaitForLoad(link);
|
|
}, 'link rel=modulepreload as=script');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?as-image';
|
|
link.as = 'image'
|
|
return attachAndWaitForError(link);
|
|
}, 'link rel=modulepreload with non-script-like as= value (image)');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?as-xslt';
|
|
link.as = 'xslt'
|
|
return attachAndWaitForError(link);
|
|
}, 'link rel=modulepreload with non-script-like as= value (xslt)');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?as-style';
|
|
link.as = 'style'
|
|
return attachAndWaitForError(link);
|
|
}, 'link rel=modulepreload with non-style as= value (style)');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?as-json';
|
|
link.as = 'json'
|
|
return attachAndWaitForError(link);
|
|
}, 'link rel=modulepreload with non-JSON as= value (JSON)');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?integrity-match';
|
|
link.integrity = 'sha256-+Ks3iNIiTq2ujlWhvB056cmXobrCFpU9hd60xZ1WCaA='
|
|
return attachAndWaitForLoad(link);
|
|
}, 'link rel=modulepreload with integrity match');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.mjs?integrity-match';
|
|
link.integrity = 'sha256-+Ks3iNIiTq2ujlWhvB056cmXobrCFpU9hd60xZ1WCaA='
|
|
return attachAndWaitForLoad(link);
|
|
}, 'link rel=modulepreload with integrity match2');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.js?integrity-doesnotmatch';
|
|
link.integrity = 'sha384-doesnotmatch'
|
|
return attachAndWaitForError(link);
|
|
}, 'link rel=modulepreload with integrity mismatch');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.mjs?integrity-doesnotmatch';
|
|
link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc='
|
|
return attachAndWaitForError(link);
|
|
}, 'link rel=modulepreload with integrity mismatch2');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = 'resources/module1.mjs?integrity-invalid';
|
|
link.integrity = 'sha256-dOxReWMnMSPfUvxEbBqIrjNh8ZN8n05j7h3JmhF8gQc=%'
|
|
return attachAndWaitForLoad(link);
|
|
}, 'link rel=modulepreload with invalid integrity');
|
|
|
|
promise_test(t => {
|
|
const link1 = document.createElement('link');
|
|
const link2 = document.createElement('link');
|
|
link1.rel = 'modulepreload';
|
|
link2.rel = 'modulepreload';
|
|
link1.href = 'resources/module2.js?child-before';
|
|
link2.href = 'resources/module1.js?child-before';
|
|
return attachAndWaitForLoad(link1)
|
|
.then(() => attachAndWaitForLoad(link2))
|
|
.then(() => new Promise(r => t.step_timeout(r, 1000)))
|
|
.then(() => {
|
|
verifyNumberOfDownloads('resources/module2.js?child-before', 1);
|
|
});
|
|
|
|
}, 'multiple link rel=modulepreload with child module before parent');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.href = '';
|
|
link.as = 'fetch';
|
|
return attachAndWaitForTimeout(link, t);
|
|
}, 'link rel=modulepreload with empty href and invalid as= value');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
const script = document.createElement('script');
|
|
link.rel = 'modulepreload';
|
|
script.type = 'module';
|
|
link.href = 'resources/module1.mjs?non-matching-crossorigin';
|
|
script.src = link.href;
|
|
script.crossOrigin = 'anonymous';
|
|
document.body.append(link);
|
|
return attachAndWaitForLoad(script);
|
|
}, 'link rel=modulepreload and script with non-matching crossorigin values');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
const script = document.createElement('script');
|
|
link.rel = 'modulepreload';
|
|
script.type = 'module';
|
|
link.href = 'resources/module1.mjs?non-matching-crossorigin';
|
|
script.src = link.href;
|
|
link.crossOrigin = 'anonymous';
|
|
script.crossOrigin = 'use-credentials';
|
|
document.body.append(link);
|
|
return attachAndWaitForLoad(script);
|
|
}, 'link rel=modulepreload and script with non-matching crossorigin values2');
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
const moduleScript = document.createElement('script');
|
|
const classicScript = document.createElement('script');
|
|
link.rel = 'modulepreload';
|
|
moduleScript.type = 'module';
|
|
link.href = 'resources/dummy-module.js?non-module script';
|
|
classicScript.src = link.href;
|
|
moduleScript.src = link.href;
|
|
document.body.append(link);
|
|
document.body.append(classicScript);
|
|
return attachAndWaitForLoad(moduleScript);
|
|
}, 'link rel=modulepreload and non-module script');
|
|
|
|
// The following tests apply to all supported preload destinations.
|
|
const types = [
|
|
{"destination": "script", "file_extension" : "js", "import_attribute_type" : null},
|
|
{"destination": "style", "file_extension" : "css", "import_attribute_type" : "css"},
|
|
{"destination": "json", "file_extension" : "json", "import_attribute_type" : "json"},
|
|
{"destination": "text", "file_extension" : "txt", "import_attribute_type" : "text"}
|
|
];
|
|
|
|
for (const { destination, file_extension, import_attribute_type } of types) {
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.as = destination;
|
|
link.href = `resources/dummy.${file_extension}?unique_fetch`;
|
|
return attachAndWaitForLoad(link).then(() => {
|
|
verifyNumberOfDownloads(`resources/dummy.${file_extension}?unique_fetch`, 1, true);
|
|
|
|
// Verify that importing doesn't fetch the module again. Note that there
|
|
// is no valid import attribute for script imports, so the `with` statement
|
|
// must be absent.
|
|
if (import_attribute_type) {
|
|
return import(`./resources/dummy.${file_extension}?unique_fetch`, { with: { type: import_attribute_type } });
|
|
} else {
|
|
return import(`./resources/dummy.${file_extension}?unique_fetch`);
|
|
}
|
|
}).then(() => {
|
|
verifyNumberOfDownloads(`resources/dummy.${file_extension}?unique_fetch`, 1, true);
|
|
});
|
|
}, `link rel=modulepreload with ${destination} doesn't re-fetch when imported`);
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.as = destination;
|
|
link.href = `resources/syntax-error.${file_extension}`;
|
|
return attachAndWaitForLoad(link);
|
|
}, `link rel=modulepreload for a ${destination} module with syntax error will still load`);
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.as = destination;
|
|
link.href = `resources/not-exist.${file_extension}`;
|
|
return attachAndWaitForError(link);
|
|
}, `link rel=modulepreload for a ${destination} module with network error`);
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.as = destination;
|
|
link.href = `resources/dummy.${file_extension}?matching-media`;
|
|
link.media = 'all';
|
|
return attachAndWaitForLoad(link);
|
|
}, `link rel=modulepreload with ${destination} and matching media`);
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.as = destination;
|
|
link.href = `resources/dummy.${file_extension}?non-matching-media`;
|
|
link.media = 'not all';
|
|
return attachAndWaitForTimeout(link, t);
|
|
}, `link rel=modulepreload with ${destination} and non-matching media`);
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.as = destination;
|
|
link.href = `resources/dummy.${file_extension}?empty-media`;
|
|
link.media = '';
|
|
return attachAndWaitForLoad(link);
|
|
}, `link rel=modulepreload with ${destination} and empty media`);
|
|
|
|
promise_test(t => {
|
|
const link = document.createElement('link');
|
|
link.rel = 'modulepreload';
|
|
link.as = destination;
|
|
link.href = '';
|
|
return attachAndWaitForTimeout(link, t);
|
|
}, `link rel=modulepreload with ${destination} and empty href`);
|
|
|
|
promise_test(t => {
|
|
const link1 = document.createElement('link');
|
|
const link2 = document.createElement('link');
|
|
link1.rel = 'modulepreload';
|
|
link2.rel = 'modulepreload';
|
|
link1.as = destination;
|
|
link2.as = destination;
|
|
link1.href = `resources/dummy.${file_extension}?same-url`;
|
|
link2.href = `resources/dummy.${file_extension}?same-url`;
|
|
return Promise.all([
|
|
attachAndWaitForLoad(link1),
|
|
attachAndWaitForLoad(link2),
|
|
]);
|
|
}, `multiple ${destination} link rel=modulepreload with same href`);
|
|
};
|
|
</script>
|
|
</body>
|