1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/test/browser_state_notifications.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,189 @@ 1.4 +/* globals Components: true, Promise: true, gBrowser: true, Test: true, 1.5 + info: true, is: true, window: true, waitForExplicitFinish: true, 1.6 + finish: true, ok: true*/ 1.7 + 1.8 +"use strict"; 1.9 + 1.10 +const { interfaces: Ci, classes: Cc, utils: Cu } = Components; 1.11 +const { addObserver, removeObserver } = Cc["@mozilla.org/observer-service;1"]. 1.12 + getService(Ci.nsIObserverService); 1.13 +const { openWindow } = Cc["@mozilla.org/embedcomp/window-watcher;1"]. 1.14 + getService(Ci.nsIWindowWatcher); 1.15 + 1.16 +const Test = routine => () => { 1.17 + waitForExplicitFinish(); 1.18 + Task.spawn(routine) 1.19 + .then(finish, error => { 1.20 + ok(false, error); 1.21 + finish(); 1.22 + }); 1.23 +}; 1.24 + 1.25 +// Returns promise for the observer notification subject for 1.26 +// the given topic. If `receive("foo")` is called `n` times 1.27 +// nth promise is resolved on an `nth` "foo" notification. 1.28 +const receive = (topic, p, syncCallback) => { 1.29 + const { promise, resolve, reject } = Promise.defer(); 1.30 + const { queue } = receive; 1.31 + const timeout = () => { 1.32 + queue.splice(queue.indexOf(resolve) - 1, 2); 1.33 + reject(new Error("Timeout")); 1.34 + }; 1.35 + 1.36 + const observer = { 1.37 + observe: subject => { 1.38 + // Browser loads bunch of other documents that we don't care 1.39 + // about so we let allow filtering notifications via `p` function. 1.40 + if (p && !p(subject)) return; 1.41 + // If observer is a first one with a given `topic` 1.42 + // in a queue resolve promise and take it off the queue 1.43 + // otherwise keep waiting. 1.44 + const index = queue.indexOf(topic); 1.45 + if (queue.indexOf(resolve) === index + 1) { 1.46 + removeObserver(observer, topic); 1.47 + clearTimeout(id, reject); 1.48 + queue.splice(index, 2); 1.49 + // Some tests need to be executed synchronously when the event is fired. 1.50 + if (syncCallback) { 1.51 + syncCallback(subject); 1.52 + } 1.53 + resolve(subject); 1.54 + } 1.55 + } 1.56 + }; 1.57 + const id = setTimeout(timeout, 90000); 1.58 + addObserver(observer, topic, false); 1.59 + queue.push(topic, resolve); 1.60 + 1.61 + return promise; 1.62 +}; 1.63 +receive.queue = []; 1.64 + 1.65 +const openTab = uri => gBrowser.selectedTab = gBrowser.addTab(uri); 1.66 + 1.67 +const sleep = ms => { 1.68 + const { promise, resolve } = Promise.defer(); 1.69 + setTimeout(resolve, ms); 1.70 + return promise; 1.71 +}; 1.72 + 1.73 +const isData = document => document.URL.startsWith("data:"); 1.74 + 1.75 +const uri1 = "data:text/html;charset=utf-8,<h1>1</h1>"; 1.76 +// For whatever reason going back on load event doesn't work so timeout it is :( 1.77 +const uri2 = "data:text/html;charset=utf-8,<h1>2</h1><script>setTimeout(back,100)</script>"; 1.78 +const uri3 = "data:text/html;charset=utf-8,<h1>3</h1>"; 1.79 + 1.80 +const uri4 = "chrome://browser/content/license.html"; 1.81 + 1.82 +const test = Test(function*() { 1.83 + let documentInteractive = receive("content-document-interactive", isData, d => { 1.84 + // This test is executed synchronously when the event is received. 1.85 + is(d.readyState, "interactive", "document is interactive"); 1.86 + is(d.URL, uri1, "document.URL matches tab url"); 1.87 + }); 1.88 + let documentLoaded = receive("content-document-loaded", isData); 1.89 + let pageShown = receive("content-page-shown", isData); 1.90 + 1.91 + info("open: uri#1"); 1.92 + const tab1 = openTab(uri1); 1.93 + const browser1 = gBrowser.getBrowserForTab(tab1); 1.94 + 1.95 + let interactiveDocument1 = yield documentInteractive; 1.96 + 1.97 + let loadedDocument1 = yield documentLoaded; 1.98 + is(loadedDocument1.readyState, "complete", "document is loaded"); 1.99 + is(interactiveDocument1, loadedDocument1, "interactive document is loaded"); 1.100 + 1.101 + let shownPage = yield pageShown; 1.102 + is(interactiveDocument1, shownPage, "loaded document is shown"); 1.103 + 1.104 + // Wait until history entry is created before loading new uri. 1.105 + yield receive("sessionstore-state-write-complete"); 1.106 + 1.107 + info("load uri#2"); 1.108 + 1.109 + documentInteractive = receive("content-document-interactive", isData, d => { 1.110 + // This test is executed synchronously when the event is received. 1.111 + is(d.readyState, "interactive", "document is interactive"); 1.112 + is(d.URL, uri2, "document.URL matches URL loaded"); 1.113 + }); 1.114 + documentLoaded = receive("content-document-loaded", isData); 1.115 + pageShown = receive("content-page-shown", isData); 1.116 + let pageHidden = receive("content-page-hidden", isData); 1.117 + 1.118 + browser1.loadURI(uri2); 1.119 + 1.120 + let hiddenPage = yield pageHidden; 1.121 + is(interactiveDocument1, hiddenPage, "loaded document is hidden"); 1.122 + 1.123 + let interactiveDocument2 = yield documentInteractive; 1.124 + 1.125 + let loadedDocument2 = yield documentLoaded; 1.126 + is(loadedDocument2.readyState, "complete", "document is loaded"); 1.127 + is(interactiveDocument2, loadedDocument2, "interactive document is loaded"); 1.128 + 1.129 + shownPage = yield pageShown; 1.130 + is(interactiveDocument2, shownPage, "loaded document is shown"); 1.131 + 1.132 + info("go back to uri#1"); 1.133 + 1.134 + 1.135 + documentInteractive = receive("content-document-interactive", isData, d => { 1.136 + // This test is executed synchronously when the event is received. 1.137 + is(d.readyState, "interactive", "document is interactive"); 1.138 + is(d.URL, uri3, "document.URL matches URL loaded"); 1.139 + }); 1.140 + documentLoaded = receive("content-document-loaded", isData); 1.141 + pageShown = receive("content-page-shown", isData); 1.142 + pageHidden = receive("content-page-hidden", isData); 1.143 + 1.144 + hiddenPage = yield pageHidden; 1.145 + is(interactiveDocument2, hiddenPage, "new document is hidden"); 1.146 + 1.147 + shownPage = yield pageShown; 1.148 + is(interactiveDocument1, shownPage, "previous document is shown"); 1.149 + 1.150 + info("load uri#3"); 1.151 + 1.152 + browser1.loadURI(uri3); 1.153 + 1.154 + pageShown = receive("content-page-shown", isData); 1.155 + 1.156 + let interactiveDocument3 = yield documentInteractive; 1.157 + 1.158 + let loadedDocument3 = yield documentLoaded; 1.159 + is(loadedDocument3.readyState, "complete", "document is loaded"); 1.160 + is(interactiveDocument3, loadedDocument3, "interactive document is loaded"); 1.161 + 1.162 + shownPage = yield pageShown; 1.163 + is(interactiveDocument3, shownPage, "previous document is shown"); 1.164 + 1.165 + gBrowser.removeTab(tab1); 1.166 + 1.167 + info("load chrome uri"); 1.168 + 1.169 + const tab2 = openTab(uri4); 1.170 + documentInteractive = receive("chrome-document-interactive", null, d => { 1.171 + // This test is executed synchronously when the event is received. 1.172 + is(d.readyState, "interactive", "document is interactive"); 1.173 + is(d.URL, uri4, "document.URL matches URL loaded"); 1.174 + }); 1.175 + documentLoaded = receive("chrome-document-loaded"); 1.176 + pageShown = receive("chrome-page-shown"); 1.177 + 1.178 + const interactiveDocument4 = yield documentInteractive; 1.179 + 1.180 + let loadedDocument4 = yield documentLoaded; 1.181 + is(loadedDocument4.readyState, "complete", "document is loaded"); 1.182 + is(interactiveDocument4, loadedDocument4, "interactive document is loaded"); 1.183 + 1.184 + shownPage = yield pageShown; 1.185 + is(interactiveDocument4, shownPage, "loaded chrome document is shown"); 1.186 + 1.187 + pageHidden = receive("chrome-page-hidden"); 1.188 + gBrowser.removeTab(tab2); 1.189 + 1.190 + hiddenPage = yield pageHidden; 1.191 + is(interactiveDocument4, hiddenPage, "chrome document hidden"); 1.192 +});