<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>
<script src="/common/utils.js"></script>
<script>

// This is a regression test for https://crbug.com/1170038.
//
// A document creates a popup and makes it navigate elsewhere. The navigation
// will never commit. The popup has not completed any real load outside of the
// initial empty document. Then from a different window with a different CSP
// policy, make it navigate to about:blank.
//
// Web browser behavior might change depending on whether a pending navigation
// exists for in the popup or not. Both are tested here.

const same_origin = get_host_info().HTTP_ORIGIN;

// Return a promise, resolving when |element| triggers |event_name| event.
const future = (element, event_name) => {
  return new Promise(resolve => element.addEventListener(event_name, resolve));
};

// `createNewPopup` is a function returning a new window that has not committed
// any real load in its frame, outside of the initial empty document. The two
// tests below vary depending on whether there is a pending navigation in the
// frame or not.
const runTest = (description, createNewPopup) => {
  promise_test(async test => {
    // Open a same-origin window with a different CSP.
    const executor_path =
      "/html/browsers/sandboxing/resources/execute-postmessage.html?pipe=";
    const csp = "|header(Content-Security-Policy, " +
                "sandbox" +
                " allow-scripts" +
                " allow-popups" +
                " allow-same-origin" +
                " allow-popups-to-escape-sandbox";
    const executor = window.open(same_origin + executor_path + csp);
    const executor_reply = await future(window, "message");
    assert_equals(executor_reply.data, "ready");

    const popup_name = token();
    const popup = await createNewPopup(test, popup_name);

    // Request the first real load from a DIFFERENT window with different CSPs.
    const first_real_load = future(popup, "load");
    executor.postMessage(`window.open("about:blank", "${popup_name}");`);
    await first_real_load;

    // The new blank document in the popup must inherit CSPs from |executor|:
    let is_sandboxed = future(window, "message");
    popup.document.write(`
      <script>
        try {
          document.domain = document.domain;
          opener.opener.postMessage("not sandboxed", "*");
        } catch (error) {
          opener.opener.postMessage("sandboxed", "*");
        }
      </scr`+`ipt>
    `);
    assert_equals((await is_sandboxed).data, "sandboxed");
  }, description);
}

// Open a new window and start loading from an unresponsive server. The frame
// will be left with the initial empty document and a pending navigation.
runTest("One pending navigation", async (test, popup_name) => {
  const unresponsive_path =
    "/fetch/api/resources/infinite-slow-response.py";
  return window.open(same_origin + unresponsive_path, popup_name);
});

// Open a new window and start loading. The response is a 204 and the navigation
// is canceled. As a result, the frame will be left with the initial empty
// document and NO pending navigation.
runTest("No pending navigation", async (test, popup_name) => {
  const no_content_path = "/common/blank.html?pipe=status(204)"
  const popup = window.open(same_origin + no_content_path, popup_name);

  // Unfortunately, there are no web API to detect a navigation has been
  // canceled. Waiting using setTimeout is the only possible way to wait for it.
  await new Promise(r => test.step_timeout(r, 1000));

  return popup;
});

</script>
