forked from mirrors/gecko-dev
		
	Ensure firing the onStateChange on the BrowsingContext's WebProgress of the page we navigate *from* instead of the one we navigate *to*. (which was what used to happen before fission/bfcacheInParent) Differential Revision: https://phabricator.services.mozilla.com/D119648
		
			
				
	
	
		
			233 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/* Any copyright is dedicated to the Public Domain.
 | 
						|
   http://creativecommons.org/publicdomain/zero/1.0/ */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
add_task(async function() {
 | 
						|
  const tab = await BrowserTestUtils.openNewForegroundTab(
 | 
						|
    gBrowser,
 | 
						|
    "about:blank"
 | 
						|
  );
 | 
						|
  const browser = tab.linkedBrowser;
 | 
						|
  const aboutBlankBrowsingContext = browser.browsingContext;
 | 
						|
  const { webProgress } = aboutBlankBrowsingContext;
 | 
						|
  ok(
 | 
						|
    webProgress,
 | 
						|
    "Got a WebProgress interface on BrowsingContext in the parent process"
 | 
						|
  );
 | 
						|
  is(
 | 
						|
    webProgress.browsingContext,
 | 
						|
    browser.browsingContext,
 | 
						|
    "WebProgress.browsingContext refers to the right BrowsingContext"
 | 
						|
  );
 | 
						|
 | 
						|
  const onLocationChanged = waitForNextLocationChange(webProgress);
 | 
						|
  const newLocation = "data:text/html;charset=utf-8,first-page";
 | 
						|
  let loaded = BrowserTestUtils.browserLoaded(browser);
 | 
						|
  BrowserTestUtils.loadURI(browser, newLocation);
 | 
						|
  await loaded;
 | 
						|
 | 
						|
  const firstPageBrowsingContext = browser.browsingContext;
 | 
						|
  const isFissionAndBfcacheInParentEnabled =
 | 
						|
    SpecialPowers.useRemoteSubframes &&
 | 
						|
    SpecialPowers.Services.prefs.getBoolPref("fission.bfcacheInParent");
 | 
						|
  if (isFissionAndBfcacheInParentEnabled) {
 | 
						|
    isnot(
 | 
						|
      aboutBlankBrowsingContext,
 | 
						|
      firstPageBrowsingContext,
 | 
						|
      "With fission and bfcache in parent, navigations spawn a new BrowsingContext"
 | 
						|
    );
 | 
						|
  } else {
 | 
						|
    is(
 | 
						|
      aboutBlankBrowsingContext,
 | 
						|
      firstPageBrowsingContext,
 | 
						|
      "Without fission or bfcache in parent, navigations reuse the same BrowsingContext"
 | 
						|
    );
 | 
						|
  }
 | 
						|
 | 
						|
  info("Wait for onLocationChange to be fired");
 | 
						|
  {
 | 
						|
    const {
 | 
						|
      browsingContext,
 | 
						|
      location,
 | 
						|
      request,
 | 
						|
      flags,
 | 
						|
    } = await onLocationChanged;
 | 
						|
    is(
 | 
						|
      browsingContext,
 | 
						|
      firstPageBrowsingContext,
 | 
						|
      "Location change fires on the new BrowsingContext"
 | 
						|
    );
 | 
						|
    ok(location instanceof Ci.nsIURI);
 | 
						|
    is(location.spec, newLocation);
 | 
						|
    ok(request instanceof Ci.nsIChannel);
 | 
						|
    is(request.URI.spec, newLocation);
 | 
						|
    is(flags, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  const onIframeLocationChanged = waitForNextLocationChange(webProgress);
 | 
						|
  const iframeLocation = "data:text/html;charset=utf-8,iframe";
 | 
						|
  const iframeBC = await SpecialPowers.spawn(
 | 
						|
    browser,
 | 
						|
    [iframeLocation],
 | 
						|
    async url => {
 | 
						|
      const iframe = content.document.createElement("iframe");
 | 
						|
      await new Promise(resolve => {
 | 
						|
        iframe.addEventListener("load", resolve, { once: true });
 | 
						|
        iframe.src = url;
 | 
						|
        content.document.body.appendChild(iframe);
 | 
						|
      });
 | 
						|
 | 
						|
      return iframe.browsingContext;
 | 
						|
    }
 | 
						|
  );
 | 
						|
  ok(
 | 
						|
    iframeBC.webProgress,
 | 
						|
    "The iframe BrowsingContext also exposes a WebProgress"
 | 
						|
  );
 | 
						|
  {
 | 
						|
    const {
 | 
						|
      browsingContext,
 | 
						|
      location,
 | 
						|
      request,
 | 
						|
      flags,
 | 
						|
    } = await onIframeLocationChanged;
 | 
						|
    is(
 | 
						|
      browsingContext,
 | 
						|
      iframeBC,
 | 
						|
      "Iframe location change fires on the iframe BrowsingContext"
 | 
						|
    );
 | 
						|
    ok(location instanceof Ci.nsIURI);
 | 
						|
    is(location.spec, iframeLocation);
 | 
						|
    ok(request instanceof Ci.nsIChannel);
 | 
						|
    is(request.URI.spec, iframeLocation);
 | 
						|
    is(flags, 0);
 | 
						|
  }
 | 
						|
 | 
						|
  const onSecondLocationChanged = waitForNextLocationChange(webProgress);
 | 
						|
  const onSecondPageDocumentStart = waitForNextDocumentStart(webProgress);
 | 
						|
  const secondLocation = "http://example.com/document-builder.sjs?html=com";
 | 
						|
  loaded = BrowserTestUtils.browserLoaded(browser);
 | 
						|
  BrowserTestUtils.loadURI(browser, secondLocation);
 | 
						|
  await loaded;
 | 
						|
 | 
						|
  const secondPageBrowsingContext = browser.browsingContext;
 | 
						|
  if (isFissionAndBfcacheInParentEnabled) {
 | 
						|
    isnot(
 | 
						|
      firstPageBrowsingContext,
 | 
						|
      secondPageBrowsingContext,
 | 
						|
      "With fission and bfcache in parent, navigations spawn a new BrowsingContext"
 | 
						|
    );
 | 
						|
  } else {
 | 
						|
    is(
 | 
						|
      firstPageBrowsingContext,
 | 
						|
      secondPageBrowsingContext,
 | 
						|
      "Without fission or bfcache in parent, navigations reuse the same BrowsingContext"
 | 
						|
    );
 | 
						|
  }
 | 
						|
  {
 | 
						|
    const {
 | 
						|
      browsingContext,
 | 
						|
      location,
 | 
						|
      request,
 | 
						|
      flags,
 | 
						|
    } = await onSecondLocationChanged;
 | 
						|
    is(
 | 
						|
      browsingContext,
 | 
						|
      secondPageBrowsingContext,
 | 
						|
      "Second location change fires on the new BrowsingContext"
 | 
						|
    );
 | 
						|
    ok(location instanceof Ci.nsIURI);
 | 
						|
    is(location.spec, secondLocation);
 | 
						|
    ok(request instanceof Ci.nsIChannel);
 | 
						|
    is(request.URI.spec, secondLocation);
 | 
						|
    is(flags, 0);
 | 
						|
  }
 | 
						|
  {
 | 
						|
    const { browsingContext, request } = await onSecondPageDocumentStart;
 | 
						|
    is(
 | 
						|
      browsingContext,
 | 
						|
      firstPageBrowsingContext,
 | 
						|
      "STATE_START, when navigating to another process, fires on the BrowsingContext we navigate *from*"
 | 
						|
    );
 | 
						|
    ok(request instanceof Ci.nsIChannel);
 | 
						|
    is(request.URI.spec, secondLocation);
 | 
						|
  }
 | 
						|
 | 
						|
  const onBackLocationChanged = waitForNextLocationChange(webProgress);
 | 
						|
  const onBackDocumentStart = waitForNextDocumentStart(webProgress);
 | 
						|
  browser.goBack();
 | 
						|
 | 
						|
  {
 | 
						|
    const {
 | 
						|
      browsingContext,
 | 
						|
      location,
 | 
						|
      request,
 | 
						|
      flags,
 | 
						|
    } = await onBackLocationChanged;
 | 
						|
    is(
 | 
						|
      browsingContext,
 | 
						|
      firstPageBrowsingContext,
 | 
						|
      "location change, when navigating back, fires on the BrowsingContext we navigate *to*"
 | 
						|
    );
 | 
						|
    ok(location instanceof Ci.nsIURI);
 | 
						|
    is(location.spec, newLocation);
 | 
						|
    ok(request instanceof Ci.nsIChannel);
 | 
						|
    is(request.URI.spec, newLocation);
 | 
						|
    is(flags, 0);
 | 
						|
  }
 | 
						|
  {
 | 
						|
    const { browsingContext, request } = await onBackDocumentStart;
 | 
						|
    is(
 | 
						|
      browsingContext,
 | 
						|
      secondPageBrowsingContext,
 | 
						|
      "STATE_START, when navigating back, fires on the BrowsingContext we navigate *from*"
 | 
						|
    );
 | 
						|
    ok(request instanceof Ci.nsIChannel);
 | 
						|
    is(request.URI.spec, newLocation);
 | 
						|
  }
 | 
						|
 | 
						|
  BrowserTestUtils.removeTab(tab);
 | 
						|
});
 | 
						|
 | 
						|
function waitForNextLocationChange(webProgress) {
 | 
						|
  return new Promise(resolve => {
 | 
						|
    const wpl = {
 | 
						|
      QueryInterface: ChromeUtils.generateQI([
 | 
						|
        "nsIWebProgressListener",
 | 
						|
        "nsISupportsWeakReference",
 | 
						|
      ]),
 | 
						|
      onLocationChange(progress, request, location, flags) {
 | 
						|
        webProgress.removeProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
 | 
						|
        resolve({
 | 
						|
          browsingContext: progress.browsingContext,
 | 
						|
          location,
 | 
						|
          request,
 | 
						|
          flags,
 | 
						|
        });
 | 
						|
      },
 | 
						|
    };
 | 
						|
    webProgress.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
 | 
						|
  });
 | 
						|
}
 | 
						|
 | 
						|
function waitForNextDocumentStart(webProgress) {
 | 
						|
  return new Promise(resolve => {
 | 
						|
    const wpl = {
 | 
						|
      QueryInterface: ChromeUtils.generateQI([
 | 
						|
        "nsIWebProgressListener",
 | 
						|
        "nsISupportsWeakReference",
 | 
						|
      ]),
 | 
						|
      onStateChange(progress, request, flags, status) {
 | 
						|
        if (
 | 
						|
          flags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT &&
 | 
						|
          flags & Ci.nsIWebProgressListener.STATE_START
 | 
						|
        ) {
 | 
						|
          webProgress.removeProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
 | 
						|
          resolve({ browsingContext: progress.browsingContext, request });
 | 
						|
        }
 | 
						|
      },
 | 
						|
    };
 | 
						|
    webProgress.addProgressListener(wpl, Ci.nsIWebProgress.NOTIFY_ALL);
 | 
						|
  });
 | 
						|
}
 |