|
1 /* globals Components: true, Promise: true, gBrowser: true, Test: true, |
|
2 info: true, is: true, window: true, waitForExplicitFinish: true, |
|
3 finish: true, ok: true*/ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 const { interfaces: Ci, classes: Cc, utils: Cu } = Components; |
|
8 const { addObserver, removeObserver } = Cc["@mozilla.org/observer-service;1"]. |
|
9 getService(Ci.nsIObserverService); |
|
10 const { openWindow } = Cc["@mozilla.org/embedcomp/window-watcher;1"]. |
|
11 getService(Ci.nsIWindowWatcher); |
|
12 |
|
13 const Test = routine => () => { |
|
14 waitForExplicitFinish(); |
|
15 Task.spawn(routine) |
|
16 .then(finish, error => { |
|
17 ok(false, error); |
|
18 finish(); |
|
19 }); |
|
20 }; |
|
21 |
|
22 // Returns promise for the observer notification subject for |
|
23 // the given topic. If `receive("foo")` is called `n` times |
|
24 // nth promise is resolved on an `nth` "foo" notification. |
|
25 const receive = (topic, p, syncCallback) => { |
|
26 const { promise, resolve, reject } = Promise.defer(); |
|
27 const { queue } = receive; |
|
28 const timeout = () => { |
|
29 queue.splice(queue.indexOf(resolve) - 1, 2); |
|
30 reject(new Error("Timeout")); |
|
31 }; |
|
32 |
|
33 const observer = { |
|
34 observe: subject => { |
|
35 // Browser loads bunch of other documents that we don't care |
|
36 // about so we let allow filtering notifications via `p` function. |
|
37 if (p && !p(subject)) return; |
|
38 // If observer is a first one with a given `topic` |
|
39 // in a queue resolve promise and take it off the queue |
|
40 // otherwise keep waiting. |
|
41 const index = queue.indexOf(topic); |
|
42 if (queue.indexOf(resolve) === index + 1) { |
|
43 removeObserver(observer, topic); |
|
44 clearTimeout(id, reject); |
|
45 queue.splice(index, 2); |
|
46 // Some tests need to be executed synchronously when the event is fired. |
|
47 if (syncCallback) { |
|
48 syncCallback(subject); |
|
49 } |
|
50 resolve(subject); |
|
51 } |
|
52 } |
|
53 }; |
|
54 const id = setTimeout(timeout, 90000); |
|
55 addObserver(observer, topic, false); |
|
56 queue.push(topic, resolve); |
|
57 |
|
58 return promise; |
|
59 }; |
|
60 receive.queue = []; |
|
61 |
|
62 const openTab = uri => gBrowser.selectedTab = gBrowser.addTab(uri); |
|
63 |
|
64 const sleep = ms => { |
|
65 const { promise, resolve } = Promise.defer(); |
|
66 setTimeout(resolve, ms); |
|
67 return promise; |
|
68 }; |
|
69 |
|
70 const isData = document => document.URL.startsWith("data:"); |
|
71 |
|
72 const uri1 = "data:text/html;charset=utf-8,<h1>1</h1>"; |
|
73 // For whatever reason going back on load event doesn't work so timeout it is :( |
|
74 const uri2 = "data:text/html;charset=utf-8,<h1>2</h1><script>setTimeout(back,100)</script>"; |
|
75 const uri3 = "data:text/html;charset=utf-8,<h1>3</h1>"; |
|
76 |
|
77 const uri4 = "chrome://browser/content/license.html"; |
|
78 |
|
79 const test = Test(function*() { |
|
80 let documentInteractive = receive("content-document-interactive", isData, d => { |
|
81 // This test is executed synchronously when the event is received. |
|
82 is(d.readyState, "interactive", "document is interactive"); |
|
83 is(d.URL, uri1, "document.URL matches tab url"); |
|
84 }); |
|
85 let documentLoaded = receive("content-document-loaded", isData); |
|
86 let pageShown = receive("content-page-shown", isData); |
|
87 |
|
88 info("open: uri#1"); |
|
89 const tab1 = openTab(uri1); |
|
90 const browser1 = gBrowser.getBrowserForTab(tab1); |
|
91 |
|
92 let interactiveDocument1 = yield documentInteractive; |
|
93 |
|
94 let loadedDocument1 = yield documentLoaded; |
|
95 is(loadedDocument1.readyState, "complete", "document is loaded"); |
|
96 is(interactiveDocument1, loadedDocument1, "interactive document is loaded"); |
|
97 |
|
98 let shownPage = yield pageShown; |
|
99 is(interactiveDocument1, shownPage, "loaded document is shown"); |
|
100 |
|
101 // Wait until history entry is created before loading new uri. |
|
102 yield receive("sessionstore-state-write-complete"); |
|
103 |
|
104 info("load uri#2"); |
|
105 |
|
106 documentInteractive = receive("content-document-interactive", isData, d => { |
|
107 // This test is executed synchronously when the event is received. |
|
108 is(d.readyState, "interactive", "document is interactive"); |
|
109 is(d.URL, uri2, "document.URL matches URL loaded"); |
|
110 }); |
|
111 documentLoaded = receive("content-document-loaded", isData); |
|
112 pageShown = receive("content-page-shown", isData); |
|
113 let pageHidden = receive("content-page-hidden", isData); |
|
114 |
|
115 browser1.loadURI(uri2); |
|
116 |
|
117 let hiddenPage = yield pageHidden; |
|
118 is(interactiveDocument1, hiddenPage, "loaded document is hidden"); |
|
119 |
|
120 let interactiveDocument2 = yield documentInteractive; |
|
121 |
|
122 let loadedDocument2 = yield documentLoaded; |
|
123 is(loadedDocument2.readyState, "complete", "document is loaded"); |
|
124 is(interactiveDocument2, loadedDocument2, "interactive document is loaded"); |
|
125 |
|
126 shownPage = yield pageShown; |
|
127 is(interactiveDocument2, shownPage, "loaded document is shown"); |
|
128 |
|
129 info("go back to uri#1"); |
|
130 |
|
131 |
|
132 documentInteractive = receive("content-document-interactive", isData, d => { |
|
133 // This test is executed synchronously when the event is received. |
|
134 is(d.readyState, "interactive", "document is interactive"); |
|
135 is(d.URL, uri3, "document.URL matches URL loaded"); |
|
136 }); |
|
137 documentLoaded = receive("content-document-loaded", isData); |
|
138 pageShown = receive("content-page-shown", isData); |
|
139 pageHidden = receive("content-page-hidden", isData); |
|
140 |
|
141 hiddenPage = yield pageHidden; |
|
142 is(interactiveDocument2, hiddenPage, "new document is hidden"); |
|
143 |
|
144 shownPage = yield pageShown; |
|
145 is(interactiveDocument1, shownPage, "previous document is shown"); |
|
146 |
|
147 info("load uri#3"); |
|
148 |
|
149 browser1.loadURI(uri3); |
|
150 |
|
151 pageShown = receive("content-page-shown", isData); |
|
152 |
|
153 let interactiveDocument3 = yield documentInteractive; |
|
154 |
|
155 let loadedDocument3 = yield documentLoaded; |
|
156 is(loadedDocument3.readyState, "complete", "document is loaded"); |
|
157 is(interactiveDocument3, loadedDocument3, "interactive document is loaded"); |
|
158 |
|
159 shownPage = yield pageShown; |
|
160 is(interactiveDocument3, shownPage, "previous document is shown"); |
|
161 |
|
162 gBrowser.removeTab(tab1); |
|
163 |
|
164 info("load chrome uri"); |
|
165 |
|
166 const tab2 = openTab(uri4); |
|
167 documentInteractive = receive("chrome-document-interactive", null, d => { |
|
168 // This test is executed synchronously when the event is received. |
|
169 is(d.readyState, "interactive", "document is interactive"); |
|
170 is(d.URL, uri4, "document.URL matches URL loaded"); |
|
171 }); |
|
172 documentLoaded = receive("chrome-document-loaded"); |
|
173 pageShown = receive("chrome-page-shown"); |
|
174 |
|
175 const interactiveDocument4 = yield documentInteractive; |
|
176 |
|
177 let loadedDocument4 = yield documentLoaded; |
|
178 is(loadedDocument4.readyState, "complete", "document is loaded"); |
|
179 is(interactiveDocument4, loadedDocument4, "interactive document is loaded"); |
|
180 |
|
181 shownPage = yield pageShown; |
|
182 is(interactiveDocument4, shownPage, "loaded chrome document is shown"); |
|
183 |
|
184 pageHidden = receive("chrome-page-hidden"); |
|
185 gBrowser.removeTab(tab2); |
|
186 |
|
187 hiddenPage = yield pageHidden; |
|
188 is(interactiveDocument4, hiddenPage, "chrome document hidden"); |
|
189 }); |