const executor_path = '/common/dispatcher/executor.html?pipe=';
const coop_header = policy => {
  return `|header(Cross-Origin-Opener-Policy,${policy})`;
};

function getExecutorPath(uuid, origin, coop_header) {
  return origin.origin + executor_path + coop_header + `&uuid=${uuid}`;
}

// Open a same-origin popup with `opener_coop` header, then open a popup with
// `openee_coop` header. Check whether the opener can script the openee.
const test_noopener_opening_popup = (
  opener_coop,
  openee_coop,
  origin,
  opener_expectation
) => {
  promise_test(async t => {
    // Set up dispatcher communications.
    const popup_token = token();
    const reply_token = token();
    const popup_reply_token = token();
    const popup_openee_token = token();

    const popup_url = getExecutorPath(
      popup_token, SAME_ORIGIN, coop_header(opener_coop));

    // We open a popup and then ping it, it will respond after loading.
    const popup = window.open(popup_url);
    t.add_cleanup(() => send(popup_token, 'window.close()'));
    send(popup_token, `send('${reply_token}', 'Popup loaded');`);
    assert_equals(await receive(reply_token), 'Popup loaded');

    if (opener_coop == 'noopener-allow-popups') {
      // Assert that we can't script the popup.
      await t.step_wait(() => popup.closed, 'Opener popup.closed')
    }

    // Ensure that the popup has no access to its opener.
    send(popup_token, `
      let openerDOMAccessAllowed = false;
      try {
        openerDOMAccessAllowed = !!self.opener.document.URL;
      } catch(ex) {}
      const payload = {
        opener: !!self.opener,
        openerDOMAccess: openerDOMAccessAllowed
      };
      send('${reply_token}', JSON.stringify(payload));
    `);
    let payload = JSON.parse(await receive(reply_token));
    if (opener_coop == 'noopener-allow-popups') {
      assert_false(payload.opener, 'popup opener');
      assert_false(payload.openerDOMAccess, 'popup DOM access');
    }

    // Open another popup from inside the popup, and wait for it to load.
    const popup_openee_url = getExecutorPath(popup_openee_token, origin,
      coop_header(openee_coop));
    send(popup_token, `
      window.openee = open("${popup_openee_url}");
      await receive('${popup_reply_token}');
      const payload = {
        openee: !!window.openee,
        closed: window.openee.closed
      };
      send('${reply_token}', JSON.stringify(payload));
    `);
    t.add_cleanup(() => send(popup_token, 'window.openee.close()'));
    // Notify the popup that its openee was loaded.
    send(popup_openee_token, `
      send('${popup_reply_token}', 'popup openee opened');
    `);

    // Assert that the popup has access to its openee.
    payload = JSON.parse(await receive(reply_token));
    assert_true(payload.openee, 'popup openee');

    // Assert that the openee has access to its popup opener.
    send(popup_openee_token, `
      let openerDOMAccessAllowed = false;
      try {
        openerDOMAccessAllowed = !!self.opener.document.URL;
      } catch(ex) {}
      const payload = {
        opener: !!self.opener,
        openerDOMAccess: openerDOMAccessAllowed
      };
      send('${reply_token}', JSON.stringify(payload));
    `);
    payload = JSON.parse(await receive(reply_token));
    if (opener_expectation) {
      assert_true(payload.opener, 'Opener is not null');
      assert_true(payload.openerDOMAccess, 'No DOM access');
    } else {
      assert_false(payload.opener, 'Opener is null');
      assert_false(payload.openerDOMAccess, 'No DOM access');
    }
  },
  'noopener-allow-popups ensures that the opener cannot script the openee,' +
  ' but further popups with no COOP can access their opener: ' +
  opener_coop + '/' + openee_coop + ':' + origin == SAME_ORIGIN);
};

// Open a same-origin popup with `popup_coop` header, then navigate away toward
// one with `noopener-allow-popups`. Check the opener can't script the openee.
const test_noopener_navigating_away = (popup_coop) => {
  promise_test(async t => {
    // Set up dispatcher communications.
    const popup_token = token();
    const reply_token = token();
    const popup_reply_token = token();
    const popup_second_token = token();

    const popup_url =
      getExecutorPath(popup_token, SAME_ORIGIN, coop_header(popup_coop));

    // We open a popup and then ping it, it will respond after loading.
    const popup = window.open(popup_url);
    send(popup_token, `send('${reply_token}', 'Popup loaded');`);
    assert_equals(await receive(reply_token), 'Popup loaded');
    t.add_cleanup(() => send(popup_token, 'window.close()'));

    // There's an open question if we should check that popup.window is null here.
    // See https://github.com/whatwg/html/issues/10457
    // Assert that we cannot script the popup.
    assert_false(popup.closed, 'popup closed');

    // Ensure that the popup has no access to its opener.
    send(popup_token, `
      let openerDOMAccessAllowed = false;
      try {
        openerDOMAccessAllowed = !!self.opener.document.URL;
      } catch(ex) {}
      const payload = {
        opener: !!self.opener,
        openerDOMAccess: openerDOMAccessAllowed
      };
      send('${reply_token}', JSON.stringify(payload));
    `);
    let payload = JSON.parse(await receive(reply_token));
    assert_true(payload.opener, 'popup opener');
    assert_true(payload.openerDOMAccess, 'popup DOM access');

    // Navigate the popup.
    const popup_second_url = getExecutorPath(
      popup_second_token, SAME_ORIGIN,
      coop_header('noopener-allow-popups'));

    send(popup_token, `
      window.location = '${popup_second_url}';
    `);

    // Notify the popup that its openee was loaded.
    send(popup_second_token, `
      send('${reply_token}', 'popup navigated away');
    `);
    assert_equals(await receive(reply_token), 'popup navigated away');

    // There's an open question if we should check that popup.window is null here.
    // See https://github.com/whatwg/html/issues/10457
    assert_true(popup.closed, 'popup.closed');
  },
  'noopener-allow-popups ensures that the opener cannot script the openee,' +
  ' even after a navigation: ' + popup_coop);
};
