<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>This test validates the render blocking status of resources.</title>
<link rel="help" href="https://www.w3.org/TR/resource-timing-2/#sec-performanceresourcetiming"/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!-- Start of test cases -->
<script src="resources/empty_script.js?script-head"></script>
<script type="module" src="resources/empty_script.js?script-head-module"></script>
<script async type=module
src="resources/empty_script.js?script-head-async-module">
</script>
<script async src="resources/empty_script.js?script-head-async"></script>
<script defer src="resources/empty_script.js?script-head-defer"></script>
<script blocking=render
src="resources/empty_script.js?script-head-blocking-render">
</script>
<script async blocking=render
src="resources/empty_script.js?script-head-async-blocking-render">
</script>
<script type=module blocking=render
src="resources/empty_script.js?script-head-module-blocking-render">
</script>
<script async type=module blocking=render
src="resources/empty_script.js?script-head-async-module-blocking-render">
</script>
<script defer blocking=render
src="resources/empty_script.js?script-head-defer-blocking-render">
</script>
<script id="script-head-remove-attr" blocking=render
src="resources/empty_script.js?script-head-blocking-render-remove-attr">
</script>
<script>
document.write(`
<script defer
src="resources/empty_script.js?script-head-defer-dynamic-docwrite">
<\/script>`);
</script>
</head>
<body>
<script src="resources/empty_script.js?script-body"></script>
<script type="module" src="resources/empty_script.js?script-body-module"></script>
<script async type=module
src="resources/empty_script.js?script-body-async-module">
</script>
<script async src="resources/empty_script.js?script-body-async"></script>
<script defer src="resources/empty_script.js?script-body-defer"></script>
<script>
const script = document.createElement("script");
script.src = "resources/empty_script.js?script-head-dynamic-dom";
document.head.appendChild(script);
// Dynamic explicitly async script
const async_script = document.createElement("script");
async_script.src = "resources/empty_script.js?script-head-async-dynamic-dom";
async_script.async = true;
document.head.appendChild(async_script);
// Dynamic non-async script
// https://html.spec.whatwg.org/multipage/scripting.html#script-processing-model
// mentions that a script element has to be parser-inserted to be
// implicitly potentially render-blocking
const non_async_script = document.createElement("script");
non_async_script.src = "resources/empty_script.js?script-head-non-async-dynamic-dom";
non_async_script.async = false;
document.head.appendChild(non_async_script);
// Dynamic defer script
const defer_script = document.createElement("script");
defer_script.src = "resources/empty_script.js?script-head-defer-dynamic-dom";
defer_script.defer = true;
document.head.appendChild(defer_script);
// Dynamic explicitly render-blocking script
const blocking_script = document.createElement("script");
blocking_script.src = "resources/empty_script.js?script-head-blocking-render-dynamic-dom";
blocking_script.blocking = "render";
document.head.appendChild(blocking_script);
// Dynamic explicitly render-blocking module script
const blocking_module_script = document.createElement("script");
blocking_module_script.src = "resources/empty_script.js?script-head-module-blocking-render-dynamic-dom";
blocking_module_script.type = "module";
blocking_module_script.blocking = "render";
document.head.appendChild(blocking_module_script);
// Dynamic async module script
const async_module_script = document.createElement("script");
async_module_script.src = "resources/empty_script.js?script-head-async-module-dynamic-dom";
async_module_script.type = "module";
async_module_script.async = true;
document.head.appendChild(async_module_script);
// Dynamic async render-blocking module script
const async_blocking_module_script = document.createElement("script");
async_blocking_module_script.src = "resources/empty_script.js?script-head-async-module-blocking-render-dynamic-dom";
async_blocking_module_script.type = "module";
async_blocking_module_script.async = true;
async_blocking_module_script.blocking = "render"
document.head.appendChild(async_blocking_module_script);
// Add a module that imports more modules
const importer_script = document.createElement("script");
importer_script.src = "resources/fake_responses.py?url=importer.js";
importer_script.type = "module";
document.head.appendChild(importer_script);
// Add an async module that imports more modules
const importer_async_script = document.createElement("script");
importer_async_script.src = "resources/fake_responses.py?url=importer_async.js";
importer_async_script.type = "module";
importer_async_script.async = true;
document.head.appendChild(importer_async_script);
// Removing blocking render attribute after request is made
const script_element = document.getElementById("script-head-remove-attr");
script_element.blocking = "";
</script>
<script>
const wait_for_onload = () => {
return new Promise(resolve => {
window.addEventListener("load", resolve);
})};
promise_test(
async () => {
const expectedRenderBlockingStatus = {
'script-head': 'blocking',
'script-head-module' : 'non-blocking',
'script-head-async-module' : 'non-blocking',
'script-head-async' : 'non-blocking',
'script-head-defer' : 'non-blocking',
'script-head-blocking-render' : 'blocking',
'script-head-async-blocking-render' : 'blocking',
'script-head-module-blocking-render' : 'blocking',
'script-head-async-module-blocking-render' : 'blocking',
'script-head-defer-blocking-render' : 'blocking',
'script-head-blocking-render-remove-attr' : 'blocking',
'script-head-defer-dynamic-docwrite' : 'non-blocking',
'script-body' : 'non-blocking',
'script-body-module' : 'non-blocking',
'script-body-async-module' : 'non-blocking',
'script-body-async' : 'non-blocking',
'script-body-defer' : 'non-blocking',
'script-head-dynamic-dom': 'non-blocking',
'script-head-async-dynamic-dom' : 'non-blocking',
'script-head-non-async-dynamic-dom': 'non-blocking',
'script-head-defer-dynamic-dom' : 'non-blocking',
'script-head-blocking-render-dynamic-dom' : 'blocking',
'script-head-module-blocking-render-dynamic-dom' : 'blocking',
'script-head-async-module-dynamic-dom' : 'non-blocking',
'script-head-async-module-blocking-render-dynamic-dom' : 'blocking',
'script-head-import-defer' : 'non-blocking',
'script-head-import-defer-dynamic' : 'non-blocking',
'script-head-import-async' : 'non-blocking',
'script-head-import-async-dynamic' : 'non-blocking',
'script-importer' : 'non-blocking',
'script-importer-async' : 'non-blocking'
};
await wait_for_onload();
const entry_list = performance.getEntriesByType("resource");
for (entry of entry_list) {
if (entry.name.includes("empty_script.js")) {
key = entry.name.split("?").pop();
expectedStatus = expectedRenderBlockingStatus[key];
assert_equals(entry.renderBlockingStatus, expectedStatus,
`render blocking status for ${entry.name} should be ${expectedStatus}`);
}
else if (entry.name.includes("importer.js")){
key = 'script-importer';
expectedStatus = expectedRenderBlockingStatus[key];
assert_equals(entry.renderBlockingStatus, expectedStatus,
`render blocking status for ${entry.name} should be ${expectedStatus}`);
}
else if (entry.name.includes("importer_async.js")){
key = 'script-importer-async';
expectedStatus = expectedRenderBlockingStatus[key];
assert_equals(entry.renderBlockingStatus, expectedStatus,
`render blocking status for ${entry.name} should be ${expectedStatus}`);
}
}
}, "Validate render blocking status of script resources in PerformanceResourceTiming");
</script>