1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/test/social/head.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,578 @@ 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 +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); 1.9 + 1.10 +XPCOMUtils.defineLazyModuleGetter(this, "Promise", 1.11 + "resource://gre/modules/Promise.jsm"); 1.12 +XPCOMUtils.defineLazyModuleGetter(this, "Task", 1.13 + "resource://gre/modules/Task.jsm"); 1.14 +XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", 1.15 + "resource://gre/modules/PlacesUtils.jsm"); 1.16 + 1.17 +function waitForCondition(condition, nextTest, errorMsg) { 1.18 + var tries = 0; 1.19 + var interval = setInterval(function() { 1.20 + if (tries >= 30) { 1.21 + ok(false, errorMsg); 1.22 + moveOn(); 1.23 + } 1.24 + var conditionPassed; 1.25 + try { 1.26 + conditionPassed = condition(); 1.27 + } catch (e) { 1.28 + ok(false, e + "\n" + e.stack); 1.29 + conditionPassed = false; 1.30 + } 1.31 + if (conditionPassed) { 1.32 + moveOn(); 1.33 + } 1.34 + tries++; 1.35 + }, 100); 1.36 + var moveOn = function() { clearInterval(interval); nextTest(); }; 1.37 +} 1.38 + 1.39 +// Check that a specified (string) URL hasn't been "remembered" (ie, is not 1.40 +// in history, will not appear in about:newtab or auto-complete, etc.) 1.41 +function promiseSocialUrlNotRemembered(url) { 1.42 + let deferred = Promise.defer(); 1.43 + let uri = Services.io.newURI(url, null, null); 1.44 + PlacesUtils.asyncHistory.isURIVisited(uri, function(aURI, aIsVisited) { 1.45 + ok(!aIsVisited, "social URL " + url + " should not be in global history"); 1.46 + deferred.resolve(); 1.47 + }); 1.48 + return deferred.promise; 1.49 +} 1.50 + 1.51 +let gURLsNotRemembered = []; 1.52 + 1.53 + 1.54 +function checkProviderPrefsEmpty(isError) { 1.55 + let MANIFEST_PREFS = Services.prefs.getBranch("social.manifest."); 1.56 + let prefs = MANIFEST_PREFS.getChildList("", []); 1.57 + let c = 0; 1.58 + for (let pref of prefs) { 1.59 + if (MANIFEST_PREFS.prefHasUserValue(pref)) { 1.60 + info("provider [" + pref + "] manifest left installed from previous test"); 1.61 + c++; 1.62 + } 1.63 + } 1.64 + is(c, 0, "all provider prefs uninstalled from previous test"); 1.65 + is(Social.providers.length, 0, "all providers uninstalled from previous test " + Social.providers.length); 1.66 +} 1.67 + 1.68 +function defaultFinishChecks() { 1.69 + checkProviderPrefsEmpty(true); 1.70 + finish(); 1.71 +} 1.72 + 1.73 +function runSocialTestWithProvider(manifest, callback, finishcallback) { 1.74 + let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; 1.75 + 1.76 + let manifests = Array.isArray(manifest) ? manifest : [manifest]; 1.77 + 1.78 + // Check that none of the provider's content ends up in history. 1.79 + function finishCleanUp() { 1.80 + ok(!SocialSidebar.provider, "no provider in sidebar"); 1.81 + SessionStore.setWindowValue(window, "socialSidebar", ""); 1.82 + for (let i = 0; i < manifests.length; i++) { 1.83 + let m = manifests[i]; 1.84 + for (let what of ['sidebarURL', 'workerURL', 'iconURL']) { 1.85 + if (m[what]) { 1.86 + yield promiseSocialUrlNotRemembered(m[what]); 1.87 + } 1.88 + }; 1.89 + } 1.90 + for (let i = 0; i < gURLsNotRemembered.length; i++) { 1.91 + yield promiseSocialUrlNotRemembered(gURLsNotRemembered[i]); 1.92 + } 1.93 + gURLsNotRemembered = []; 1.94 + } 1.95 + 1.96 + info("runSocialTestWithProvider: " + manifests.toSource()); 1.97 + 1.98 + let finishCount = 0; 1.99 + function finishIfDone(callFinish) { 1.100 + finishCount++; 1.101 + if (finishCount == manifests.length) 1.102 + Task.spawn(finishCleanUp).then(finishcallback || defaultFinishChecks); 1.103 + } 1.104 + function removeAddedProviders(cleanup) { 1.105 + manifests.forEach(function (m) { 1.106 + // If we're "cleaning up", don't call finish when done. 1.107 + let callback = cleanup ? function () {} : finishIfDone; 1.108 + // Similarly, if we're cleaning up, catch exceptions from removeProvider 1.109 + let removeProvider = SocialService.removeProvider.bind(SocialService); 1.110 + if (cleanup) { 1.111 + removeProvider = function (origin, cb) { 1.112 + try { 1.113 + SocialService.removeProvider(origin, cb); 1.114 + } catch (ex) { 1.115 + // Ignore "provider doesn't exist" errors. 1.116 + if (ex.message.indexOf("SocialService.removeProvider: no provider with origin") == 0) 1.117 + return; 1.118 + info("Failed to clean up provider " + origin + ": " + ex); 1.119 + } 1.120 + } 1.121 + } 1.122 + removeProvider(m.origin, callback); 1.123 + }); 1.124 + } 1.125 + function finishSocialTest(cleanup) { 1.126 + removeAddedProviders(cleanup); 1.127 + } 1.128 + 1.129 + let providersAdded = 0; 1.130 + let firstProvider; 1.131 + 1.132 + manifests.forEach(function (m) { 1.133 + SocialService.addProvider(m, function(provider) { 1.134 + 1.135 + providersAdded++; 1.136 + info("runSocialTestWithProvider: provider added"); 1.137 + 1.138 + // we want to set the first specified provider as the UI's provider 1.139 + if (provider.origin == manifests[0].origin) { 1.140 + firstProvider = provider; 1.141 + } 1.142 + 1.143 + // If we've added all the providers we need, call the callback to start 1.144 + // the tests (and give it a callback it can call to finish them) 1.145 + if (providersAdded == manifests.length) { 1.146 + registerCleanupFunction(function () { 1.147 + finishSocialTest(true); 1.148 + }); 1.149 + waitForCondition(function() provider.enabled, 1.150 + function() { 1.151 + info("provider has been enabled"); 1.152 + callback(finishSocialTest); 1.153 + }, "providers added and enabled"); 1.154 + } 1.155 + }); 1.156 + }); 1.157 +} 1.158 + 1.159 +function runSocialTests(tests, cbPreTest, cbPostTest, cbFinish) { 1.160 + let testIter = Iterator(tests); 1.161 + let providersAtStart = Social.providers.length; 1.162 + info("runSocialTests: start test run with " + providersAtStart + " providers"); 1.163 + 1.164 + if (cbPreTest === undefined) { 1.165 + cbPreTest = function(cb) {cb()}; 1.166 + } 1.167 + if (cbPostTest === undefined) { 1.168 + cbPostTest = function(cb) {cb()}; 1.169 + } 1.170 + 1.171 + function runNextTest() { 1.172 + let name, func; 1.173 + try { 1.174 + [name, func] = testIter.next(); 1.175 + } catch (err if err instanceof StopIteration) { 1.176 + // out of items: 1.177 + (cbFinish || defaultFinishChecks)(); 1.178 + is(providersAtStart, Social.providers.length, 1.179 + "runSocialTests: finish test run with " + Social.providers.length + " providers"); 1.180 + return; 1.181 + } 1.182 + // We run on a timeout as the frameworker also makes use of timeouts, so 1.183 + // this helps keep the debug messages sane. 1.184 + executeSoon(function() { 1.185 + function cleanupAndRunNextTest() { 1.186 + info("sub-test " + name + " complete"); 1.187 + cbPostTest(runNextTest); 1.188 + } 1.189 + cbPreTest(function() { 1.190 + info("pre-test: starting with " + Social.providers.length + " providers"); 1.191 + info("sub-test " + name + " starting"); 1.192 + try { 1.193 + func.call(tests, cleanupAndRunNextTest); 1.194 + } catch (ex) { 1.195 + ok(false, "sub-test " + name + " failed: " + ex.toString() +"\n"+ex.stack); 1.196 + cleanupAndRunNextTest(); 1.197 + } 1.198 + }) 1.199 + }); 1.200 + } 1.201 + runNextTest(); 1.202 +} 1.203 + 1.204 +// A fairly large hammer which checks all aspects of the SocialUI for 1.205 +// internal consistency. 1.206 +function checkSocialUI(win) { 1.207 + let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService; 1.208 + win = win || window; 1.209 + let doc = win.document; 1.210 + let enabled = win.SocialUI.enabled; 1.211 + let active = Social.providers.length > 0 && !win.SocialUI._chromeless && 1.212 + !PrivateBrowsingUtils.isWindowPrivate(win); 1.213 + let sidebarEnabled = win.SocialSidebar.provider ? enabled : false; 1.214 + 1.215 + // if we have enabled providers, we should also have instances of those 1.216 + // providers 1.217 + if (SocialService.hasEnabledProviders) { 1.218 + ok(Social.providers.length > 0, "providers are enabled"); 1.219 + } else { 1.220 + is(Social.providers.length, 0, "providers are not enabled"); 1.221 + } 1.222 + 1.223 + // some local helpers to avoid log-spew for the many checks made here. 1.224 + let numGoodTests = 0, numTests = 0; 1.225 + function _ok(what, msg) { 1.226 + numTests++; 1.227 + if (!ok) 1.228 + ok(what, msg) 1.229 + else 1.230 + ++numGoodTests; 1.231 + } 1.232 + function _is(a, b, msg) { 1.233 + numTests++; 1.234 + if (a != b) 1.235 + is(a, b, msg) 1.236 + else 1.237 + ++numGoodTests; 1.238 + } 1.239 + function isbool(a, b, msg) { 1.240 + _is(!!a, !!b, msg); 1.241 + } 1.242 + isbool(win.SocialSidebar.canShow, sidebarEnabled, "social sidebar active?"); 1.243 + isbool(win.SocialChatBar.isAvailable, enabled, "chatbar available?"); 1.244 + isbool(!win.SocialChatBar.chatbar.hidden, enabled, "chatbar visible?"); 1.245 + 1.246 + let contextMenus = [ 1.247 + { 1.248 + type: "link", 1.249 + id: "context-marklinkMenu", 1.250 + label: "social.marklinkMenu.label" 1.251 + }, 1.252 + { 1.253 + type: "page", 1.254 + id: "context-markpageMenu", 1.255 + label: "social.markpageMenu.label" 1.256 + } 1.257 + ]; 1.258 + 1.259 + for (let c of contextMenus) { 1.260 + let leMenu = document.getElementById(c.id); 1.261 + let parent, menus; 1.262 + let markProviders = SocialMarks.getProviders(); 1.263 + if (markProviders.length > SocialMarks.MENU_LIMIT) { 1.264 + // menus should be in a submenu, not in the top level of the context menu 1.265 + parent = leMenu.firstChild; 1.266 + menus = document.getElementsByClassName("context-mark" + c.type); 1.267 + _is(menus.length, 0, "menu's are not in main context menu\n"); 1.268 + menus = parent.childNodes; 1.269 + _is(menus.length, markProviders.length, c.id + " menu exists for each mark provider"); 1.270 + } else { 1.271 + // menus should be in the top level of the context menu, not in a submenu 1.272 + parent = leMenu.parentNode; 1.273 + menus = document.getElementsByClassName("context-mark" + c.type); 1.274 + _is(menus.length, markProviders.length, c.id + " menu exists for each mark provider"); 1.275 + menus = leMenu.firstChild.childNodes; 1.276 + _is(menus.length, 0, "menu's are not in context submenu\n"); 1.277 + } 1.278 + for (let m of menus) 1.279 + _is(m.parentNode, parent, "menu has correct parent"); 1.280 + } 1.281 + 1.282 + // and for good measure, check all the social commands. 1.283 + isbool(!doc.getElementById("Social:ToggleSidebar").hidden, sidebarEnabled, "Social:ToggleSidebar visible?"); 1.284 + isbool(!doc.getElementById("Social:ToggleNotifications").hidden, enabled, "Social:ToggleNotifications visible?"); 1.285 + isbool(!doc.getElementById("Social:FocusChat").hidden, enabled, "Social:FocusChat visible?"); 1.286 + isbool(doc.getElementById("Social:FocusChat").getAttribute("disabled"), enabled ? "false" : "true", "Social:FocusChat disabled?"); 1.287 + 1.288 + // and report on overall success of failure of the various checks here. 1.289 + is(numGoodTests, numTests, "The Social UI tests succeeded.") 1.290 +} 1.291 + 1.292 +function waitForNotification(topic, cb) { 1.293 + function observer(subject, topic, data) { 1.294 + Services.obs.removeObserver(observer, topic); 1.295 + cb(); 1.296 + } 1.297 + Services.obs.addObserver(observer, topic, false); 1.298 +} 1.299 + 1.300 +// blocklist testing 1.301 +function updateBlocklist(aCallback) { 1.302 + var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"] 1.303 + .getService(Ci.nsITimerCallback); 1.304 + var observer = function() { 1.305 + Services.obs.removeObserver(observer, "blocklist-updated"); 1.306 + if (aCallback) 1.307 + executeSoon(aCallback); 1.308 + }; 1.309 + Services.obs.addObserver(observer, "blocklist-updated", false); 1.310 + blocklistNotifier.notify(null); 1.311 +} 1.312 + 1.313 +var _originalTestBlocklistURL = null; 1.314 +function setAndUpdateBlocklist(aURL, aCallback) { 1.315 + if (!_originalTestBlocklistURL) 1.316 + _originalTestBlocklistURL = Services.prefs.getCharPref("extensions.blocklist.url"); 1.317 + Services.prefs.setCharPref("extensions.blocklist.url", aURL); 1.318 + updateBlocklist(aCallback); 1.319 +} 1.320 + 1.321 +function resetBlocklist(aCallback) { 1.322 + // XXX - this has "forked" from the head.js helpers in our parent directory :( 1.323 + // But let's reuse their blockNoPlugins.xml. Later, we should arrange to 1.324 + // use their head.js helpers directly 1.325 + let noBlockedURL = "http://example.com/browser/browser/base/content/test/plugins/blockNoPlugins.xml"; 1.326 + setAndUpdateBlocklist(noBlockedURL, function() { 1.327 + Services.prefs.setCharPref("extensions.blocklist.url", _originalTestBlocklistURL); 1.328 + if (aCallback) 1.329 + aCallback(); 1.330 + }); 1.331 +} 1.332 + 1.333 +function setManifestPref(name, manifest) { 1.334 + let string = Cc["@mozilla.org/supports-string;1"]. 1.335 + createInstance(Ci.nsISupportsString); 1.336 + string.data = JSON.stringify(manifest); 1.337 + Services.prefs.setComplexValue(name, Ci.nsISupportsString, string); 1.338 +} 1.339 + 1.340 +function getManifestPrefname(aManifest) { 1.341 + // is same as the generated name in SocialServiceInternal.getManifestPrefname 1.342 + let originUri = Services.io.newURI(aManifest.origin, null, null); 1.343 + return "social.manifest." + originUri.hostPort.replace('.','-'); 1.344 +} 1.345 + 1.346 +function setBuiltinManifestPref(name, manifest) { 1.347 + // we set this as a default pref, it must not be a user pref 1.348 + manifest.builtin = true; 1.349 + let string = Cc["@mozilla.org/supports-string;1"]. 1.350 + createInstance(Ci.nsISupportsString); 1.351 + string.data = JSON.stringify(manifest); 1.352 + Services.prefs.getDefaultBranch(null).setComplexValue(name, Ci.nsISupportsString, string); 1.353 + // verify this is set on the default branch 1.354 + let stored = Services.prefs.getComplexValue(name, Ci.nsISupportsString).data; 1.355 + is(stored, string.data, "manifest '"+name+"' stored in default prefs"); 1.356 + // don't dirty our manifest, we'll need it without this flag later 1.357 + delete manifest.builtin; 1.358 + // verify we DO NOT have a user-level pref 1.359 + ok(!Services.prefs.prefHasUserValue(name), "manifest '"+name+"' is not in user-prefs"); 1.360 +} 1.361 + 1.362 +function resetBuiltinManifestPref(name) { 1.363 + Services.prefs.getDefaultBranch(null).deleteBranch(name); 1.364 + is(Services.prefs.getDefaultBranch(null).getPrefType(name), 1.365 + Services.prefs.PREF_INVALID, "default manifest removed"); 1.366 +} 1.367 + 1.368 +function addTab(url, callback) { 1.369 + let tab = gBrowser.selectedTab = gBrowser.addTab(url, {skipAnimation: true}); 1.370 + tab.linkedBrowser.addEventListener("load", function tabLoad(event) { 1.371 + tab.linkedBrowser.removeEventListener("load", tabLoad, true); 1.372 + executeSoon(function() {callback(tab)}); 1.373 + }, true); 1.374 +} 1.375 + 1.376 +function selectBrowserTab(tab, callback) { 1.377 + if (gBrowser.selectedTab == tab) { 1.378 + executeSoon(function() {callback(tab)}); 1.379 + return; 1.380 + } 1.381 + gBrowser.tabContainer.addEventListener("TabSelect", function onTabSelect() { 1.382 + gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect, false); 1.383 + is(gBrowser.selectedTab, tab, "browser tab is selected"); 1.384 + executeSoon(function() {callback(tab)}); 1.385 + }); 1.386 + gBrowser.selectedTab = tab; 1.387 +} 1.388 + 1.389 +function loadIntoTab(tab, url, callback) { 1.390 + tab.linkedBrowser.addEventListener("load", function tabLoad(event) { 1.391 + tab.linkedBrowser.removeEventListener("load", tabLoad, true); 1.392 + executeSoon(function() {callback(tab)}); 1.393 + }, true); 1.394 + tab.linkedBrowser.loadURI(url); 1.395 +} 1.396 + 1.397 + 1.398 +// chat test help functions 1.399 + 1.400 +// And lots of helpers for the resize tests. 1.401 +function get3ChatsForCollapsing(mode, cb) { 1.402 + // We make one chat, then measure its size. We then resize the browser to 1.403 + // ensure a second can be created fully visible but a third can not - then 1.404 + // create the other 2. first will will be collapsed, second fully visible 1.405 + // and the third also visible and the "selected" one. 1.406 + // To make our life easier we don't go via the worker and ports so we get 1.407 + // more control over creation *and* to make the code much simpler. We 1.408 + // assume the worker/port stuff is individually tested above. 1.409 + let chatbar = window.SocialChatBar.chatbar; 1.410 + let chatWidth = undefined; 1.411 + let num = 0; 1.412 + is(chatbar.childNodes.length, 0, "chatbar starting empty"); 1.413 + is(chatbar.menupopup.childNodes.length, 0, "popup starting empty"); 1.414 + 1.415 + makeChat(mode, "first chat", function() { 1.416 + // got the first one. 1.417 + checkPopup(); 1.418 + ok(chatbar.menupopup.parentNode.collapsed, "menu selection isn't visible"); 1.419 + // we kinda cheat here and get the width of the first chat, assuming 1.420 + // that all future chats will have the same width when open. 1.421 + chatWidth = chatbar.calcTotalWidthOf(chatbar.selectedChat); 1.422 + let desired = chatWidth * 2.5; 1.423 + resizeWindowToChatAreaWidth(desired, function(sizedOk) { 1.424 + ok(sizedOk, "can't do any tests without this width"); 1.425 + checkPopup(); 1.426 + makeChat(mode, "second chat", function() { 1.427 + is(chatbar.childNodes.length, 2, "now have 2 chats"); 1.428 + checkPopup(); 1.429 + // and create the third. 1.430 + makeChat(mode, "third chat", function() { 1.431 + is(chatbar.childNodes.length, 3, "now have 3 chats"); 1.432 + checkPopup(); 1.433 + // XXX - this is a hacky implementation detail around the order of 1.434 + // the chats. Ideally things would be a little more sane wrt the 1.435 + // other in which the children were created. 1.436 + let second = chatbar.childNodes[2]; 1.437 + let first = chatbar.childNodes[1]; 1.438 + let third = chatbar.childNodes[0]; 1.439 + ok(first.collapsed && !second.collapsed && !third.collapsed, "collapsed state as promised"); 1.440 + is(chatbar.selectedChat, third, "third is selected as promised") 1.441 + info("have 3 chats for collapse testing - starting actual test..."); 1.442 + cb(first, second, third); 1.443 + }, mode); 1.444 + }, mode); 1.445 + }); 1.446 + }, mode); 1.447 +} 1.448 + 1.449 +function makeChat(mode, uniqueid, cb) { 1.450 + info("making a chat window '" + uniqueid +"'"); 1.451 + let provider = SocialSidebar.provider; 1.452 + const chatUrl = provider.origin + "/browser/browser/base/content/test/social/social_chat.html"; 1.453 + let isOpened = window.SocialChatBar.openChat(provider, chatUrl + "?id=" + uniqueid, function(chat) { 1.454 + info("chat window has opened"); 1.455 + // we can't callback immediately or we might close the chat during 1.456 + // this event which upsets the implementation - it is only 1/2 way through 1.457 + // handling the load event. 1.458 + chat.document.title = uniqueid; 1.459 + executeSoon(cb); 1.460 + }, mode); 1.461 + if (!isOpened) { 1.462 + ok(false, "unable to open chat window, no provider? more failures to come"); 1.463 + executeSoon(cb); 1.464 + } 1.465 +} 1.466 + 1.467 +function checkPopup() { 1.468 + // popup only showing if any collapsed popup children. 1.469 + let chatbar = window.SocialChatBar.chatbar; 1.470 + let numCollapsed = 0; 1.471 + for (let chat of chatbar.childNodes) { 1.472 + if (chat.collapsed) { 1.473 + numCollapsed += 1; 1.474 + // and it have a menuitem weakmap 1.475 + is(chatbar.menuitemMap.get(chat).nodeName, "menuitem", "collapsed chat has a menu item"); 1.476 + } else { 1.477 + ok(!chatbar.menuitemMap.has(chat), "open chat has no menu item"); 1.478 + } 1.479 + } 1.480 + is(chatbar.menupopup.parentNode.collapsed, numCollapsed == 0, "popup matches child collapsed state"); 1.481 + is(chatbar.menupopup.childNodes.length, numCollapsed, "popup has correct count of children"); 1.482 + // todo - check each individual elt is what we expect? 1.483 +} 1.484 +// Resize the main window so the chat area's boxObject is |desired| wide. 1.485 +// Does a callback passing |true| if the window is now big enough or false 1.486 +// if we couldn't resize large enough to satisfy the test requirement. 1.487 +function resizeWindowToChatAreaWidth(desired, cb, count = 0) { 1.488 + let current = window.SocialChatBar.chatbar.getBoundingClientRect().width; 1.489 + let delta = desired - current; 1.490 + info(count + ": resizing window so chat area is " + desired + " wide, currently it is " 1.491 + + current + ". Screen avail is " + window.screen.availWidth 1.492 + + ", current outer width is " + window.outerWidth); 1.493 + 1.494 + // WTF? Sometimes we will get fractional values due to the - err - magic 1.495 + // of DevPointsPerCSSPixel etc, so we allow a couple of pixels difference. 1.496 + let widthDeltaCloseEnough = function(d) { 1.497 + return Math.abs(d) < 2; 1.498 + } 1.499 + 1.500 + // attempting to resize by (0,0), unsurprisingly, doesn't cause a resize 1.501 + // event - so just callback saying all is well. 1.502 + if (widthDeltaCloseEnough(delta)) { 1.503 + info(count + ": skipping this as screen width is close enough"); 1.504 + executeSoon(function() { 1.505 + cb(true); 1.506 + }); 1.507 + return; 1.508 + } 1.509 + // On lo-res screens we may already be maxed out but still smaller than the 1.510 + // requested size, so asking to resize up also will not cause a resize event. 1.511 + // So just callback now saying the test must be skipped. 1.512 + if (window.screen.availWidth - window.outerWidth < delta) { 1.513 + info(count + ": skipping this as screen available width is less than necessary"); 1.514 + executeSoon(function() { 1.515 + cb(false); 1.516 + }); 1.517 + return; 1.518 + } 1.519 + function resize_handler(event) { 1.520 + // we did resize - but did we get far enough to be able to continue? 1.521 + let newSize = window.SocialChatBar.chatbar.getBoundingClientRect().width; 1.522 + let sizedOk = widthDeltaCloseEnough(newSize - desired); 1.523 + if (!sizedOk) 1.524 + return; 1.525 + window.removeEventListener("resize", resize_handler, true); 1.526 + info(count + ": resized window width is " + newSize); 1.527 + executeSoon(function() { 1.528 + cb(sizedOk); 1.529 + }); 1.530 + } 1.531 + // Otherwise we request resize and expect a resize event 1.532 + window.addEventListener("resize", resize_handler, true); 1.533 + window.resizeBy(delta, 0); 1.534 +} 1.535 + 1.536 +function resizeAndCheckWidths(first, second, third, checks, cb) { 1.537 + if (checks.length == 0) { 1.538 + cb(); // nothing more to check! 1.539 + return; 1.540 + } 1.541 + let count = checks.length; 1.542 + let [width, numExpectedVisible, why] = checks.shift(); 1.543 + info("<< Check " + count + ": " + why); 1.544 + info(count + ": " + "resizing window to " + width + ", expect " + numExpectedVisible + " visible items"); 1.545 + resizeWindowToChatAreaWidth(width, function(sizedOk) { 1.546 + checkPopup(); 1.547 + ok(sizedOk, count+": window resized correctly"); 1.548 + function collapsedObserver(r, m) { 1.549 + if ([first, second, third].filter(function(item) !item.collapsed).length == numExpectedVisible) { 1.550 + if (m) { 1.551 + m.disconnect(); 1.552 + } 1.553 + ok(true, count + ": " + "correct number of chats visible"); 1.554 + info(">> Check " + count); 1.555 + executeSoon(function() { 1.556 + resizeAndCheckWidths(first, second, third, checks, cb); 1.557 + }); 1.558 + } 1.559 + } 1.560 + let m = new MutationObserver(collapsedObserver); 1.561 + m.observe(first, {attributes: true }); 1.562 + m.observe(second, {attributes: true }); 1.563 + m.observe(third, {attributes: true }); 1.564 + // and just in case we are already at the right size, explicitly call the 1.565 + // observer. 1.566 + collapsedObserver(undefined, m); 1.567 + }, count); 1.568 +} 1.569 + 1.570 +function getPopupWidth() { 1.571 + let popup = window.SocialChatBar.chatbar.menupopup; 1.572 + ok(!popup.parentNode.collapsed, "asking for popup width when it is visible"); 1.573 + let cs = document.defaultView.getComputedStyle(popup.parentNode); 1.574 + let margins = parseInt(cs.marginLeft) + parseInt(cs.marginRight); 1.575 + return popup.parentNode.getBoundingClientRect().width + margins; 1.576 +} 1.577 + 1.578 +function closeAllChats() { 1.579 + let chatbar = window.SocialChatBar.chatbar; 1.580 + chatbar.removeAll(); 1.581 +}