| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 
 | <!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>
 |