Blame dom/base/test/browser_state_notifications.js

Packit f0b94e
/* globals Components: true, Promise: true, gBrowser: true, Test: true,
Packit f0b94e
           info: true, is: true, window: true, waitForExplicitFinish: true,
Packit f0b94e
           finish: true, ok: true*/
Packit f0b94e
Packit f0b94e
"use strict";
Packit f0b94e
Packit f0b94e
const { addObserver, removeObserver } = Cc["@mozilla.org/observer-service;1"].
Packit f0b94e
                                          getService(Ci.nsIObserverService);
Packit f0b94e
const { openWindow } = Cc["@mozilla.org/embedcomp/window-watcher;1"].
Packit f0b94e
                         getService(Ci.nsIWindowWatcher);
Packit f0b94e
Packit f0b94e
const Test = routine => () => {
Packit f0b94e
  waitForExplicitFinish();
Packit f0b94e
  routine()
Packit f0b94e
      .then(finish, error => {
Packit f0b94e
        ok(false, error);
Packit f0b94e
        finish();
Packit f0b94e
      });
Packit f0b94e
};
Packit f0b94e
Packit f0b94e
// Returns promise for the observer notification subject for
Packit f0b94e
// the given topic. If `receive("foo")` is called `n` times
Packit f0b94e
// nth promise is resolved on an `nth` "foo" notification.
Packit f0b94e
const receive = (topic, p, syncCallback) => {
Packit f0b94e
  return new Promise((resolve, reject) => {
Packit f0b94e
    const { queue } = receive;
Packit f0b94e
    const timeout = () => {
Packit f0b94e
      queue.splice(queue.indexOf(resolve) - 1, 2);
Packit f0b94e
      reject(new Error("Timeout"));
Packit f0b94e
    };
Packit f0b94e
Packit f0b94e
    const observer = {
Packit f0b94e
      observe: subject => {
Packit f0b94e
        // Browser loads bunch of other documents that we don't care
Packit f0b94e
        // about so we let allow filtering notifications via `p` function.
Packit f0b94e
        if (p && !p(subject)) return;
Packit f0b94e
        // If observer is a first one with a given `topic`
Packit f0b94e
        // in a queue resolve promise and take it off the queue
Packit f0b94e
        // otherwise keep waiting.
Packit f0b94e
        const index = queue.indexOf(topic);
Packit f0b94e
        if (queue.indexOf(resolve) === index + 1) {
Packit f0b94e
          removeObserver(observer, topic);
Packit f0b94e
          clearTimeout(id, reject);
Packit f0b94e
          queue.splice(index, 2);
Packit f0b94e
          // Some tests need to be executed synchronously when the event is fired.
Packit f0b94e
          if (syncCallback) {
Packit f0b94e
            syncCallback(subject);
Packit f0b94e
          }
Packit f0b94e
          resolve(subject);
Packit f0b94e
        }
Packit f0b94e
      }
Packit f0b94e
    };
Packit f0b94e
    const id = setTimeout(timeout, 90000);
Packit f0b94e
    addObserver(observer, topic, false);
Packit f0b94e
    queue.push(topic, resolve);
Packit f0b94e
  });
Packit f0b94e
};
Packit f0b94e
receive.queue = [];
Packit f0b94e
Packit f0b94e
const openTab = uri => gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, uri);
Packit f0b94e
Packit f0b94e
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
Packit f0b94e
Packit f0b94e
const isData = document => document.URL.startsWith("data:");
Packit f0b94e
Packit f0b94e
const uri1 = "data:text/html;charset=utf-8,

1

";
Packit f0b94e
// For whatever reason going back on load event doesn't work so timeout it is :(
Packit f0b94e
const uri2 = "data:text/html;charset=utf-8,

2

<script>setTimeout(SpecialPowers.wrap(window).back,100)</script>";
Packit f0b94e
const uri3 = "data:text/html;charset=utf-8,

3

