| <!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> | |
| // Dynamic style using document.write in head | |
| document.write(` | |
| <link rel=stylesheet | |
| href='resources/empty_style.css?stylesheet-head-dynamic-docWrite'> | |
| `); | |
| document.write(` | |
| <link rel=stylesheet | |
| href='resources/empty_style.css?stylesheet-head-dynamic-docWrite-print' | |
| media=print> | |
| `); | |
| </script> | |
| <link rel=stylesheet href="resources/empty_style.css?stylesheet-head"> | |
| <link rel=stylesheet href="resources/empty_style.css?stylesheet-head-media-print" | |
| media=print> | |
| <link rel="alternate stylesheet" | |
| href="resources/empty_style.css?stylesheet-head-alternate"> | |
| <link rel=preload as=style href="resources/empty_style.css?link-style-head-preload"> | |
| <link rel=preload as=style href="resources/empty_style.css?link-style-preload-used"> | |
| <link rel=preload as=style href="resources/empty_style.css?link-style-preload-used-immediately"> | |
| <link rel=stylesheet href="resources/empty_style.css?link-style-preload-used-immediately"> | |
| <link rel=preload as=style href="resources/empty_style.css?link-style-preload-used-immediately-then-preloaded-again"> | |
| <link rel=stylesheet href="resources/empty_style.css?link-style-preload-used-immediately-then-preloaded-again"> | |
| <link rel=preload as=style href="resources/empty_style.css?link-style-preload-used-immediately-then-preloaded-again"> | |
| <link rel=stylesheet href="resources/importer.css?stylesheet-importer-head"> | |
| <link rel=stylesheet id="link-head-remove-attr" blocking="render" | |
| href="resources/empty_style.css?stylesheet-head-blocking-render-remove-attr"> | |
| <link rel=modulepreload href="resources/empty_script.js?link-head-modulepreload"> | |
| <link rel=preload as="script" href="resources/empty_script.js?link-script-preload-used-immediately"> | |
| <script src="resources/empty_script.js?link-script-preload-used-immediately"></script> | |
| <link rel=preload as="script" href="resources/empty_script.js?link-script-preload-defer-used-immediately"> | |
| <script defer src="resources/empty_script.js?link-script-preload-defer-used-immediately"></script> | |
| <style>@import url(resources/empty_style.css?stylesheet-inline-imported);</style> | |
| <style media=print> | |
| @import url(resources/empty_style.css?stylesheet-inline-imported-print); | |
| </style> | |
| </head> | |
| <body> | |
| <link rel=stylesheet href="resources/empty_style.css?stylesheet-body"> | |
| <link rel=stylesheet href="resources/importer.css?stylesheet-importer-body"> | |
| <link rel=stylesheet href="resources/empty_style.css?stylesheet-body-media-print" | |
| media=print> | |
| <link rel=stylesheet blocking="render" | |
| href="resources/empty_style.css?stylesheet-body-blocking-render"> | |
| <img src="resources/blue.png?link-image-preload-used-immediately"> | |
| <!-- https://html.spec.whatwg.org/multipage/urls-and-fetching.html#blocking-attributes | |
| mentions that an element is potentially render-blocking if its blocking | |
| tokens set contains "render", or if it is implicitly potentially | |
| render-blocking. By default, an element is not implicitly potentially | |
| render-blocking. | |
| https://html.spec.whatwg.org/multipage/links.html#link-type-stylesheet | |
| specifies that a link element of type stylesheet is implicitly potentially | |
| render-blocking only if the element was created by its node document's parser. --> | |
| <script> | |
| // Dynamic style using document.write in body | |
| document.write(` | |
| <link rel=stylesheet | |
| href='resources/empty_style.css?stylesheet-body-dynamic-docWrite'> | |
| `); | |
| document.write(` | |
| <link rel=stylesheet | |
| href='resources/empty_style.css?stylesheet-body-dynamic-docWrite-print' | |
| media=print> | |
| `); | |
| // Dynamic style using innerHTML | |
| document.head.innerHTML += ` | |
| <link rel=stylesheet | |
| href='resources/empty_style.css?stylesheet-head-dynamic-innerHTML'> | |
| `; | |
| document.head.innerHTML += ` | |
| <link rel=stylesheet | |
| href='resources/empty_style.css?stylesheet-head-dynamic-innerHTML-print' | |
| media=print> | |
| `; | |
| document.head.innerHTML += ` | |
| <link rel=stylesheet blocking=render | |
| href='resources/empty_style.css?stylesheet-head-blocking-render-dynamic-innerHTML'> | |
| `; | |
| // Dynamic style using DOM API | |
| var link = document.createElement("link"); | |
| link.href = "resources/empty_style.css?stylesheet-head-dynamic-dom"; | |
| link.rel = "stylesheet"; | |
| document.head.appendChild(link); | |
| // Add a dynamic render-blocking style with DOM API | |
| link = document.createElement("link"); | |
| link.href = "resources/empty_style.css?stylesheet-head-blocking-render-dynamic-dom"; | |
| link.rel = "stylesheet"; | |
| link.blocking = "render"; | |
| document.head.appendChild(link); | |
| // Dynamic style preload using DOM API | |
| link = document.createElement("link"); | |
| link.href = "resources/empty_style.css?link-style-head-preload-dynamic-dom"; | |
| link.rel = "preload"; | |
| link.as = "style"; | |
| document.head.appendChild(link); | |
| // Dynamic module via modulepreload using DOM API | |
| link = document.createElement("link"); | |
| link.href = "resources/empty_script.js?link-head-modulepreload-dynamic-dom"; | |
| link.rel = "modulepreload"; | |
| document.head.appendChild(link); | |
| // Add a style preload with DOM API to be used later | |
| link = document.createElement("link"); | |
| link.href = "resources/empty_style.css?link-style-preload-used-dynamic"; | |
| link.rel = "preload"; | |
| link.as = "style"; | |
| document.head.appendChild(link); | |
| // Use the preload | |
| link = document.createElement("link"); | |
| link.href = "resources/empty_style.css?link-style-preload-used-dynamic"; | |
| link.rel = "stylesheet"; | |
| document.head.appendChild(link); | |
| // Dynamic inline CSS | |
| // Add an inline CSS importer | |
| document.write(` | |
| <style> | |
| @import url('resources/empty_style.css?stylesheet-inline-imported-dynamic-docwrite') | |
| </style> | |
| `); | |
| document.write(` | |
| <style media=print> | |
| @import url('resources/empty_style.css?stylesheet-inline-imported-dynamic-docwrite-print') | |
| </style> | |
| `); | |
| // Add a dynamic inline CSS importer using DOM API | |
| let style = document.createElement("style"); | |
| style.textContent = "@import url('resources/empty_style.css?stylesheet-inline-imported-dynamic-dom')"; | |
| document.head.appendChild(style); | |
| // Add a dynamic render-blocking inline CSS importer | |
| style = document.createElement("style"); | |
| style.textContent = "@import url('resources/empty_style.css?stylesheet-inline-imported-blocking-render-dynamic-dom')"; | |
| style.blocking = "render"; | |
| document.head.appendChild(style); | |
| // Dynamic CSS importer | |
| document.write(` | |
| <link rel=stylesheet href='resources/importer_dynamic.css'> | |
| `); | |
| document.write(` | |
| <link rel=stylesheet href='resources/importer_print.css' media=print> | |
| `); | |
| // Removing blocking render attribute after request is made | |
| const sheet = document.getElementById("link-head-remove-attr"); | |
| sheet.blocking = ""; | |
| </script> | |
| <link rel=stylesheet href="resources/empty_style.css?link-style-preload-used"> | |
| <script> | |
| const wait_for_onload = () => { | |
| return new Promise(resolve => { | |
| window.addEventListener("load", resolve); | |
| })}; | |
| promise_test( | |
| async () => { | |
| const expectedRenderBlockingStatus = { | |
| 'stylesheet-head-dynamic-docWrite' : 'blocking', | |
| 'stylesheet-head-dynamic-docWrite-print' : 'non-blocking', | |
| 'stylesheet-head' : 'blocking', | |
| 'stylesheet-head-media-print' : 'non-blocking', | |
| 'stylesheet-head-alternate' : 'non-blocking', | |
| 'link-style-head-preload' : 'non-blocking', | |
| 'stylesheet-importer-head' : 'blocking', | |
| 'stylesheet-head-blocking-render-remove-attr' : 'blocking', | |
| 'link-head-modulepreload' : 'non-blocking', | |
| 'stylesheet-inline-imported' : 'blocking', | |
| 'stylesheet-inline-imported-print' : 'non-blocking', | |
| 'stylesheet-body': 'non-blocking', | |
| 'stylesheet-importer-body' : 'non-blocking', | |
| 'stylesheet-body-media-print' : 'non-blocking', | |
| 'stylesheet-body-blocking-render' : 'non-blocking', | |
| 'stylesheet-body-dynamic-docWrite' : 'non-blocking', | |
| 'stylesheet-body-dynamic-docWrite-print': 'non-blocking', | |
| 'stylesheet-head-dynamic-innerHTML' : 'non-blocking', | |
| 'stylesheet-head-dynamic-innerHTML-print' : 'non-blocking', | |
| 'stylesheet-head-blocking-render-dynamic-innerHTML' : 'blocking', | |
| 'stylesheet-head-dynamic-dom' : 'non-blocking', | |
| 'stylesheet-head-blocking-render-dynamic-dom' : 'blocking', | |
| 'link-style-head-preload-dynamic-dom' : 'non-blocking', | |
| 'link-head-modulepreload-dynamic-dom' : 'non-blocking', | |
| 'link-style-preload-used' : 'non-blocking', | |
| 'link-style-preload-used-dynamic' : 'non-blocking', | |
| 'link-style-preload-used-immediately' : 'blocking', | |
| 'link-style-preload-used-immediately-then-preloaded-again' : 'blocking', | |
| 'stylesheet-inline-imported-dynamic-docwrite' : 'blocking', | |
| 'stylesheet-inline-imported-dynamic-docwrite-print' : 'non-blocking', | |
| 'stylesheet-inline-imported-dynamic-dom' : 'non-blocking', | |
| 'stylesheet-inline-imported-blocking-render-dynamic-dom' : 'blocking', | |
| 'stylesheet-imported' : 'blocking', | |
| 'stylesheet-imported-print' : 'non-blocking', | |
| 'stylesheet-imported-dynamic' : 'non-blocking', | |
| 'link-image-preload-used-immediately' : 'non-blocking', | |
| 'link-script-preload-used-immediately' : 'blocking', | |
| 'link-script-preload-defer-used-immediately' : 'non-blocking' | |
| }; | |
| await wait_for_onload(); | |
| const entry_list = performance.getEntriesByType("resource"); | |
| for (entry of entry_list) { | |
| if (entry.name.includes("empty_style.css") || | |
| entry.name.includes("importer.css") || | |
| entry.name.includes("empty_script.js") || | |
| entry.name.includes("blue.png")) { | |
| key = entry.name.split("?").pop(); | |
| expectedStatus = expectedRenderBlockingStatus[key]; | |
| assert_equals(entry.renderBlockingStatus, expectedStatus, | |
| `render blocking status for ${entry.name} should be ${expectedStatus}`); | |
| } | |
| } | |
| }, "Validate render blocking status of link resources in PerformanceResourceTiming"); | |
| </script> |