<!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>