";
Packit f0b94e
Packit f0b94e
const uri4 = "chrome://browser/content/license.html";
Packit f0b94e
Packit f0b94e
const test = Test(async function() {
Packit f0b94e
  let documentInteractive = receive("content-document-interactive", isData, d => {
Packit f0b94e
    // This test is executed synchronously when the event is received.
Packit f0b94e
    is(d.readyState, "interactive", "document is interactive");
Packit f0b94e
    is(d.URL, uri1, "document.URL matches tab url");
Packit f0b94e
  });
Packit f0b94e
  let documentLoaded = receive("content-document-loaded", isData);
Packit f0b94e
  let pageShown = receive("content-page-shown", isData);
Packit f0b94e
Packit f0b94e
  info("open: uri#1");
Packit f0b94e
  const tab1 = openTab(uri1);
Packit f0b94e
  const browser1 = gBrowser.getBrowserForTab(tab1);
Packit f0b94e
Packit f0b94e
  let interactiveDocument1 = await documentInteractive;
Packit f0b94e
Packit f0b94e
  let loadedDocument1 = await documentLoaded;
Packit f0b94e
  is(loadedDocument1.readyState, "complete", "document is loaded");
Packit f0b94e
  is(interactiveDocument1, loadedDocument1, "interactive document is loaded");
Packit f0b94e
Packit f0b94e
  let shownPage = await pageShown;
Packit f0b94e
  is(interactiveDocument1, shownPage, "loaded document is shown");
Packit f0b94e
Packit f0b94e
  // Wait until history entry is created before loading new uri.
Packit f0b94e
  await receive("sessionstore-state-write-complete");
Packit f0b94e
Packit f0b94e
  info("load uri#2");
Packit f0b94e
Packit f0b94e
  documentInteractive = receive("content-document-interactive", isData, d => {
Packit f0b94e
    // This test is executed synchronously when the event is received.
Packit f0b94e
    is(d.readyState, "interactive", "document is interactive");
Packit f0b94e
    is(d.URL, uri2, "document.URL matches URL loaded");
Packit f0b94e
  });
Packit f0b94e
  documentLoaded = receive("content-document-loaded", isData);
Packit f0b94e
  pageShown = receive("content-page-shown", isData);
Packit f0b94e
  let pageHidden = receive("content-page-hidden", isData);
Packit f0b94e
Packit f0b94e
  browser1.loadURI(uri2);
Packit f0b94e
Packit f0b94e
  let hiddenPage = await pageHidden;
Packit f0b94e
  is(interactiveDocument1, hiddenPage, "loaded document is hidden");
Packit f0b94e
Packit f0b94e
  let interactiveDocument2 = await documentInteractive;
Packit f0b94e
Packit f0b94e
  let loadedDocument2 = await documentLoaded;
Packit f0b94e
  is(loadedDocument2.readyState, "complete", "document is loaded");
Packit f0b94e
  is(interactiveDocument2, loadedDocument2, "interactive document is loaded");
Packit f0b94e
Packit f0b94e
  shownPage = await pageShown;
Packit f0b94e
  is(interactiveDocument2, shownPage, "loaded document is shown");
Packit f0b94e
Packit f0b94e
  info("go back to uri#1");
Packit f0b94e
Packit f0b94e
Packit f0b94e
  documentInteractive = receive("content-document-interactive", isData, d => {
Packit f0b94e
    // This test is executed synchronously when the event is received.
Packit f0b94e
    is(d.readyState, "interactive", "document is interactive");
Packit f0b94e
    is(d.URL, uri3, "document.URL matches URL loaded");
Packit f0b94e
  });
Packit f0b94e
  documentLoaded = receive("content-document-loaded", isData);
Packit f0b94e
  pageShown = receive("content-page-shown", isData);
Packit f0b94e
  pageHidden = receive("content-page-hidden", isData);
Packit f0b94e
Packit f0b94e
  hiddenPage = await pageHidden;
Packit f0b94e
  is(interactiveDocument2, hiddenPage, "new document is hidden");
Packit f0b94e
Packit f0b94e
  shownPage = await pageShown;
Packit f0b94e
  is(interactiveDocument1, shownPage, "previous document is shown");
Packit f0b94e
Packit f0b94e
  info("load uri#3");
Packit f0b94e
Packit f0b94e
  browser1.loadURI(uri3);
Packit f0b94e
Packit f0b94e
  pageShown = receive("content-page-shown", isData);
Packit f0b94e
Packit f0b94e
  let interactiveDocument3 = await documentInteractive;
Packit f0b94e
Packit f0b94e
  let loadedDocument3 = await documentLoaded;
Packit f0b94e
  is(loadedDocument3.readyState, "complete", "document is loaded");
Packit f0b94e
  is(interactiveDocument3, loadedDocument3, "interactive document is loaded");
Packit f0b94e
Packit f0b94e
  shownPage = await pageShown;
Packit f0b94e
  is(interactiveDocument3, shownPage, "previous document is shown");
Packit f0b94e
Packit f0b94e
  gBrowser.removeTab(tab1);
Packit f0b94e
Packit f0b94e
  info("load chrome uri");
Packit f0b94e
Packit f0b94e
  const tab2 = openTab(uri4);
Packit f0b94e
  documentInteractive = receive("chrome-document-interactive", null, d => {
Packit f0b94e
    // This test is executed synchronously when the event is received.
Packit f0b94e
    is(d.readyState, "interactive", "document is interactive");
Packit f0b94e
    is(d.URL, uri4, "document.URL matches URL loaded");
Packit f0b94e
  });
Packit f0b94e
  documentLoaded = receive("chrome-document-loaded");
Packit f0b94e
  pageShown = receive("chrome-page-shown");
Packit f0b94e
Packit f0b94e
  const interactiveDocument4 = await documentInteractive;
Packit f0b94e
Packit f0b94e
  let loadedDocument4 = await documentLoaded;
Packit f0b94e
  is(loadedDocument4.readyState, "complete", "document is loaded");
Packit f0b94e
  is(interactiveDocument4, loadedDocument4, "interactive document is loaded");
Packit f0b94e
Packit f0b94e
  shownPage = await pageShown;
Packit f0b94e
  is(interactiveDocument4, shownPage, "loaded chrome document is shown");
Packit f0b94e
Packit f0b94e
  pageHidden = receive("chrome-page-hidden");
Packit f0b94e
  gBrowser.removeTab(tab2);
Packit f0b94e
Packit f0b94e
  hiddenPage = await pageHidden;
Packit f0b94e
  is(interactiveDocument4, hiddenPage, "chrome document hidden");
Packit f0b94e
});