browser/base/content/test/social/browser_social_chatwindowfocus.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/browser/base/content/test/social/browser_social_chatwindowfocus.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,361 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +// Is the currently opened tab focused?
     1.9 +function isTabFocused() {
    1.10 +  let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
    1.11 +  return Services.focus.focusedWindow == tabb.contentWindow;
    1.12 +}
    1.13 +
    1.14 +function isChatFocused(chat) {
    1.15 +  return SocialChatBar.chatbar._isChatFocused(chat);
    1.16 +}
    1.17 +
    1.18 +function openChatViaUser() {
    1.19 +  let sidebarDoc = document.getElementById("social-sidebar-browser").contentDocument;
    1.20 +  let button = sidebarDoc.getElementById("chat-opener");
    1.21 +  // Note we must use synthesizeMouseAtCenter() rather than calling
    1.22 +  // .click() directly as this causes nsIDOMWindowUtils.isHandlingUserInput
    1.23 +  // to be true.
    1.24 +  EventUtils.synthesizeMouseAtCenter(button, {}, sidebarDoc.defaultView);
    1.25 +}
    1.26 +
    1.27 +function openChatViaSidebarMessage(port, data, callback) {
    1.28 +  port.onmessage = function (e) {
    1.29 +    if (e.data.topic == "chatbox-opened")
    1.30 +      callback();
    1.31 +  }
    1.32 +  port.postMessage({topic: "test-chatbox-open", data: data});
    1.33 +}
    1.34 +
    1.35 +function openChatViaWorkerMessage(port, data, callback) {
    1.36 +  // sadly there is no message coming back to tell us when the chat has
    1.37 +  // been opened, so we wait until one appears.
    1.38 +  let chatbar = SocialChatBar.chatbar;
    1.39 +  let numExpected = chatbar.childElementCount + 1;
    1.40 +  port.postMessage({topic: "test-worker-chat", data: data});
    1.41 +  waitForCondition(function() chatbar.childElementCount == numExpected,
    1.42 +                   function() {
    1.43 +                      // so the child has been added, but we don't know if it
    1.44 +                      // has been intialized - re-request it and the callback
    1.45 +                      // means it's done.  Minimized, same as the worker.
    1.46 +                      SocialChatBar.openChat(SocialSidebar.provider,
    1.47 +                                             data,
    1.48 +                                             function() {
    1.49 +                                                callback();
    1.50 +                                             },
    1.51 +                                             "minimized");
    1.52 +                   },
    1.53 +                   "No new chat appeared");
    1.54 +}
    1.55 +
    1.56 +
    1.57 +let isSidebarLoaded = false;
    1.58 +
    1.59 +function startTestAndWaitForSidebar(callback) {
    1.60 +  let doneCallback;
    1.61 +  let port = SocialSidebar.provider.getWorkerPort();
    1.62 +  function maybeCallback() {
    1.63 +    if (!doneCallback)
    1.64 +      callback(port);
    1.65 +    doneCallback = true;
    1.66 +  }
    1.67 +  port.onmessage = function(e) {
    1.68 +    let topic = e.data.topic;
    1.69 +    switch (topic) {
    1.70 +      case "got-sidebar-message":
    1.71 +        // if sidebar loaded too fast, we need a backup ping
    1.72 +      case "got-isVisible-response":
    1.73 +        isSidebarLoaded = true;
    1.74 +        maybeCallback();
    1.75 +        break;
    1.76 +      case "test-init-done":
    1.77 +        if (isSidebarLoaded)
    1.78 +          maybeCallback();
    1.79 +        else
    1.80 +          port.postMessage({topic: "test-isVisible"});
    1.81 +        break;
    1.82 +    }
    1.83 +  }
    1.84 +  port.postMessage({topic: "test-init"});
    1.85 +}
    1.86 +
    1.87 +let manifest = { // normal provider
    1.88 +  name: "provider 1",
    1.89 +  origin: "https://example.com",
    1.90 +  sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html",
    1.91 +  workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js",
    1.92 +  iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png"
    1.93 +};
    1.94 +
    1.95 +function test() {
    1.96 +  waitForExplicitFinish();
    1.97 +
    1.98 +  // Note that (probably) due to bug 604289, if a tab is focused but the
    1.99 +  // focused element is null, our chat windows can "steal" focus.  This is
   1.100 +  // avoided if we explicitly focus an element in the tab.
   1.101 +  // So we load a page with an <input> field and focus that before testing.
   1.102 +  let url = "data:text/html;charset=utf-8," + encodeURI('<input id="theinput">');
   1.103 +  let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true});
   1.104 +  tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
   1.105 +    tab.linkedBrowser.removeEventListener("load", tabLoad, true);
   1.106 +    // before every test we focus the input field.
   1.107 +    let preSubTest = function(cb) {
   1.108 +      // XXX - when bug 604289 is fixed it should be possible to just do:
   1.109 +      // tab.linkedBrowser.contentWindow.focus()
   1.110 +      // but instead we must do:
   1.111 +      tab.linkedBrowser.contentDocument.getElementById("theinput").focus();
   1.112 +      waitForCondition(function() isTabFocused(), cb, "tab should have focus");
   1.113 +    }
   1.114 +    let postSubTest = function(cb) {
   1.115 +      window.SocialChatBar.chatbar.removeAll();
   1.116 +      cb();
   1.117 +    }
   1.118 +    // and run the tests.
   1.119 +    runSocialTestWithProvider(manifest, function (finishcb) {
   1.120 +      SocialSidebar.show();
   1.121 +      runSocialTests(tests, preSubTest, postSubTest, function () {
   1.122 +        finishcb();
   1.123 +      });
   1.124 +    });
   1.125 +  }, true);
   1.126 +  registerCleanupFunction(function() {
   1.127 +    gBrowser.removeTab(tab);
   1.128 +  });
   1.129 +
   1.130 +}
   1.131 +
   1.132 +var tests = {
   1.133 +  // In this test the worker asks the sidebar to open a chat.  As that means
   1.134 +  // we aren't handling user-input we will not focus the chatbar.
   1.135 +  // Then we do it again - should still not be focused.
   1.136 +  // Then we perform a user-initiated request - it should get focus.
   1.137 +  testNoFocusWhenViaWorker: function(next) {
   1.138 +    startTestAndWaitForSidebar(function(port) {
   1.139 +      openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
   1.140 +        ok(true, "got chatbox message");
   1.141 +        is(SocialChatBar.chatbar.childElementCount, 1, "exactly 1 chat open");
   1.142 +        ok(isTabFocused(), "tab should still be focused");
   1.143 +        // re-request the same chat via a message.
   1.144 +        openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
   1.145 +          is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
   1.146 +          ok(isTabFocused(), "tab should still be focused");
   1.147 +          // re-request the same chat via user event.
   1.148 +          openChatViaUser();
   1.149 +          waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
   1.150 +                           function() {
   1.151 +            is(SocialChatBar.chatbar.childElementCount, 1, "still exactly 1 chat open");
   1.152 +            is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat should be selected");
   1.153 +            next();
   1.154 +          }, "chat should be focused");
   1.155 +        });
   1.156 +      });
   1.157 +    });
   1.158 +  },
   1.159 +
   1.160 +  // In this test we arrange for the sidebar to open the chat via a simulated
   1.161 +  // click.  This should cause the new chat to be opened and focused.
   1.162 +  testFocusWhenViaUser: function(next) {
   1.163 +    startTestAndWaitForSidebar(function(port) {
   1.164 +      openChatViaUser();
   1.165 +      ok(SocialChatBar.chatbar.firstElementChild, "chat opened");
   1.166 +      waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
   1.167 +                       function() {
   1.168 +        is(SocialChatBar.chatbar.selectedChat, SocialChatBar.chatbar.firstElementChild, "chat is selected");
   1.169 +        next();
   1.170 +      }, "chat should be focused");
   1.171 +    });
   1.172 +  },
   1.173 +
   1.174 +  // Open a chat via the worker - it will open and not have focus.
   1.175 +  // Then open the same chat via a sidebar message - it will be restored but
   1.176 +  // should still not have grabbed focus.
   1.177 +  testNoFocusOnAutoRestore: function(next) {
   1.178 +    const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html?id=1";
   1.179 +    let chatbar = SocialChatBar.chatbar;
   1.180 +    startTestAndWaitForSidebar(function(port) {
   1.181 +      openChatViaWorkerMessage(port, chatUrl, function() {
   1.182 +        is(chatbar.childElementCount, 1, "exactly 1 chat open");
   1.183 +        // bug 865086 opening minimized still sets the window as selected
   1.184 +        todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected");
   1.185 +        ok(isTabFocused(), "tab should be focused");
   1.186 +        openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
   1.187 +          is(chatbar.childElementCount, 1, "still 1 chat open");
   1.188 +          ok(!chatbar.firstElementChild.minimized, "chat no longer minimized");
   1.189 +          // bug 865086 because we marked it selected on open, it still is
   1.190 +          todo(chatbar.selectedChat != chatbar.firstElementChild, "chat is not selected");
   1.191 +          ok(isTabFocused(), "tab should still be focused");
   1.192 +          next();
   1.193 +        });
   1.194 +      });
   1.195 +    });
   1.196 +  },
   1.197 +
   1.198 +  // Here we open a chat, which will not be focused.  Then we minimize it and
   1.199 +  // restore it via a titlebar clock - it should get focus at that point.
   1.200 +  testFocusOnExplicitRestore: function(next) {
   1.201 +    startTestAndWaitForSidebar(function(port) {
   1.202 +      openChatViaSidebarMessage(port, {stealFocus: 1}, function() {
   1.203 +        ok(true, "got chatbox message");
   1.204 +        ok(isTabFocused(), "tab should still be focused");
   1.205 +        let chatbox = SocialChatBar.chatbar.firstElementChild;
   1.206 +        ok(chatbox, "chat opened");
   1.207 +        chatbox.minimized = true;
   1.208 +        ok(isTabFocused(), "tab should still be focused");
   1.209 +        // pretend we clicked on the titlebar
   1.210 +        chatbox.onTitlebarClick({button: 0});
   1.211 +        waitForCondition(function() isChatFocused(SocialChatBar.chatbar.selectedChat),
   1.212 +                         function() {
   1.213 +          ok(!chatbox.minimized, "chat should have been restored");
   1.214 +          ok(isChatFocused(chatbox), "chat should be focused");
   1.215 +          is(chatbox, SocialChatBar.chatbar.selectedChat, "chat is marked selected");
   1.216 +          next();
   1.217 +        }, "chat should have focus");
   1.218 +      });
   1.219 +    });
   1.220 +  },
   1.221 +
   1.222 +  // Open 2 chats and give 1 focus.  Minimize the focused one - the second
   1.223 +  // should get focus.
   1.224 +  testMinimizeFocused: function(next) {
   1.225 +    let chatbar = SocialChatBar.chatbar;
   1.226 +    startTestAndWaitForSidebar(function(port) {
   1.227 +      openChatViaSidebarMessage(port, {stealFocus: 1, id: 1}, function() {
   1.228 +        let chat1 = chatbar.firstElementChild;
   1.229 +        openChatViaSidebarMessage(port, {stealFocus: 1, id: 2}, function() {
   1.230 +          is(chatbar.childElementCount, 2, "exactly 2 chats open");
   1.231 +          let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
   1.232 +          chatbar.selectedChat = chat1;
   1.233 +          chatbar.focus();
   1.234 +          waitForCondition(function() isChatFocused(chat1),
   1.235 +                           function() {
   1.236 +            is(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is marked selected");
   1.237 +            isnot(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is not marked selected");
   1.238 +            chat1.minimized = true;
   1.239 +            waitForCondition(function() isChatFocused(chat2),
   1.240 +                             function() {
   1.241 +              // minimizing the chat with focus should give it to another.
   1.242 +              isnot(chat1, SocialChatBar.chatbar.selectedChat, "chat1 is not marked selected");
   1.243 +              is(chat2, SocialChatBar.chatbar.selectedChat, "chat2 is marked selected");
   1.244 +              next();
   1.245 +            }, "chat2 should have focus");
   1.246 +          }, "chat1 should have focus");
   1.247 +        });
   1.248 +      });
   1.249 +    });
   1.250 +  },
   1.251 +
   1.252 +  // Open 2 chats, select (but not focus) one, then re-request it be
   1.253 +  // opened via a message.  Focus should not move.
   1.254 +  testReopenNonFocused: function(next) {
   1.255 +    let chatbar = SocialChatBar.chatbar;
   1.256 +    startTestAndWaitForSidebar(function(port) {
   1.257 +      openChatViaSidebarMessage(port, {id: 1}, function() {
   1.258 +        let chat1 = chatbar.firstElementChild;
   1.259 +        openChatViaSidebarMessage(port, {id: 2}, function() {
   1.260 +          let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
   1.261 +          chatbar.selectedChat = chat2;
   1.262 +          // tab still has focus
   1.263 +          ok(isTabFocused(), "tab should still be focused");
   1.264 +          // re-request the first.
   1.265 +          openChatViaSidebarMessage(port, {id: 1}, function() {
   1.266 +            is(chatbar.selectedChat, chat1, "chat1 now selected");
   1.267 +            ok(isTabFocused(), "tab should still be focused");
   1.268 +            next();
   1.269 +          });
   1.270 +        });
   1.271 +      });
   1.272 +    });
   1.273 +  },
   1.274 +
   1.275 +  // Open 2 chats, select and focus the second.  Pressing the TAB key should
   1.276 +  // cause focus to move between all elements in our chat window before moving
   1.277 +  // to the next chat window.
   1.278 +  testTab: function(next) {
   1.279 +    function sendTabAndWaitForFocus(chat, eltid, callback) {
   1.280 +      // ideally we would use the 'focus' event here, but that doesn't work
   1.281 +      // as expected for the iframe - the iframe itself never gets the focus
   1.282 +      // event (apparently the sub-document etc does.)
   1.283 +      // So just poll for the correct element getting focus...
   1.284 +      let doc = chat.contentDocument;
   1.285 +      EventUtils.sendKey("tab");
   1.286 +      waitForCondition(function() {
   1.287 +        let elt = eltid ? doc.getElementById(eltid) : doc.documentElement;
   1.288 +        return doc.activeElement == elt;
   1.289 +      }, callback, "element " + eltid + " never got focus");
   1.290 +    }
   1.291 +
   1.292 +    let chatbar = SocialChatBar.chatbar;
   1.293 +    startTestAndWaitForSidebar(function(port) {
   1.294 +      openChatViaSidebarMessage(port, {id: 1}, function() {
   1.295 +        let chat1 = chatbar.firstElementChild;
   1.296 +        openChatViaSidebarMessage(port, {id: 2}, function() {
   1.297 +          let chat2 = chat1.nextElementSibling || chat1.previousElementSibling;
   1.298 +          chatbar.selectedChat = chat2;
   1.299 +          chatbar.focus();
   1.300 +          waitForCondition(function() isChatFocused(chatbar.selectedChat),
   1.301 +                           function() {
   1.302 +            // Our chats have 3 focusable elements, so it takes 4 TABs to move
   1.303 +            // to the new chat.
   1.304 +            sendTabAndWaitForFocus(chat2, "input1", function() {
   1.305 +              is(chat2.contentDocument.activeElement.getAttribute("id"), "input1",
   1.306 +                 "first input field has focus");
   1.307 +              ok(isChatFocused(chat2), "new chat still focused after first tab");
   1.308 +              sendTabAndWaitForFocus(chat2, "input2", function() {
   1.309 +                ok(isChatFocused(chat2), "new chat still focused after tab");
   1.310 +                is(chat2.contentDocument.activeElement.getAttribute("id"), "input2",
   1.311 +                   "second input field has focus");
   1.312 +                sendTabAndWaitForFocus(chat2, "iframe", function() {
   1.313 +                  ok(isChatFocused(chat2), "new chat still focused after tab");
   1.314 +                  is(chat2.contentDocument.activeElement.getAttribute("id"), "iframe",
   1.315 +                     "iframe has focus");
   1.316 +                  // this tab now should move to the next chat, but focus the
   1.317 +                  // document element itself (hence the null eltid)
   1.318 +                  sendTabAndWaitForFocus(chat1, null, function() {
   1.319 +                    ok(isChatFocused(chat1), "first chat is focused");
   1.320 +                    next();
   1.321 +                  });
   1.322 +                });
   1.323 +              });
   1.324 +            });
   1.325 +          }, "chat should have focus");
   1.326 +        });
   1.327 +      });
   1.328 +    });
   1.329 +  },
   1.330 +
   1.331 +  // Open a chat and focus an element other than the first. Move focus to some
   1.332 +  // other item (the tab itself in this case), then focus the chatbar - the
   1.333 +  // same element that was previously focused should still have focus.
   1.334 +  testFocusedElement: function(next) {
   1.335 +    let chatbar = SocialChatBar.chatbar;
   1.336 +    startTestAndWaitForSidebar(function(port) {
   1.337 +      openChatViaUser();
   1.338 +      let chat = chatbar.firstElementChild;
   1.339 +      // need to wait for the content to load before we can focus it.
   1.340 +      chat.addEventListener("DOMContentLoaded", function DOMContentLoaded() {
   1.341 +        chat.removeEventListener("DOMContentLoaded", DOMContentLoaded);
   1.342 +        chat.contentDocument.getElementById("input2").focus();
   1.343 +        waitForCondition(function() isChatFocused(chat),
   1.344 +                         function() {
   1.345 +          is(chat.contentDocument.activeElement.getAttribute("id"), "input2",
   1.346 +             "correct input field has focus");
   1.347 +          // set focus to the tab.
   1.348 +          let tabb = gBrowser.getBrowserForTab(gBrowser.selectedTab);
   1.349 +          Services.focus.moveFocus(tabb.contentWindow, null, Services.focus.MOVEFOCUS_ROOT, 0);
   1.350 +          waitForCondition(function() isTabFocused(),
   1.351 +                           function() {
   1.352 +            chatbar.focus();
   1.353 +            waitForCondition(function() isChatFocused(chat),
   1.354 +                             function() {
   1.355 +              is(chat.contentDocument.activeElement.getAttribute("id"), "input2",
   1.356 +                 "correct input field still has focus");
   1.357 +              next();
   1.358 +            }, "chat took focus");
   1.359 +          }, "tab has focus");
   1.360 +        }, "chat took focus");
   1.361 +      });
   1.362 +    });
   1.363 +  },
   1.364 +};

mercurial