diff --git a/browser/base/content/socialchat.xml b/browser/base/content/socialchat.xml index b1cddaf2c773..c61d932c2642 100644 --- a/browser/base/content/socialchat.xml +++ b/browser/base/content/socialchat.xml @@ -620,7 +620,7 @@ diff --git a/browser/base/content/test/social/Makefile.in b/browser/base/content/test/social/Makefile.in index ff334cc61759..37c28c1dd025 100644 --- a/browser/base/content/test/social/Makefile.in +++ b/browser/base/content/test/social/Makefile.in @@ -27,6 +27,7 @@ MOCHITEST_BROWSER_FILES = \ browser_social_mozSocial_API.js \ browser_social_isVisible.js \ browser_social_chatwindow.js \ + browser_social_chatwindow_resize.js \ browser_social_chatwindowfocus.js \ browser_social_multiprovider.js \ browser_social_errorPage.js \ diff --git a/browser/base/content/test/social/browser_social_chatwindow.js b/browser/base/content/test/social/browser_social_chatwindow.js index 78ecf60964e8..9fb47d3f906e 100644 --- a/browser/base/content/test/social/browser_social_chatwindow.js +++ b/browser/base/content/test/social/browser_social_chatwindow.js @@ -287,47 +287,6 @@ var tests = { }); }, - // resize and collapse testing. - testBrowserResize: function(next, mode) { - let chats = document.getElementById("pinnedchats"); - let port = Social.provider.getWorkerPort(); - port.postMessage({topic: "test-init"}); - get3ChatsForCollapsing(mode || "normal", function(first, second, third) { - let chatWidth = chats.getTotalChildWidth(first); - ok(chatWidth, "have a chatwidth"); - let popupWidth = getPopupWidth(); - ok(popupWidth, "have a popupwidth"); - info("starting resize tests - each chat's width is " + chatWidth + - " and the popup width is " + popupWidth); - // Note that due to a difference between "device", "app" and "css" pixels - // we allow use 2 pixels as the minimum size difference. - resizeAndCheckWidths(first, second, third, [ - [chatWidth-2, 1, "to < 1 chat width - only last should be visible."], - [chatWidth+2, 1, "2 pixels more then one fully exposed (not counting popup) - still only 1."], - [chatWidth+popupWidth+2, 1, "2 pixels more than one fully exposed (including popup) - still only 1."], - [chatWidth*2-2, 1, "second not showing by 2 pixels (not counting popup) - only 1 exposed."], - [chatWidth*2+popupWidth-2, 1, "second not showing by 2 pixelx (including popup) - only 1 exposed."], - [chatWidth*2+popupWidth+2, 2, "big enough to fit 2 - nub remains visible as first is still hidden"], - [chatWidth*3+popupWidth-2, 2, "one smaller than the size necessary to display all three - first still hidden"], - [chatWidth*3+popupWidth+2, 3, "big enough to fit all - all exposed (which removes the nub)"], - [chatWidth*3+2, 3, "now the nub is hidden we can resize back down to chatWidth*3 before overflow."], - [chatWidth*3-2, 2, "2 pixels less and the first is again collapsed (and the nub re-appears)"], - [chatWidth*2+popupWidth+2, 2, "back down to just big enough to fit 2"], - [chatWidth*2+popupWidth-2, 1, "back down to just not enough to fit 2"], - [chatWidth*3+popupWidth+2, 3, "now a large jump to make all 3 visible (ie, affects 2)"], - [chatWidth*1.5, 1, "and a large jump back down to 1 visible (ie, affects 2)"], - ], function() { - closeAllChats(); - port.close(); - next(); - }); - }); - }, - - testBrowserResizeMinimized: function(next) { - this.testBrowserResize(next, "minimized"); - }, - testShowWhenCollapsed: function(next) { let port = Social.provider.getWorkerPort(); port.postMessage({topic: "test-init"}); @@ -511,159 +470,3 @@ var tests = { port.postMessage({topic: "test-worker-chat", data: chatUrl}); }, } - -// And lots of helpers for the resize tests. -function get3ChatsForCollapsing(mode, cb) { - // We make one chat, then measure its size. We then resize the browser to - // ensure a second can be created fully visible but a third can not - then - // create the other 2. first will will be collapsed, second fully visible - // and the third also visible and the "selected" one. - // To make our life easier we don't go via the worker and ports so we get - // more control over creation *and* to make the code much simpler. We - // assume the worker/port stuff is individually tested above. - let chatbar = window.SocialChatBar.chatbar; - let chatWidth = undefined; - let num = 0; - is(chatbar.childNodes.length, 0, "chatbar starting empty"); - is(chatbar.menupopup.childNodes.length, 0, "popup starting empty"); - - makeChat(mode, "first chat", function() { - // got the first one. - checkPopup(); - ok(chatbar.menupopup.parentNode.collapsed, "menu selection isn't visible"); - // we kinda cheat here and get the width of the first chat, assuming - // that all future chats will have the same width when open. - chatWidth = chatbar.calcTotalWidthOf(chatbar.selectedChat); - let desired = chatWidth * 2.5; - resizeWindowToChatAreaWidth(desired, function(sizedOk) { - ok(sizedOk, "can't do any tests without this width"); - checkPopup(); - makeChat(mode, "second chat", function() { - is(chatbar.childNodes.length, 2, "now have 2 chats"); - checkPopup(); - // and create the third. - makeChat(mode, "third chat", function() { - is(chatbar.childNodes.length, 3, "now have 3 chats"); - checkPopup(); - // XXX - this is a hacky implementation detail around the order of - // the chats. Ideally things would be a little more sane wrt the - // other in which the children were created. - let second = chatbar.childNodes[2]; - let first = chatbar.childNodes[1]; - let third = chatbar.childNodes[0]; - ok(first.collapsed && !second.collapsed && !third.collapsed, "collapsed state as promised"); - is(chatbar.selectedChat, third, "third is selected as promised") - info("have 3 chats for collapse testing - starting actual test..."); - cb(first, second, third); - }, mode); - }, mode); - }); - }, mode); -} - -function makeChat(mode, uniqueid, cb) { - const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html"; - let provider = Social.provider; - window.SocialChatBar.openChat(provider, chatUrl + "?id=" + uniqueid, function(chat) { - // we can't callback immediately or we might close the chat during - // this event which upsets the implementation - it is only 1/2 way through - // handling the load event. - chat.document.title = uniqueid; - executeSoon(cb); - }, mode); -} - -function checkPopup() { - // popup only showing if any collapsed popup children. - let chatbar = window.SocialChatBar.chatbar; - let numCollapsed = 0; - for (let chat of chatbar.childNodes) { - if (chat.collapsed) { - numCollapsed += 1; - // and it have a menuitem weakmap - is(chatbar.menuitemMap.get(chat).nodeName, "menuitem", "collapsed chat has a menu item"); - } else { - ok(!chatbar.menuitemMap.has(chat), "open chat has no menu item"); - } - } - is(chatbar.menupopup.parentNode.collapsed, numCollapsed == 0, "popup matches child collapsed state"); - is(chatbar.menupopup.childNodes.length, numCollapsed, "popup has correct count of children"); - // todo - check each individual elt is what we expect? -} - -// Resize the main window so the chat area's boxObject is |desired| wide. -// Does a callback passing |true| if the window is now big enough or false -// if we couldn't resize large enough to satisfy the test requirement. -function resizeWindowToChatAreaWidth(desired, cb) { - let current = window.SocialChatBar.chatbar.getBoundingClientRect().width; - let delta = desired - current; - info("resizing window so chat area is " + desired + " wide, currently it is " - + current + ". Screen avail is " + window.screen.availWidth - + ", current outer width is " + window.outerWidth); - - // WTF? Sometimes we will get fractional values due to the - err - magic - // of DevPointsPerCSSPixel etc, so we allow a couple of pixels difference. - let widthDeltaCloseEnough = function(d) { - return Math.abs(d) < 2; - } - - // attempting to resize by (0,0), unsurprisingly, doesn't cause a resize - // event - so just callback saying all is well. - if (widthDeltaCloseEnough(delta)) { - cb(true); - return; - } - // On lo-res screens we may already be maxed out but still smaller than the - // requested size, so asking to resize up also will not cause a resize event. - // So just callback now saying the test must be skipped. - if (window.screen.availWidth - window.outerWidth < delta) { - info("skipping this as screen available width is less than necessary"); - cb(false); - return; - } - // Otherwise we request resize and expect a resize event - window.addEventListener("resize", function resize_handler() { - // we did resize - but did we get far enough to be able to continue? - let newSize = window.SocialChatBar.chatbar.getBoundingClientRect().width; - let sizedOk = widthDeltaCloseEnough(newSize - desired); - if (!sizedOk) { - return; - } - window.removeEventListener("resize", resize_handler); - executeSoon(function() { - cb(sizedOk); - }); - }); - window.resizeBy(delta, 0); -} - -function resizeAndCheckWidths(first, second, third, checks, cb) { - if (checks.length == 0) { - cb(); // nothing more to check! - return; - } - let [width, numExpectedVisible, why] = checks.shift(); - info("Check: " + why); - info("resizing window to " + width + ", expect " + numExpectedVisible + " visible items"); - resizeWindowToChatAreaWidth(width, function(sizedOk) { - checkPopup(); - if (sizedOk) { - let numVisible = [first, second, third].filter(function(item) !item.collapsed).length; - is(numVisible, numExpectedVisible, "correct number of chats visible"); - } - resizeAndCheckWidths(first, second, third, checks, cb); - }); -} - -function getPopupWidth() { - let popup = window.SocialChatBar.chatbar.menupopup; - ok(!popup.parentNode.collapsed, "asking for popup width when it is visible"); - let cs = document.defaultView.getComputedStyle(popup.parentNode); - let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight); - return popup.parentNode.getBoundingClientRect().width + margins; -} - -function closeAllChats() { - let chatbar = window.SocialChatBar.chatbar; - chatbar.removeAll(); -} diff --git a/browser/base/content/test/social/browser_social_chatwindow_resize.js b/browser/base/content/test/social/browser_social_chatwindow_resize.js new file mode 100644 index 000000000000..c6bd72078ab4 --- /dev/null +++ b/browser/base/content/test/social/browser_social_chatwindow_resize.js @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +function test() { + requestLongerTimeout(2); // only debug builds seem to need more time... + waitForExplicitFinish(); + + let manifest = { // normal provider + name: "provider 1", + origin: "https://example.com", + sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html", + workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js", + iconURL: "https://example.com/browser/browser/base/content/test/moz.png", + // added for test purposes + chatURL: "https://example.com/browser/browser/base/content/test/social/social_chat.html" + }; + let oldwidth = window.outerWidth; // we futz with these, so we restore them + let oldleft = window.screenX; + window.moveTo(0, window.screenY) + let postSubTest = function(cb) { + let chats = document.getElementById("pinnedchats"); + ok(chats.children.length == 0, "no chatty children left behind"); + cb(); + }; + + runSocialTestWithProvider(manifest, function (finishcb) { + let port = Social.provider.getWorkerPort(); + ok(port, "provider has a port"); + port.postMessage({topic: "test-init"}); + // we require a logged in user for chats, wait for that + waitForCondition(function() { + let sbrowser = document.getElementById("social-sidebar-browser"); + return Social.provider && + Social.provider.profile && + Social.provider.profile.displayName && + sbrowser.docShellIsActive; + }, function() { + // executeSoon to let the browser UI observers run first + runSocialTests(tests, undefined, postSubTest, function() { + window.moveTo(oldleft, window.screenY) + window.resizeTo(oldwidth, window.outerHeight); + port.close(); + finishcb(); + }); + }, + "waitForProviderLoad: provider profile was not set"); + }); +} + +var tests = { + + // resize and collapse testing. + testBrowserResize: function(next, mode) { + let chats = document.getElementById("pinnedchats"); + get3ChatsForCollapsing(mode || "normal", function(first, second, third) { + let chatWidth = chats.getTotalChildWidth(first); + ok(chatWidth, "have a chatwidth"); + let popupWidth = getPopupWidth(); + ok(popupWidth, "have a popupwidth"); + info("starting resize tests - each chat's width is " + chatWidth + + " and the popup width is " + popupWidth); + // Note that due to a difference between "device", "app" and "css" pixels + // we allow use 2 pixels as the minimum size difference. + resizeAndCheckWidths(first, second, third, [ + [chatWidth-2, 1, "to < 1 chat width - only last should be visible."], + [chatWidth+2, 1, "2 pixels more then one fully exposed (not counting popup) - still only 1."], + [chatWidth+popupWidth+2, 1, "2 pixels more than one fully exposed (including popup) - still only 1."], + [chatWidth*2-2, 1, "second not showing by 2 pixels (not counting popup) - only 1 exposed."], + [chatWidth*2+popupWidth-2, 1, "second not showing by 2 pixelx (including popup) - only 1 exposed."], + [chatWidth*2+popupWidth+2, 2, "big enough to fit 2 - nub remains visible as first is still hidden"], + [chatWidth*3+popupWidth-2, 2, "one smaller than the size necessary to display all three - first still hidden"], + [chatWidth*3+popupWidth+2, 3, "big enough to fit all - all exposed (which removes the nub)"], + [chatWidth*3+2, 3, "now the nub is hidden we can resize back down to chatWidth*3 before overflow."], + [chatWidth*3-2, 2, "2 pixels less and the first is again collapsed (and the nub re-appears)"], + [chatWidth*2+popupWidth+2, 2, "back down to just big enough to fit 2"], + [chatWidth*2+popupWidth-2, 1, "back down to just not enough to fit 2"], + [chatWidth*3+popupWidth+2, 3, "now a large jump to make all 3 visible (ie, affects 2)"], + [chatWidth*1.5, 1, "and a large jump back down to 1 visible (ie, affects 2)"], + ], function() { + closeAllChats(); + next(); + }); + }); + }, + + testBrowserResizeMinimized: function(next) { + this.testBrowserResize(next); + } +} diff --git a/browser/base/content/test/social/head.js b/browser/base/content/test/social/head.js index 357bd9fcd8cf..cb37e3c925cd 100644 --- a/browser/base/content/test/social/head.js +++ b/browser/base/content/test/social/head.js @@ -345,3 +345,180 @@ function loadIntoTab(tab, url, callback) { tab.linkedBrowser.loadURI(url); } + +// chat test help functions + +// And lots of helpers for the resize tests. +function get3ChatsForCollapsing(mode, cb) { + // We make one chat, then measure its size. We then resize the browser to + // ensure a second can be created fully visible but a third can not - then + // create the other 2. first will will be collapsed, second fully visible + // and the third also visible and the "selected" one. + // To make our life easier we don't go via the worker and ports so we get + // more control over creation *and* to make the code much simpler. We + // assume the worker/port stuff is individually tested above. + let chatbar = window.SocialChatBar.chatbar; + let chatWidth = undefined; + let num = 0; + is(chatbar.childNodes.length, 0, "chatbar starting empty"); + is(chatbar.menupopup.childNodes.length, 0, "popup starting empty"); + + makeChat(mode, "first chat", function() { + // got the first one. + checkPopup(); + ok(chatbar.menupopup.parentNode.collapsed, "menu selection isn't visible"); + // we kinda cheat here and get the width of the first chat, assuming + // that all future chats will have the same width when open. + chatWidth = chatbar.calcTotalWidthOf(chatbar.selectedChat); + let desired = chatWidth * 2.5; + resizeWindowToChatAreaWidth(desired, function(sizedOk) { + ok(sizedOk, "can't do any tests without this width"); + checkPopup(); + makeChat(mode, "second chat", function() { + is(chatbar.childNodes.length, 2, "now have 2 chats"); + checkPopup(); + // and create the third. + makeChat(mode, "third chat", function() { + is(chatbar.childNodes.length, 3, "now have 3 chats"); + checkPopup(); + // XXX - this is a hacky implementation detail around the order of + // the chats. Ideally things would be a little more sane wrt the + // other in which the children were created. + let second = chatbar.childNodes[2]; + let first = chatbar.childNodes[1]; + let third = chatbar.childNodes[0]; + ok(first.collapsed && !second.collapsed && !third.collapsed, "collapsed state as promised"); + is(chatbar.selectedChat, third, "third is selected as promised") + info("have 3 chats for collapse testing - starting actual test..."); + cb(first, second, third); + }, mode); + }, mode); + }); + }, mode); +} + +function makeChat(mode, uniqueid, cb) { + info("making a chat window '" + uniqueid +"'"); + const chatUrl = "https://example.com/browser/browser/base/content/test/social/social_chat.html"; + let provider = Social.provider; + let isOpened = window.SocialChatBar.openChat(provider, chatUrl + "?id=" + uniqueid, function(chat) { + info("chat window has opened"); + // we can't callback immediately or we might close the chat during + // this event which upsets the implementation - it is only 1/2 way through + // handling the load event. + chat.document.title = uniqueid; + executeSoon(cb); + }, mode); + if (!isOpened) { + ok(false, "unable to open chat window, no provider? more failures to come"); + executeSoon(cb); + } +} + +function checkPopup() { + // popup only showing if any collapsed popup children. + let chatbar = window.SocialChatBar.chatbar; + let numCollapsed = 0; + for (let chat of chatbar.childNodes) { + if (chat.collapsed) { + numCollapsed += 1; + // and it have a menuitem weakmap + is(chatbar.menuitemMap.get(chat).nodeName, "menuitem", "collapsed chat has a menu item"); + } else { + ok(!chatbar.menuitemMap.has(chat), "open chat has no menu item"); + } + } + is(chatbar.menupopup.parentNode.collapsed, numCollapsed == 0, "popup matches child collapsed state"); + is(chatbar.menupopup.childNodes.length, numCollapsed, "popup has correct count of children"); + // todo - check each individual elt is what we expect? +} +// Resize the main window so the chat area's boxObject is |desired| wide. +// Does a callback passing |true| if the window is now big enough or false +// if we couldn't resize large enough to satisfy the test requirement. +function resizeWindowToChatAreaWidth(desired, cb, count = 0) { + let current = window.SocialChatBar.chatbar.getBoundingClientRect().width; + let delta = desired - current; + info(count + ": resizing window so chat area is " + desired + " wide, currently it is " + + current + ". Screen avail is " + window.screen.availWidth + + ", current outer width is " + window.outerWidth); + + // WTF? Sometimes we will get fractional values due to the - err - magic + // of DevPointsPerCSSPixel etc, so we allow a couple of pixels difference. + let widthDeltaCloseEnough = function(d) { + return Math.abs(d) < 2; + } + + // attempting to resize by (0,0), unsurprisingly, doesn't cause a resize + // event - so just callback saying all is well. + if (widthDeltaCloseEnough(delta)) { + info(count + ": skipping this as screen width is close enough"); + executeSoon(function() { + cb(true); + }); + return; + } + // On lo-res screens we may already be maxed out but still smaller than the + // requested size, so asking to resize up also will not cause a resize event. + // So just callback now saying the test must be skipped. + if (window.screen.availWidth - window.outerWidth < delta) { + info(count + ": skipping this as screen available width is less than necessary"); + executeSoon(function() { + cb(false); + }); + return; + } + function resize_handler(event) { + // for whatever reason, sometimes we get called twice for different event + // phases, only handle one of them. + if (event.eventPhase != event.AT_TARGET) + return; + // we did resize - but did we get far enough to be able to continue? + let newSize = window.SocialChatBar.chatbar.getBoundingClientRect().width; + let sizedOk = widthDeltaCloseEnough(newSize - desired); + if (!sizedOk) + return; + window.removeEventListener("resize", resize_handler); + info(count + ": resized window width is " + newSize); + executeSoon(function() { + cb(sizedOk); + }); + } + // Otherwise we request resize and expect a resize event + window.addEventListener("resize", resize_handler); + window.resizeBy(delta, 0); +} + +function resizeAndCheckWidths(first, second, third, checks, cb) { + if (checks.length == 0) { + cb(); // nothing more to check! + return; + } + let count = checks.length; + let [width, numExpectedVisible, why] = checks.shift(); + info("<< Check " + count + ": " + why); + info(count + ": " + "resizing window to " + width + ", expect " + numExpectedVisible + " visible items"); + resizeWindowToChatAreaWidth(width, function(sizedOk) { + checkPopup(); + ok(sizedOk, count+": window resized correctly"); + if (sizedOk) { + let numVisible = [first, second, third].filter(function(item) !item.collapsed).length; + is(numVisible, numExpectedVisible, count + ": " + "correct number of chats visible"); + } + info(">> Check " + count); + resizeAndCheckWidths(first, second, third, checks, cb); + }, count); +} + +function getPopupWidth() { + let popup = window.SocialChatBar.chatbar.menupopup; + ok(!popup.parentNode.collapsed, "asking for popup width when it is visible"); + let cs = document.defaultView.getComputedStyle(popup.parentNode); + let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight); + return popup.parentNode.getBoundingClientRect().width + margins; +} + +function closeAllChats() { + let chatbar = window.SocialChatBar.chatbar; + chatbar.removeAll(); +} +