Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | // Is the currently opened tab focused? |
michael@0 | 6 | function isTabFocused() { |
michael@0 | 7 | let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab); |
michael@0 | 8 | return Services.focus.focusedWindow == tabb.contentWindow; |
michael@0 | 9 | } |
michael@0 | 10 | |
michael@0 | 11 | function isChatFocused(chat) { |
michael@0 | 12 | return SocialChatBar.chatbar._isChatFocused(chat); |
michael@0 | 13 | } |
michael@0 | 14 | |
michael@0 | 15 | function openChatViaUser() { |
michael@0 | 16 | let sidebarDoc = document.getElementById("social-sidebar-browser").contentDocument; |
michael@0 | 17 | let button = sidebarDoc.getElementById("chat-opener"); |
michael@0 | 18 | // Note we must use synthesizeMouseAtCenter() rather than calling |
michael@0 | 19 | // .click() directly as this causes nsIDOMWindowUtils.isHandlingUserInput |
michael@0 | 20 | // to be true. |
michael@0 | 21 | EventUtils.synthesizeMouseAtCenter(button, {}, sidebarDoc.defaultView); |
michael@0 | 22 | } |
michael@0 | 23 | |
michael@0 | 24 | function openChatViaSidebarMessage(port, data, callback) { |
michael@0 | 25 | port.onmessage = function (e) { |
michael@0 | 26 | if (e.data.topic == "chatbox-opened") |
michael@0 | 27 | callback(); |
michael@0 | 28 | } |
michael@0 | 29 | port.postMessage({topic: "test-chatbox-open", data: data}); |
michael@0 | 30 | } |
michael@0 | 31 | |
michael@0 | 32 | function openChatViaWorkerMessage(port, data, callback) { |
michael@0 | 33 | // sadly there is no message coming back to tell us when the chat has |
michael@0 | 34 | // been opened, so we wait until one appears. |
michael@0 | 35 | let chatbar = SocialChatBar.chatbar; |
michael@0 | 36 | let numExpected = chatbar.childElementCount + 1; |
michael@0 | 37 | port.postMessage({topic: "test-worker-chat", data: data}); |
michael@0 | 38 | waitForCondition(function() chatbar.childElementCount == numExpected, |
michael@0 | 39 | function() { |
michael@0 | 40 | // so the child has been added, but we don't know if it |
michael@0 | 41 | // has been intialized - re-request it and the callback |
michael@0 | 42 | // means it's done. Minimized, same as the worker. |
michael@0 | 43 | SocialChatBar.openChat(SocialSidebar.provider, |
michael@0 | 44 | data, |
michael@0 | 45 | function() { |
michael@0 | 46 | callback(); |
michael@0 | 47 | }, |
michael@0 | 48 | "minimized"); |
michael@0 | 49 | }, |
michael@0 | 50 | "No new chat appeared"); |
michael@0 | 51 | } |
michael@0 | 52 | |
michael@0 | 53 | |
michael@0 | 54 | let isSidebarLoaded = false; |
michael@0 | 55 | |
michael@0 | 56 | function startTestAndWaitForSidebar(callback) { |
michael@0 | 57 | let doneCallback; |
michael@0 | 58 | let port = SocialSidebar.provider.getWorkerPort(); |
michael@0 | 59 | function maybeCallback() { |
michael@0 | 60 | if (!doneCallback) |
michael@0 | 61 | callback(port); |
michael@0 | 62 | doneCallback = true; |
michael@0 | 63 | } |
michael@0 | 64 | port.onmessage = function(e) { |
michael@0 | 65 | let topic = e.data.topic; |
michael@0 | 66 | switch (topic) { |
michael@0 | 67 | case "got-sidebar-message": |
michael@0 | 68 | // if sidebar loaded too fast, we need a backup ping |
michael@0 | 69 | case "got-isVisible-response": |
michael@0 | 70 | isSidebarLoaded = true; |
michael@0 | 71 | maybeCallback(); |
michael@0 | 72 | break; |
michael@0 | 73 | case "test-init-done": |
michael@0 | 74 | if (isSidebarLoaded) |
michael@0 | 75 | maybeCallback(); |
michael@0 | 76 | else |
michael@0 | 77 | port.postMessage({topic: "test-isVisible"}); |
michael@0 | 78 | break; |
michael@0 | 79 | } |
michael@0 | 80 | } |
michael@0 | 81 | port.postMessage({topic: "test-init"}); |
michael@0 | 82 | } |
michael@0 | 83 | |
michael@0 | 84 | let manifest = { // normal provider |
michael@0 | 85 | name: "provider 1", |
michael@0 | 86 | origin: "https://example.com", |
michael@0 | 87 | sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html", |
michael@0 | 88 | workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js", |
michael@0 | 89 | iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png" |
michael@0 | 90 | }; |
michael@0 | 91 | |
michael@0 | 92 | function test() { |
michael@0 | 93 | waitForExplicitFinish(); |
michael@0 | 94 | |
michael@0 | 95 | // Note that (probably) due to bug 604289, if a tab is focused but the |
michael@0 | 96 | // focused element is null, our chat windows can "steal" focus. This is |
michael@0 | 97 | // avoided if we explicitly focus an element in the tab. |
michael@0 | 98 | // So we load a page with an <input> field and focus that before testing. |
michael@0 | 99 | let url = "data:text/html;charset=utf-8," + encodeURI('<input id="theinput">'); |
michael@0 | 100 | let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true}); |
michael@0 | 101 | tab.linkedBrowser.addEventListener("load", function tabLoad(event) { |
michael@0 | 102 | tab.linkedBrowser.removeEventListener("load", tabLoad, true); |
michael@0 | 103 | // before every test we focus the input field. |
michael@0 | 104 | let preSubTest = function(cb) { |
michael@0 | 105 | // XXX - when bug 604289 is fixed it should be possible to just do: |
michael@0 | 106 | // tab.linkedBrowser.contentWindow.focus() |
michael@0 | 107 | // but instead we must do: |
michael@0 | 108 | tab.linkedBrowser.contentDocument.getElementById("theinput").focus(); |
michael@0 | 109 | waitForCondition(function() isTabFocused(), cb, "tab should have focus"); |
michael@0 | 110 | } |
michael@0 | 111 | let postSubTest = function(cb) { |
michael@0 | 112 | window.SocialChatBar.chatbar.removeAll(); |
michael@0 | 113 | cb(); |
michael@0 | 114 | } |
michael@0 | 115 | // and run the tests. |
michael@0 | 116 | runSocialTestWithProvider(manifest, function (finishcb) { |
michael@0 | 117 | SocialSidebar.show(); |
michael@0 | 118 | runSocialTests(tests, preSubTest, postSubTest, function () { |
michael@0 | 119 | finishcb(); |
michael@0 | 120 | }); |
michael@0 | 121 | }); |
michael@0 | 122 | }, true); |
michael@0 | 123 | registerCleanupFunction(function() { |
michael@0 | 124 | gBrowser.removeTab(tab); |
michael@0 | 125 | }); |
michael@0 | 126 | |
michael@0 | 127 | } |
michael@0 | 128 | |
michael@0 | 129 | var tests = { |
michael@0 | 130 | // In this test the worker asks the sidebar to open a chat. As that means |
michael@0 | 131 | // we aren't handling user-input we will not focus the chatbar. |
michael@0 | 132 | // Then we do it again - should still not be focused. |
michael@0 | 133 | // Then we perform a user-initiated request - it should get focus. |
michael@0 | 134 | testNoFocusWhenViaWorker: function(next) { |
michael@0 | 135 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 136 | openChatViaSidebarMessage(port, {stealFocus: 1}, function() { |
michael@0 | 137 | ok(true, "got chatbox message"); |
michael@0 | 138 | is(SocialChatBar.chatbar.childElementCount, 1, "exactly 1 chat open"); |
michael@0 | 139 | ok(isTabFocused(), "tab should still be focused"); |
michael@0 | 140 | // re-request the same chat via a message. |
michael@0 | 141 | openChatViaSidebarMessage(port, {stealFocus: 1}, function() { |
michael@0 | 142 | is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open"); |
michael@0 | 143 | ok(isTabFocused(), "tab should still be focused"); |
michael@0 | 144 | // re-request the same chat via user event. |
michael@0 | 145 | openChatViaUser(); |
michael@0 | 146 | waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat), |
michael@0 | 147 | function() { |
michael@0 | 148 | is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open"); |
michael@0 | 149 | is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat should be selected"); |
michael@0 | 150 | next(); |
michael@0 | 151 | }, "chat should be focused"); |
michael@0 | 152 | }); |
michael@0 | 153 | }); |
michael@0 | 154 | }); |
michael@0 | 155 | }, |
michael@0 | 156 | |
michael@0 | 157 | // In this test we arrange for the sidebar to open the chat via a simulated |
michael@0 | 158 | // click. This should cause the new chat to be opened and focused. |
michael@0 | 159 | testFocusWhenViaUser: function(next) { |
michael@0 | 160 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 161 | openChatViaUser(); |
michael@0 | 162 | ok(SocialChatBar.chatbar.firstElementChild, "chat opened"); |
michael@0 | 163 | waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat), |
michael@0 | 164 | function() { |
michael@0 | 165 | is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat is selected"); |
michael@0 | 166 | next(); |
michael@0 | 167 | }, "chat should be focused"); |
michael@0 | 168 | }); |
michael@0 | 169 | }, |
michael@0 | 170 | |
michael@0 | 171 | // Open a chat via the worker - it will open and not have focus. |
michael@0 | 172 | // Then open the same chat via a sidebar message - it will be restored but |
michael@0 | 173 | // should still not have grabbed focus. |
michael@0 | 174 | testNoFocusOnAutoRestore: function(next) { |
michael@0 | 175 | const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html?id=1"; |
michael@0 | 176 | let chatbar = SocialChatBar.chatbar; |
michael@0 | 177 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 178 | openChatViaWorkerMessage(port, chatUrl, function() { |
michael@0 | 179 | is(chatbar.childElementCount, 1, "exactly 1 chat open"); |
michael@0 | 180 | // bug 865086 opening minimized still sets the window as selected |
michael@0 | 181 | todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected"); |
michael@0 | 182 | ok(isTabFocused(), "tab should be focused"); |
michael@0 | 183 | openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() { |
michael@0 | 184 | is(chatbar.childElementCount, 1, "still 1 chat open"); |
michael@0 | 185 | ok(!chatbar.firstElementChild.minimized, "chat no longer minimized"); |
michael@0 | 186 | // bug 865086 because we marked it selected on open, it still is |
michael@0 | 187 | todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected"); |
michael@0 | 188 | ok(isTabFocused(), "tab should still be focused"); |
michael@0 | 189 | next(); |
michael@0 | 190 | }); |
michael@0 | 191 | }); |
michael@0 | 192 | }); |
michael@0 | 193 | }, |
michael@0 | 194 | |
michael@0 | 195 | // Here we open a chat, which will not be focused. Then we minimize it and |
michael@0 | 196 | // restore it via a titlebar clock - it should get focus at that point. |
michael@0 | 197 | testFocusOnExplicitRestore: function(next) { |
michael@0 | 198 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 199 | openChatViaSidebarMessage(port, {stealFocus: 1}, function() { |
michael@0 | 200 | ok(true, "got chatbox message"); |
michael@0 | 201 | ok(isTabFocused(), "tab should still be focused"); |
michael@0 | 202 | let chatbox = SocialChatBar.chatbar.firstElementChild; |
michael@0 | 203 | ok(chatbox, "chat opened"); |
michael@0 | 204 | chatbox.minimized = true; |
michael@0 | 205 | ok(isTabFocused(), "tab should still be focused"); |
michael@0 | 206 | // pretend we clicked on the titlebar |
michael@0 | 207 | chatbox.onTitlebarClick({button: 0}); |
michael@0 | 208 | waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat), |
michael@0 | 209 | function() { |
michael@0 | 210 | ok(!chatbox.minimized, "chat should have been restored"); |
michael@0 | 211 | ok(isChatFocused(chatbox), "chat should be focused"); |
michael@0 | 212 | is(chatbox, SocialChatBar.chatbar.selectedChat, "chat is marked selected"); |
michael@0 | 213 | next(); |
michael@0 | 214 | }, "chat should have focus"); |
michael@0 | 215 | }); |
michael@0 | 216 | }); |
michael@0 | 217 | }, |
michael@0 | 218 | |
michael@0 | 219 | // Open 2 chats and give 1 focus. Minimize the focused one - the second |
michael@0 | 220 | // should get focus. |
michael@0 | 221 | testMinimizeFocused: function(next) { |
michael@0 | 222 | let chatbar = SocialChatBar.chatbar; |
michael@0 | 223 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 224 | openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() { |
michael@0 | 225 | let chat1 = chatbar.firstElementChild; |
michael@0 | 226 | openChatViaSidebarMessage(port, {stealFocus: 1, id: 2}, function() { |
michael@0 | 227 | is(chatbar.childElementCount, 2, "exactly 2 chats open"); |
michael@0 | 228 | let chat2 = chat1.nextElementSibling || chat1.previousElementSibling; |
michael@0 | 229 | chatbar.selectedChat = chat1; |
michael@0 | 230 | chatbar.focus(); |
michael@0 | 231 | waitForCondition(function() isChatFocused(chat1), |
michael@0 | 232 | function() { |
michael@0 | 233 | is(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is marked selected"); |
michael@0 | 234 | isnot(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is not marked selected"); |
michael@0 | 235 | chat1.minimized = true; |
michael@0 | 236 | waitForCondition(function() isChatFocused(chat2), |
michael@0 | 237 | function() { |
michael@0 | 238 | // minimizing the chat with focus should give it to another. |
michael@0 | 239 | isnot(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is not marked selected"); |
michael@0 | 240 | is(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is marked selected"); |
michael@0 | 241 | next(); |
michael@0 | 242 | }, "chat2 should have focus"); |
michael@0 | 243 | }, "chat1 should have focus"); |
michael@0 | 244 | }); |
michael@0 | 245 | }); |
michael@0 | 246 | }); |
michael@0 | 247 | }, |
michael@0 | 248 | |
michael@0 | 249 | // Open 2 chats, select (but not focus) one, then re-request it be |
michael@0 | 250 | // opened via a message. Focus should not move. |
michael@0 | 251 | testReopenNonFocused: function(next) { |
michael@0 | 252 | let chatbar = SocialChatBar.chatbar; |
michael@0 | 253 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 254 | openChatViaSidebarMessage(port, {id: 1}, function() { |
michael@0 | 255 | let chat1 = chatbar.firstElementChild; |
michael@0 | 256 | openChatViaSidebarMessage(port, {id: 2}, function() { |
michael@0 | 257 | let chat2 = chat1.nextElementSibling || chat1.previousElementSibling; |
michael@0 | 258 | chatbar.selectedChat = chat2; |
michael@0 | 259 | // tab still has focus |
michael@0 | 260 | ok(isTabFocused(), "tab should still be focused"); |
michael@0 | 261 | // re-request the first. |
michael@0 | 262 | openChatViaSidebarMessage(port, {id: 1}, function() { |
michael@0 | 263 | is(chatbar.selectedChat, chat1, "chat1 now selected"); |
michael@0 | 264 | ok(isTabFocused(), "tab should still be focused"); |
michael@0 | 265 | next(); |
michael@0 | 266 | }); |
michael@0 | 267 | }); |
michael@0 | 268 | }); |
michael@0 | 269 | }); |
michael@0 | 270 | }, |
michael@0 | 271 | |
michael@0 | 272 | // Open 2 chats, select and focus the second. Pressing the TAB key should |
michael@0 | 273 | // cause focus to move between all elements in our chat window before moving |
michael@0 | 274 | // to the next chat window. |
michael@0 | 275 | testTab: function(next) { |
michael@0 | 276 | function sendTabAndWaitForFocus(chat, eltid, callback) { |
michael@0 | 277 | // ideally we would use the 'focus' event here, but that doesn't work |
michael@0 | 278 | // as expected for the iframe - the iframe itself never gets the focus |
michael@0 | 279 | // event (apparently the sub-document etc does.) |
michael@0 | 280 | // So just poll for the correct element getting focus... |
michael@0 | 281 | let doc = chat.contentDocument; |
michael@0 | 282 | EventUtils.sendKey("tab"); |
michael@0 | 283 | waitForCondition(function() { |
michael@0 | 284 | let elt = eltid ? doc.getElementById(eltid) : doc.documentElement; |
michael@0 | 285 | return doc.activeElement == elt; |
michael@0 | 286 | }, callback, "element " + eltid + " never got focus"); |
michael@0 | 287 | } |
michael@0 | 288 | |
michael@0 | 289 | let chatbar = SocialChatBar.chatbar; |
michael@0 | 290 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 291 | openChatViaSidebarMessage(port, {id: 1}, function() { |
michael@0 | 292 | let chat1 = chatbar.firstElementChild; |
michael@0 | 293 | openChatViaSidebarMessage(port, {id: 2}, function() { |
michael@0 | 294 | let chat2 = chat1.nextElementSibling || chat1.previousElementSibling; |
michael@0 | 295 | chatbar.selectedChat = chat2; |
michael@0 | 296 | chatbar.focus(); |
michael@0 | 297 | waitForCondition(function() isChatFocused(chatbar.selectedChat), |
michael@0 | 298 | function() { |
michael@0 | 299 | // Our chats have 3 focusable elements, so it takes 4 TABs to move |
michael@0 | 300 | // to the new chat. |
michael@0 | 301 | sendTabAndWaitForFocus(chat2, "input1", function() { |
michael@0 | 302 | is(chat2.contentDocument.activeElement.getAttribute("id"), "input1", |
michael@0 | 303 | "first input field has focus"); |
michael@0 | 304 | ok(isChatFocused(chat2), "new chat still focused after first tab"); |
michael@0 | 305 | sendTabAndWaitForFocus(chat2, "input2", function() { |
michael@0 | 306 | ok(isChatFocused(chat2), "new chat still focused after tab"); |
michael@0 | 307 | is(chat2.contentDocument.activeElement.getAttribute("id"), "input2", |
michael@0 | 308 | "second input field has focus"); |
michael@0 | 309 | sendTabAndWaitForFocus(chat2, "iframe", function() { |
michael@0 | 310 | ok(isChatFocused(chat2), "new chat still focused after tab"); |
michael@0 | 311 | is(chat2.contentDocument.activeElement.getAttribute("id"), "iframe", |
michael@0 | 312 | "iframe has focus"); |
michael@0 | 313 | // this tab now should move to the next chat, but focus the |
michael@0 | 314 | // document element itself (hence the null eltid) |
michael@0 | 315 | sendTabAndWaitForFocus(chat1, null, function() { |
michael@0 | 316 | ok(isChatFocused(chat1), "first chat is focused"); |
michael@0 | 317 | next(); |
michael@0 | 318 | }); |
michael@0 | 319 | }); |
michael@0 | 320 | }); |
michael@0 | 321 | }); |
michael@0 | 322 | }, "chat should have focus"); |
michael@0 | 323 | }); |
michael@0 | 324 | }); |
michael@0 | 325 | }); |
michael@0 | 326 | }, |
michael@0 | 327 | |
michael@0 | 328 | // Open a chat and focus an element other than the first. Move focus to some |
michael@0 | 329 | // other item (the tab itself in this case), then focus the chatbar - the |
michael@0 | 330 | // same element that was previously focused should still have focus. |
michael@0 | 331 | testFocusedElement: function(next) { |
michael@0 | 332 | let chatbar = SocialChatBar.chatbar; |
michael@0 | 333 | startTestAndWaitForSidebar(function(port) { |
michael@0 | 334 | openChatViaUser(); |
michael@0 | 335 | let chat = chatbar.firstElementChild; |
michael@0 | 336 | // need to wait for the content to load before we can focus it. |
michael@0 | 337 | chat.addEventListener("DOMContentLoaded", function DOMContentLoaded() { |
michael@0 | 338 | chat.removeEventListener("DOMContentLoaded", DOMContentLoaded); |
michael@0 | 339 | chat.contentDocument.getElementById("input2").focus(); |
michael@0 | 340 | waitForCondition(function() isChatFocused(chat), |
michael@0 | 341 | function() { |
michael@0 | 342 | is(chat.contentDocument.activeElement.getAttribute("id"), "input2", |
michael@0 | 343 | "correct input field has focus"); |
michael@0 | 344 | // set focus to the tab. |
michael@0 | 345 | let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab); |
michael@0 | 346 | Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0); |
michael@0 | 347 | waitForCondition(function() isTabFocused(), |
michael@0 | 348 | function() { |
michael@0 | 349 | chatbar.focus(); |
michael@0 | 350 | waitForCondition(function() isChatFocused(chat), |
michael@0 | 351 | function() { |
michael@0 | 352 | is(chat.contentDocument.activeElement.getAttribute("id"), "input2", |
michael@0 | 353 | "correct input field still has focus"); |
michael@0 | 354 | next(); |
michael@0 | 355 | }, "chat took focus"); |
michael@0 | 356 | }, "tab has focus"); |
michael@0 | 357 | }, "chat took focus"); |
michael@0 | 358 | }); |
michael@0 | 359 | }); |
michael@0 | 360 | }, |
michael@0 | 361 | }; |