<!DOCTYPE html>
<title>WindowClient.navigate() on a prerendered iframe</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/speculation-rules/prerender/resources/utils.js"></script>
<script src="/speculation-rules/prerender/resources/deferred-promise-utils.js"></script>
<body>
<script>
// The main test page loads the initiator page, then the initiator page will
// prerender itself with the `prerendering` parameter and add an iframe. Once
// the prerendered iframe is ready, post a message to a service worker to call
// WindowClient.navigate().

const params = new URLSearchParams(location.search);
const prerendering = params.has('prerendering');
const navigationUrl = params.get('navigationUrl');
const uid = params.get('uid');

const IFRAME_URL = `prerendered-iframe.html?uid=${uid}`;

function addIframe() {
  const iframe = document.createElement('iframe');
  iframe.src = IFRAME_URL;
  document.body.appendChild(iframe);
}

// If the navigation is expected to be deferred, wait to navigate to
// `navigationUrl` until a prerendered iframe is activated by
// PrerenderEventCollector. The result of the navigation is sent to
// "navigation-channel" PrerenderChannel and the prerendering states and events
// is sent to "test-channel" PrerenderChannel by PrerenderEventCollector.
async function startNavigationToCrossOriginUrl() {
  assert_not_equals(new URL(navigationUrl).origin, window.location.origin);

  const navigationPromise = new Promise(resolve => {
    const bc = new PrerenderChannel('navigation-channel', uid);
    bc.addEventListener('message', e => {
      assert_equals(e.data, 'navigate() succeeded');
      resolve()
      bc.close();
    });
    bc.postMessage(JSON.stringify({
      navigationUrl: navigationUrl,
      clientUrl: new URL(IFRAME_URL, window.location).toString(),
      respondTo: 'navigation-channel',
    }));
  });

  const prerenderEventCollector = new PrerenderEventCollector();
  prerenderEventCollector.start(navigationPromise, 'navigation on iframe');
}

// If the navigation is expected to succeed without delay, the navigation result
// is directly sent to "test-channel" PrerenderChannel.
function startNavigationToSameOriginUrl() {
  assert_equals(new URL(navigationUrl).origin, window.location.origin);

  const bc = new PrerenderChannel('navigation-channel', uid);
  bc.postMessage(JSON.stringify({
    navigationUrl: navigationUrl,
    clientUrl: new URL(IFRAME_URL, window.location).toString(),
    respondTo: 'test-channel',
  }));
  bc.close();
}

if (prerendering) {
  assert_not_equals(null, navigator.serviceWorker.controller,
      'should be controlled by a service worker');

  const bc = new PrerenderChannel('iframe-channel', uid);
  const readyPromise = new Promise(resolve => {
    bc.addEventListener('message', e => {
      resolve(e.data);
    }, {
      once: true
    });
  });

  addIframe();

  readyPromise.then(result => {
    assert_equals(result, 'prerender success');

    if (new URL(navigationUrl).origin === window.location.origin) {
      startNavigationToSameOriginUrl();
    } else {
      startNavigationToCrossOriginUrl();
    }

    bc.close();
  });
} else {
  loadInitiatorPage();
}
</script>
</body>
