diff --git a/addon-sdk/source/test/test-sandbox.js b/addon-sdk/source/test/test-sandbox.js index 5ef281c9b5d..8592e9fbcb4 100644 --- a/addon-sdk/source/test/test-sandbox.js +++ b/addon-sdk/source/test/test-sandbox.js @@ -117,6 +117,8 @@ exports['test load script with data: URL and complex char'] = function(assert) { }; exports['test metadata'] = function(assert) { + let self = require('sdk/self'); + let dbg = new Debugger(); dbg.onNewGlobalObject = function(global) { let metadata = Cu.getSandboxMetadata(global.unsafeDereference()); @@ -127,7 +129,7 @@ exports['test metadata'] = function(assert) { } let fixture = sandbox(); - let self = require('sdk/self'); + assert.equal(dbg.onNewGlobalObject, undefined, 'Should have reset the handler'); } exports['test nuke sandbox'] = function(assert) { diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index fca1dc32c22..cab76273249 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index e904f8d1d70..377fd4b03d2 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index c015505fdac..7e0a8ec8a86 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -1,39 +1,48 @@ - - - - + + + + + + - - - + + + + - - - - - + + + + - + + + + + + + + + - - + @@ -42,8 +51,6 @@ - - @@ -53,6 +60,7 @@ + @@ -62,11 +70,9 @@ - - @@ -81,9 +87,8 @@ - - + @@ -91,21 +96,17 @@ + + + + - - + - - - - - - - diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 5dd2a854d7b..801fb2f5702 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,10 +17,10 @@ - + - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index ac880817d22..a0d798e5aab 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index 9ae39f57799..4934635d19e 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index c015505fdac..7e0a8ec8a86 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -1,39 +1,48 @@ - - - - + + + + + + - - - + + + + - - - - - + + + + - + + + + + + + + + - - + @@ -42,8 +51,6 @@ - - @@ -53,6 +60,7 @@ + @@ -62,11 +70,9 @@ - - @@ -81,9 +87,8 @@ - - + @@ -91,21 +96,17 @@ + + + + - - + - - - - - - - diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index b6f2a22dbfb..39f8b7948eb 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 6e4912fe9d9..4759b67043f 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "ea673b5c4cc19c3daca072691a659c68e4c6937f", + "git_revision": "37250b125e0db6966875d3b37b117f6d9b76cbc0", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "f5fc1ed93387c0ff18811fb306e061b8ca77bd40", + "revision": "e094d698a05cd04c90815dd11579326f43f02a6b", "repo_path": "integration/gaia-central" } diff --git a/b2g/config/nexus-4-kk/sources.xml b/b2g/config/nexus-4-kk/sources.xml index 6b3cfe596fe..c0aeb646672 100644 --- a/b2g/config/nexus-4-kk/sources.xml +++ b/b2g/config/nexus-4-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 446c1f6d0b3..f92c433565b 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -18,10 +18,10 @@ - + - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 7f769a41885..85ab233b07e 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + @@ -24,7 +24,7 @@ - + diff --git a/b2g/graphene/confvars.sh b/b2g/graphene/confvars.sh index 2ddc199c518..8a557d3c03b 100644 --- a/b2g/graphene/confvars.sh +++ b/b2g/graphene/confvars.sh @@ -63,3 +63,6 @@ MOZ_JSDOWNLOADS=1 MOZ_BUNDLED_FONTS=1 export JS_GC_SMALL_CHUNK_SIZE=1 + +# Include the DevTools client, not just the server (which is the default) +MOZ_DEVTOOLS=all diff --git a/b2g/graphene/graphene.js b/b2g/graphene/graphene.js index 796e2dddda9..45d8e62ab0e 100644 --- a/b2g/graphene/graphene.js +++ b/b2g/graphene/graphene.js @@ -53,3 +53,10 @@ pref("media.useAudioChannelService", false); #ifdef ENABLE_MARIONETTE pref("b2g.is_mulet", true); #endif + +// Most DevTools prefs are set from the shared file +// devtools/client/preferences/devtools.js, but this one is currently set +// per-app or per-channel. +// Number of usages of the web console or scratchpad. If this is less than 5, +// then pasting code into the web console or scratchpad is disabled +pref("devtools.selfxss.count", 5); diff --git a/b2g/installer/flash.bat b/b2g/installer/flash.bat new file mode 100755 index 00000000000..9b5093677de --- /dev/null +++ b/b2g/installer/flash.bat @@ -0,0 +1,73 @@ +@ECHO OFF + +REM read config file +setlocal ENABLEDELAYEDEXPANSION +set loop=0 +for /F "tokens=*" %%A in (.config) do ( + SET /A loop=!loop! + 1 + set %%A +) + +set DEVICE_FOUND=0 + +REM nexus has device instead of product name +IF [%PRODUCT_NAME%]==[] ( + set PRODUCT_NAME=%DEVICE% +) + +REM if nexus 4 assume you are in fastboot mode, can't seem to find drivers +IF [%DEVICE%]==[mako] ( +call :flash +) + +REM push device from adb to fastboot mode +win_adb kill-server +win_adb devices +win_adb get-state > devicestate.txt +set /p DEVICE_STATE= < devicestate.txt + +IF NOT "%DEVICE_STATE%"=="device" ( + ECHO Please check : + ECHO 1. to make sure that only one device is connected to the computer + ECHO 2. the device is turned on with the screen showing + ECHO 3. the device is set to debugging via USB : ADB Only or ADB and Devtools + ECHO 4. the device drivers are installed on the computer. + Del devicestate.txt + PAUSE + EXIT /b +) + +Del devicestate.txt +win_adb reboot bootloader + +TIMEOUT 5 + +:flash +win_fastboot devices 2> fastboot_state.txt +set /p FASTBOOT_STATE= < fastboot_state.txt + +IF NOT [%FASTBOOT_STATE%]==[] ( + ECHO Please check : + ECHO 1. to make sure that only one device is connected to the computer + ECHO 2. the device is turned on with an indication that the device is in fastboot mode + ECHO 3. the fastboot drivers are installed on the computer. + Del fastboot_state.txt + PAUSE + EXIT /b +) + +Del fastboot_state.txt + +ECHO "Flashing build. If nothing mentions that it flashed anything and it looks stuck, make sure you have the drivers installed." +win_fastboot flash boot out/target/product/%PRODUCT_NAME%/boot.img +win_fastboot flash system out/target/product/%PRODUCT_NAME%/system.img +win_fastboot flash persist out/target/product/%PRODUCT_NAME%/persist.img +win_fastboot flash recovery out/target/product/%PRODUCT_NAME%/recovery.img +win_fastboot flash cache out/target/product/%PRODUCT_NAME%/cache.img +win_fastboot flash userdata out/target/product/%PRODUCT_NAME%/userdata.img + +ECHO "Done..." + +win_fastboot reboot +echo "Just close the windows as you wish." +TIMEOUT 5 diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 39801b6206f..f7cbaa88cdf 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -748,6 +748,9 @@ ; DevTools @RESPATH@/chrome/devtools@JAREXT@ @RESPATH@/chrome/devtools.manifest +#ifdef MOZ_GRAPHENE +@RESPATH@/@PREF_DIR@/devtools.js +#endif ; shell icons #ifdef XP_UNIX diff --git a/browser/base/content/browser-loop.js b/browser/base/content/browser-loop.js index 713cd6ad0cc..4f834577633 100644 --- a/browser/base/content/browser-loop.js +++ b/browser/base/content/browser-loop.js @@ -171,11 +171,14 @@ var LoopUI; this.LoopAPI.initialize(); let anchor = event ? event.target : this.toolbarButton.anchor; - + let setHeight = 410; + if (gBrowser.selectedBrowser.getAttribute("remote") === "true") { + setHeight = 262; + } this.PanelFrame.showPopup(window, anchor, "loop", null, "about:looppanel", // Loop wants a fixed size for the panel. This also stops it dynamically resizing. - { width: 330, height: 410 }, + { width: 330, height: setHeight }, callback); }); }); @@ -290,6 +293,7 @@ var LoopUI; } else if (aReason == "login" && this.MozLoopService.userProfile) { state = "active"; mozL10nId += "-active"; + suffix += "2"; } else if (this.MozLoopService.doNotDisturb) { state = "disabled"; mozL10nId += "-donotdisturb"; @@ -302,11 +306,15 @@ var LoopUI; mozL10nId += "-active"; } + suffix += "2"; this.updateTooltiptext(mozL10nId + suffix); this.toolbarButton.node.setAttribute("state", state); }); return; + } else { + suffix += "2"; } + this.toolbarButton.node.setAttribute("state", state); this.updateTooltiptext(mozL10nId + suffix); }, diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css index d1198eeecbf..58b764277e9 100644 --- a/browser/base/content/browser.css +++ b/browser/base/content/browser.css @@ -667,6 +667,7 @@ html|*#fullscreen-warning { } html|*#fullscreen-warning:not([hidden]) { display: flex; + will-change: transform; } html|*#fullscreen-warning[onscreen] { transform: translate(-50%, 50px); diff --git a/browser/base/content/content.js b/browser/base/content/content.js index 1956aa0455a..c53f66ba6bd 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -518,9 +518,10 @@ var ClickEventHandler = { while (node && !href) { if (node.nodeType == content.Node.ELEMENT_NODE) { href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href"); - if (href) + if (href) { baseURI = node.ownerDocument.baseURIObject; - break; + break; + } } node = node.parentNode; } diff --git a/browser/base/content/test/alerts/browser.ini b/browser/base/content/test/alerts/browser.ini index a7c4d1e1f3a..1ebf36ef598 100644 --- a/browser/base/content/test/alerts/browser.ini +++ b/browser/base/content/test/alerts/browser.ini @@ -8,6 +8,5 @@ support-files = [browser_notification_open_settings.js] [browser_notification_remove_permission.js] [browser_notification_permission_migration.js] - [browser_notification_tab_switching.js] -skip-if = buildapp == 'mulet' || e10s # Bug 1100662 - content access causing uncaught exception - Error: cannot ipc non-cpow object at chrome://mochitests/content/browser/browser/base/content/test/general/browser_notification_tab_switching.js:32 (or in RemoteAddonsChild.jsm) +skip-if = buildapp == 'mulet' diff --git a/browser/base/content/test/alerts/browser_notification_close.js b/browser/base/content/test/alerts/browser_notification_close.js index 053c32f29f6..82e1f314fac 100644 --- a/browser/base/content/test/alerts/browser_notification_close.js +++ b/browser/base/content/test/alerts/browser_notification_close.js @@ -25,6 +25,11 @@ add_task(function* test_notificationClose() { return; } + let alertTitleLabel = alertWindow.document.getElementById("alertTitleLabel"); + is(alertTitleLabel.value, "Test title", "Title text of notification should be present"); + let alertTextLabel = alertWindow.document.getElementById("alertTextLabel"); + is(alertTextLabel.textContent, "Test body", "Body text of notification should be present"); + let alertCloseButton = alertWindow.document.querySelector(".alertCloseButton"); is(alertCloseButton.localName, "toolbarbutton", "close button found"); let promiseBeforeUnloadEvent = diff --git a/browser/base/content/test/alerts/browser_notification_tab_switching.js b/browser/base/content/test/alerts/browser_notification_tab_switching.js index 781cd081198..5e0a6925e7e 100644 --- a/browser/base/content/test/alerts/browser_notification_tab_switching.js +++ b/browser/base/content/test/alerts/browser_notification_tab_switching.js @@ -9,87 +9,57 @@ var notification; var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html"; var newWindowOpenedFromTab; -function test () { - waitForExplicitFinish(); - +add_task(function* test_notificationPreventDefaultAndSwitchTabs() { let pm = Services.perms; - registerCleanupFunction(function() { - pm.remove(makeURI(notificationURL), "desktop-notification"); - gBrowser.removeTab(tab); - window.restore(); - }); - pm.add(makeURI(notificationURL), "desktop-notification", pm.ALLOW_ACTION); - tab = gBrowser.addTab(notificationURL); - tab.linkedBrowser.addEventListener("load", onLoad, true); -} + let originalTab = gBrowser.selectedTab; + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: notificationURL + }, function* dummyTabTask(aBrowser) { + // Put new tab in background so it is obvious when it is re-focused. + yield BrowserTestUtils.switchTab(gBrowser, originalTab); + isnot(gBrowser.selectedBrowser, aBrowser, "Notification page loaded as a background tab"); -function onLoad() { - isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); - tab.linkedBrowser.removeEventListener("load", onLoad, true); - let win = tab.linkedBrowser.contentWindow.wrappedJSObject; - win.newWindow = win.open("about:blank", "", "height=100,width=100"); - newWindowOpenedFromTab = win.newWindow; - win.newWindow.addEventListener("load", function() { - info("new window loaded"); - win.newWindow.addEventListener("blur", function b() { - info("new window got blur"); - win.newWindow.removeEventListener("blur", b); - notification = win.showNotification1(); - win.newWindow.addEventListener("focus", onNewWindowFocused); - notification.addEventListener("show", onAlertShowing); - }); - - function waitUntilNewWindowHasFocus() { - if (!win.newWindow.document.hasFocus()) { - setTimeout(waitUntilNewWindowHasFocus, 50); - } else { - // Focus another window so that new window gets blur event. - gBrowser.selectedBrowser.contentWindow.focus(); - } + // First, show a notification that will be have the tab-switching prevented. + let win = aBrowser.contentWindow.wrappedJSObject; + let notification = win.showNotification1(); + yield BrowserTestUtils.waitForEvent(notification, "show"); + info("Notification alert showing"); + let alertWindow = Services.wm.getMostRecentWindow("alert:alert"); + if (!alertWindow) { + ok(true, "Notifications don't use XUL windows on all platforms."); + notification.close(); + return; } - win.newWindow.focus(); - waitUntilNewWindowHasFocus(); - }); -} - -function onAlertShowing() { - info("Notification alert showing"); - notification.removeEventListener("show", onAlertShowing); - - let alertWindow = Services.wm.getMostRecentWindow("alert:alert"); - if (!alertWindow) { - ok(true, "Notifications don't use XUL windows on all platforms."); + info("Clicking on notification"); + let promiseClickEvent = BrowserTestUtils.waitForEvent(notification, "click"); + EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), + {}, + alertWindow); + let clickEvent = yield promiseClickEvent; + ok(clickEvent.defaultPrevented, "The event handler for the first notification cancels the event"); + isnot(gBrowser.selectedBrowser, aBrowser, "Notification page still a background tab"); notification.close(); - newWindowOpenedFromTab.close(); - finish(); - return; - } - gBrowser.tabContainer.addEventListener("TabSelect", onTabSelect); - EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), {}, alertWindow); - info("Clicked on notification"); - alertWindow.close(); -} + yield BrowserTestUtils.waitForEvent(notification, "close"); -function onNewWindowFocused(event) { - event.target.close(); - isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); - // Using timeout to test that something do *not* happen! - setTimeout(openSecondNotification, 50); -} + // Second, show a notification that will cause the tab to get switched. + let notification2 = win.showNotification2(); + yield BrowserTestUtils.waitForEvent(notification2, "show"); + alertWindow = Services.wm.getMostRecentWindow("alert:alert"); + let promiseTabSelect = BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabSelect"); + EventUtils.synthesizeMouseAtCenter(alertWindow.document.getElementById("alertTitleLabel"), + {}, + alertWindow); + yield promiseTabSelect; + is(gBrowser.selectedBrowser.currentURI.spec, notificationURL, + "Clicking on the second notification should select its originating tab"); + notification2.close(); + yield BrowserTestUtils.waitForEvent(notification2, "close"); + }); +}); -function openSecondNotification() { - isnot(gBrowser.selectedTab, tab, "Notification page loaded as a background tab"); - let win = tab.linkedBrowser.contentWindow.wrappedJSObject; - notification = win.showNotification2(); - notification.addEventListener("show", onAlertShowing); -} - -function onTabSelect() { - gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect); - is(gBrowser.selectedBrowser.contentWindow.location.href, notificationURL, - "Notification tab should be selected."); - - finish(); -} +add_task(function* cleanup() { + Services.perms.remove(makeURI(notificationURL), "desktop-notification"); +}); diff --git a/browser/base/content/test/alerts/file_dom_notifications.html b/browser/base/content/test/alerts/file_dom_notifications.html index 7cbdebdd48e..8f5c6f2fd57 100644 --- a/browser/base/content/test/alerts/file_dom_notifications.html +++ b/browser/base/content/test/alerts/file_dom_notifications.html @@ -15,8 +15,6 @@ function showNotification1() { var n = new Notification("Test title", options); n.addEventListener("click", function(event) { event.preventDefault(); - dump("Should focus new window."); - newWindow.focus(); }); return n; } diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm index 3c0fe81e286..0c030d741aa 100644 --- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -956,7 +956,7 @@ const CustomizableWidgets = [ id: "loop-button", type: "custom", label: "loop-call-button3.label", - tooltiptext: "loop-call-button3.tooltiptext", + tooltiptext: "loop-call-button3.tooltiptext2", privateBrowsingTooltiptext: "loop-call-button3-pb.tooltiptext", defaultArea: CustomizableUI.AREA_NAVBAR, introducedInVersion: 4, diff --git a/browser/components/extensions/test/browser/browser.ini b/browser/components/extensions/test/browser/browser.ini index 38a9b5d5fba..b04e6f6c1a4 100644 --- a/browser/components/extensions/test/browser/browser.ini +++ b/browser/components/extensions/test/browser/browser.ini @@ -5,6 +5,8 @@ support-files = ctxmenu-image.png context_tabs_onUpdated_page.html context_tabs_onUpdated_iframe.html + file_popup_api_injection_a.html + file_popup_api_injection_b.html [browser_ext_simple.js] [browser_ext_currentWindow.js] @@ -15,6 +17,7 @@ support-files = [browser_ext_pageAction_context.js] [browser_ext_pageAction_popup.js] [browser_ext_browserAction_popup.js] +[browser_ext_popup_api_injection.js] [browser_ext_contextMenus.js] [browser_ext_getViews.js] [browser_ext_tabs_executeScript.js] diff --git a/browser/components/extensions/test/browser/browser_ext_popup_api_injection.js b/browser/components/extensions/test/browser/browser_ext_popup_api_injection.js new file mode 100644 index 00000000000..314d53ec09c --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_popup_api_injection.js @@ -0,0 +1,106 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +"use strict"; + +add_task(function* testPageActionPopup() { + const BASE = "http://example.com/browser/browser/components/extensions/test/browser"; + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + "browser_action": { + "default_popup": `${BASE}/file_popup_api_injection_a.html`, + }, + "page_action": { + "default_popup": `${BASE}/file_popup_api_injection_b.html`, + }, + }, + + files: { + "popup-a.html": String.raw``, + + "popup-b.html": String.raw``, + }, + + background: function() { + let tabId + browser.tabs.query({ active: true, currentWindow: true }, tabs => { + tabId = tabs[0].id; + browser.pageAction.show(tabId); + browser.test.sendMessage("ready"); + }); + + browser.test.onMessage.addListener(() => { + browser.browserAction.setPopup({ popup: "/popup-a.html" }); + browser.pageAction.setPopup({ tabId, popup: "popup-b.html" }); + + browser.test.sendMessage("ok"); + }); + }, + }); + + let browserActionId = makeWidgetId(extension.id) + "-browser-action"; + let pageActionId = makeWidgetId(extension.id) + "-page-action"; + + function openPopup(buttonId) { + let button = document.getElementById(buttonId); + if (buttonId == pageActionId) { + // TODO: I don't know why a proper synthesized event doesn't work here. + button.dispatchEvent(new MouseEvent("click", {})); + } else { + EventUtils.synthesizeMouseAtCenter(button, {}, window); + } + }; + + let promiseConsoleMessage = pattern => new Promise(resolve => { + Services.console.registerListener(function listener(msg) { + if (pattern.test(msg.message)) { + resolve(msg.message); + Services.console.unregisterListener(listener); + } + }); + }); + + yield extension.startup(); + yield extension.awaitMessage("ready"); + + + // Check that unprivileged documents don't get the API. + // BrowserAction: + let awaitMessage = promiseConsoleMessage(/WebExt Privilege Escalation: BrowserAction/); + SimpleTest.expectUncaughtException(); + openPopup(browserActionId); + + let message = yield awaitMessage; + ok(message.includes("WebExt Privilege Escalation: BrowserAction: typeof(browser) = undefined"), + `No BrowserAction API injection`); + + // PageAction + awaitMessage = promiseConsoleMessage(/WebExt Privilege Escalation: PageAction/); + SimpleTest.expectUncaughtException(); + openPopup(pageActionId); + + message = yield awaitMessage; + ok(message.includes("WebExt Privilege Escalation: PageAction: typeof(browser) = undefined"), + `No PageAction API injection: ${message}`); + + SimpleTest.expectUncaughtException(false); + + + // Check that privileged documents *do* get the API. + extension.sendMessage("next"); + yield extension.awaitMessage("ok"); + + + // Check that unprivileged documents don't get the API. + openPopup(browserActionId); + yield extension.awaitMessage("from-popup-a"); + + openPopup(pageActionId); + yield extension.awaitMessage("from-popup-b"); + + yield extension.unload(); +}); diff --git a/browser/components/extensions/test/browser/file_popup_api_injection_a.html b/browser/components/extensions/test/browser/file_popup_api_injection_a.html new file mode 100644 index 00000000000..dd1632da875 --- /dev/null +++ b/browser/components/extensions/test/browser/file_popup_api_injection_a.html @@ -0,0 +1,9 @@ + + + + + + + diff --git a/browser/components/extensions/test/browser/file_popup_api_injection_b.html b/browser/components/extensions/test/browser/file_popup_api_injection_b.html new file mode 100644 index 00000000000..24d749220e0 --- /dev/null +++ b/browser/components/extensions/test/browser/file_popup_api_injection_b.html @@ -0,0 +1,9 @@ + + + + + + + diff --git a/browser/components/loop/content/css/panel.css b/browser/components/loop/content/css/panel.css index eb7bec62c0c..374d8654302 100644 --- a/browser/components/loop/content/css/panel.css +++ b/browser/components/loop/content/css/panel.css @@ -716,3 +716,49 @@ html[dir="rtl"] .settings-menu .dropdown-menu { background-color: #5cccee; color: #fff; } + +/* E10s not supported */ + +.error-content { + /* Manual vertical centering */ + flex: 1; + padding: 3.5rem 0 1.5rem 0; + display: flex; + flex-direction: column; +} + +.error-title { + margin: 0 15px; + text-align: center; +} + +.error-title > img { + width: 72px; +} + +.error-subheader { + text-align: center; + font-size: 1.6rem; + margin: 2.5rem 0; + color: #4a4a4a; + line-height: 2.2rem; +} + +.e10s-not-supported-button { + border: none; + color: #fff; + background-color: #00a9dc; + line-height: 43px; + margin: 0 15px; + padding: 0; + border-radius: 4px; + font-size: 1.4rem; + font-weight: bold; +} + +.e10s-not-supported-button:hover, +.e10s-not-supported-button:focus, +.e10s-not-supported-button:active { + background-color: #5cccee; + color: #fff; +} diff --git a/browser/components/loop/content/js/panel.js b/browser/components/loop/content/js/panel.js index 42d9e13058a..395806d7ae4 100644 --- a/browser/components/loop/content/js/panel.js +++ b/browser/components/loop/content/js/panel.js @@ -863,6 +863,33 @@ loop.panel = (function(_, mozL10n) { } }); + /** + * E10s not supported view + */ + var E10sNotSupported = React.createClass({displayName: "E10sNotSupported", + propTypes: { + onClick: React.PropTypes.func.isRequired + }, + + render: function() { + return ( + React.createElement("div", {className: "error-content"}, + React.createElement("header", {className: "error-title"}, + React.createElement("img", {src: "loop/shared/img/sad_hello_icon_64x64.svg"}), + React.createElement("p", {className: "error-subheader"}, + mozL10n.get("e10s_not_supported_subheading", { + brandShortname: mozL10n.get("clientShortname2") + }) + ) + ), + React.createElement(Button, {additionalClass: "e10s-not-supported-button", + caption: mozL10n.get("e10s_not_supported_button_label"), + onClick: this.props.onClick}) + ) + ); + } + }); + /** * Panel view. */ @@ -889,7 +916,8 @@ loop.panel = (function(_, mozL10n) { fxAEnabled: true, hasEncryptionKey: false, userProfile: null, - gettingStartedSeen: true + gettingStartedSeen: true, + multiProcessEnabled: false }; }, @@ -961,13 +989,15 @@ loop.panel = (function(_, mozL10n) { ["GetFxAEnabled"], ["GetHasEncryptionKey"], ["GetUserProfile"], - ["GetLoopPref", "gettingStarted.seen"] + ["GetLoopPref", "gettingStarted.seen"], + ["IsMultiProcessEnabled"] ).then(function(results) { this.setState({ fxAEnabled: results[0], hasEncryptionKey: results[1], userProfile: results[2], - gettingStartedSeen: results[3] + gettingStartedSeen: results[3], + multiProcessEnabled: results[4] }); }.bind(this)); }, @@ -986,9 +1016,21 @@ loop.panel = (function(_, mozL10n) { e.preventDefault(); }, + launchNonE10sWindow: function(e) { + loop.request("GetSelectedTabMetadata").then(function(metadata) { + loop.request("OpenNonE10sWindow", metadata.url); + }); + }, + render: function() { var NotificationListView = sharedViews.NotificationListView; + if (this.state.multiProcessEnabled) { + return ( + React.createElement(E10sNotSupported, {onClick: this.launchNonE10sWindow}) + ); + } + if (!this.props.gettingStartedSeen || !this.state.gettingStartedSeen) { return ( React.createElement("div", {className: "fte-get-started-container", @@ -1084,6 +1126,7 @@ loop.panel = (function(_, mozL10n) { return { AccountLink: AccountLink, ConversationDropdown: ConversationDropdown, + E10sNotSupported: E10sNotSupported, GettingStartedView: GettingStartedView, init: init, NewRoomView: NewRoomView, diff --git a/browser/components/loop/content/js/panel.jsx b/browser/components/loop/content/js/panel.jsx index 6acaf551f86..e7aa44b43fe 100644 --- a/browser/components/loop/content/js/panel.jsx +++ b/browser/components/loop/content/js/panel.jsx @@ -863,6 +863,33 @@ loop.panel = (function(_, mozL10n) { } }); + /** + * E10s not supported view + */ + var E10sNotSupported = React.createClass({ + propTypes: { + onClick: React.PropTypes.func.isRequired + }, + + render: function() { + return ( +
+
+ +

+ {mozL10n.get("e10s_not_supported_subheading", { + brandShortname: mozL10n.get("clientShortname2") + })} +

+
+
+ ); + } + }); + /** * Panel view. */ @@ -889,7 +916,8 @@ loop.panel = (function(_, mozL10n) { fxAEnabled: true, hasEncryptionKey: false, userProfile: null, - gettingStartedSeen: true + gettingStartedSeen: true, + multiProcessEnabled: false }; }, @@ -961,13 +989,15 @@ loop.panel = (function(_, mozL10n) { ["GetFxAEnabled"], ["GetHasEncryptionKey"], ["GetUserProfile"], - ["GetLoopPref", "gettingStarted.seen"] + ["GetLoopPref", "gettingStarted.seen"], + ["IsMultiProcessEnabled"] ).then(function(results) { this.setState({ fxAEnabled: results[0], hasEncryptionKey: results[1], userProfile: results[2], - gettingStartedSeen: results[3] + gettingStartedSeen: results[3], + multiProcessEnabled: results[4] }); }.bind(this)); }, @@ -986,9 +1016,21 @@ loop.panel = (function(_, mozL10n) { e.preventDefault(); }, + launchNonE10sWindow: function(e) { + loop.request("GetSelectedTabMetadata").then(function(metadata) { + loop.request("OpenNonE10sWindow", metadata.url); + }); + }, + render: function() { var NotificationListView = sharedViews.NotificationListView; + if (this.state.multiProcessEnabled) { + return ( + + ); + } + if (!this.props.gettingStartedSeen || !this.state.gettingStartedSeen) { return (
.dropdown-menu-item { height: calc(100% - 300px); } -.desktop-room-wrapper > .media-layout > .media-wrapper > .text-chat-view { - height: calc(100% - 150px); -} - -/* Temporarily slaved from .media-wrapper until we use it in more places - to avoid affecting the conversation window on desktop. */ -.media-wrapper > .text-chat-view > .text-chat-entries { - /* 40px is the height of .text-chat-box. */ - height: calc(100% - 40px); -} - -.media-wrapper > .text-chat-disabled > .text-chat-entries { - /* When text chat is disabled, the entries box should be 100% height. */ - height: 100%; -} - .media-wrapper.receiving-screen-share > .screen { order: 1; } @@ -754,19 +738,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { height: 50%; } - /* Temporarily slaved from .media-wrapper until we use it in more places - to avoid affecting the conversation window on desktop. */ - .text-chat-view > .text-chat-entries { - /* 40px is the height of .text-chat-box. */ - height: calc(100% - 40px); - width: 100%; - } - - .media-wrapper > .text-chat-disabled > .text-chat-entries { - /* When text chat is disabled, the entries box should be 100% height. */ - height: 100%; - } - .media-wrapper > .focus-stream > .local ~ .conversation-toolbar { /* 120px is for the local video area. */ max-width: calc(100% - 120px); @@ -790,13 +761,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { left: 0; } - - .standalone-room-wrapper > .media-layout > .media-wrapper > .local { - /* Add 10px for the margin on standalone */ - right: 10px; - } - - html[dir="rtl"] .media-wrapper > .local { right: auto; left: 0; @@ -812,7 +776,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { .media-wrapper.showing-local-streams > .text-chat-view, .media-wrapper.showing-local-streams.receiving-screen-share > .text-chat-view { /* The remaining 30% that the .focus-stream doesn't use. */ - height: 30%; + height: 45%; } .media-wrapper.receiving-screen-share > .remote > .conversation-toolbar, @@ -821,11 +785,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { } - .desktop-room-wrapper > .media-layout > .media-wrapper > .text-chat-view { - /* This is temp, to echo the .media-wrapper > .text-chat-view above */ - height: 45%; - } - .media-wrapper.receiving-screen-share > .screen { order: 1; } @@ -925,7 +884,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { height: 263px; } - .desktop-room-wrapper > .media-layout > .media-wrapper > .text-chat-view { + .media-wrapper > .text-chat-view { height: calc(100% - 263px); } } @@ -936,9 +895,17 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item { background: white; } -.text-chat-entries { +.text-chat-view > .text-chat-entries { + width: 100%; overflow: auto; padding-top: .6rem; + /* 40px is the height of .text-chat-box. */ + height: calc(100% - 40px); +} + +.text-chat-disabled > .text-chat-entries { + /* When text chat is disabled, the entries box should be 100% height. */ + height: 100%; } .text-chat-entry, @@ -1177,25 +1144,6 @@ html[dir="rtl"] .text-chat-entry.received .text-chat-arrow { border-top: 1px solid #66c9f2; } -@media screen and (max-width:640px) { - /* Rooms specific responsive styling */ - .standalone .room-conversation-wrapper .room-inner-info-area { - right: 0; - margin: auto; - width: 100%; - left: 0; - } - .standalone .room-conversation-wrapper .video-layout-wrapper { - height: 100%; - } - .standalone .room-conversation .video_wrapper.remote_wrapper { - width: 100%; - } - .standalone .room-conversation .video_wrapper.remote_wrapper.not-joined { - width: 100%; - } -} - /* e.g. very narrow widths similar to conversation window */ @media screen and (max-width:350px) { .text-chat-view { diff --git a/browser/components/loop/modules/MozLoopAPI.jsm b/browser/components/loop/modules/MozLoopAPI.jsm index ed178f29289..70638ee9fe3 100644 --- a/browser/components/loop/modules/MozLoopAPI.jsm +++ b/browser/components/loop/modules/MozLoopAPI.jsm @@ -129,6 +129,7 @@ var gPageListeners = null; var gOriginalPageListeners = null; var gSocialProviders = null; var gStringBundle = null; +var gStubbedMessageHandlers = null; const kBatchMessage = "Batch"; const kMaxLoopCount = 10; const kMessageName = "Loop:Message"; @@ -689,6 +690,22 @@ const kMessageHandlers = { MozLoopService.hangupAllChatWindows(); }, + /** + * Check if the current browser has e10s enabled or not + * + * @param {Object} message Message meant for the handler function, containing + * the following parameters in its `data` property: + * [] + * @param {Function} reply Callback function, invoked with the result of this + * message handler. The result will be sent back to + * the senders' channel. + */ + IsMultiProcessEnabled: function(message, reply) { + let win = Services.wm.getMostRecentWindow("navigator:browser"); + let browser = win && win.gBrowser.selectedBrowser; + reply(!!(browser && browser.getAttribute("remote") == "true")); + }, + /** * Start the FxA login flow using the OAuth client and params from the Loop * server. @@ -783,6 +800,22 @@ const kMessageHandlers = { reply(); }, + /** + * Opens a non e10s window + * + * @param {Object} message Message meant for the handler function, containing + * the following parameters in its `data` property: + * [url] + * @param {Function} reply Callback function, invoked with the result of this + * message handler. The result will be sent back to + * the senders' channel. + */ + OpenNonE10sWindow: function(message, reply) { + let win = Services.wm.getMostRecentWindow("navigator:browser"); + let url = message.data[0] ? message.data[0] : "about:home"; + win.openDialog("chrome://browser/content/", "_blank", "chrome,all,dialog=no,non-remote", url); + }, + /** * Opens a URL in a new tab in the browser. * @@ -1059,12 +1092,23 @@ const LoopAPIInternal = { // `kMessageHandlers` dictionary. let wildcardName = handlerName + ":*"; if (kMessageHandlers[wildcardName]) { - // Alright, pass the message forward. - kMessageHandlers[wildcardName](action, message, reply); + // A unit test might've stubbed the handler. + if (gStubbedMessageHandlers && gStubbedMessageHandlers[wildcardName]) { + gStubbedMessageHandlers[wildcardName](action, message, reply); + } else { + // Alright, pass the message forward. + kMessageHandlers[wildcardName](action, message, reply); + } // Aaaaand we're done. return; } + // A unit test might've stubbed the handler. + if (gStubbedMessageHandlers && gStubbedMessageHandlers[handlerName]) { + gStubbedMessageHandlers[handlerName](message, reply); + return; + } + if (!kMessageHandlers[handlerName]) { let msg = "Ouch, no message handler available for '" + handlerName + "'"; MozLoopService.log.error(msg); @@ -1252,9 +1296,13 @@ this.LoopAPI = Object.freeze({ } gPageListeners = pageListeners; }, + stubMessageHandlers: function(handlers) { + gStubbedMessageHandlers = handlers; + }, restore: function() { if (gOriginalPageListeners) { gPageListeners = gOriginalPageListeners; } + gStubbedMessageHandlers = null; } }); diff --git a/browser/components/loop/standalone/content/css/webapp.css b/browser/components/loop/standalone/content/css/webapp.css index cedb557e7e8..bc46ed3d9e9 100644 --- a/browser/components/loop/standalone/content/css/webapp.css +++ b/browser/components/loop/standalone/content/css/webapp.css @@ -239,6 +239,7 @@ html[dir="rtl"] .standalone-overlay-wrapper > .standalone-moz-logo { color: #4a4a4a; margin: auto; padding: 0 5px; + width: 100%; } .room-inner-info-area > button { diff --git a/browser/components/loop/test/desktop-local/index.html b/browser/components/loop/test/desktop-local/index.html index f8ebaaa8b10..d5108f26457 100644 --- a/browser/components/loop/test/desktop-local/index.html +++ b/browser/components/loop/test/desktop-local/index.html @@ -14,32 +14,22 @@
+ + - - diff --git a/browser/components/loop/test/desktop-local/panel_test.js b/browser/components/loop/test/desktop-local/panel_test.js index 512b8440a45..381f8ffa277 100644 --- a/browser/components/loop/test/desktop-local/panel_test.js +++ b/browser/components/loop/test/desktop-local/panel_test.js @@ -68,6 +68,7 @@ describe("loop.panel", function() { Confirm: sinon.stub(), GetHasEncryptionKey: function() { return true; }, HangupAllChatWindows: function() {}, + IsMultiProcessEnabled: sinon.stub(), LoginToFxA: sinon.stub(), LogoutFromFxA: sinon.stub(), NotifyUITour: sinon.stub(), @@ -591,6 +592,17 @@ describe("loop.panel", function() { // Do nothing } }); + + it("should render a E10sNotSupported when multiprocess is enabled", function() { + LoopMochaUtils.stubLoopRequest({ + IsMultiProcessEnabled: function() { return true; } + }); + + var view = createTestPanelView(); + + TestUtils.findRenderedComponentWithType(view, loop.panel.E10sNotSupported); + }); + }); }); diff --git a/browser/components/loop/test/mochitest/browser_fxa_login.js b/browser/components/loop/test/mochitest/browser_fxa_login.js index 964da7b6a32..9036c06ad98 100644 --- a/browser/components/loop/test/mochitest/browser_fxa_login.js +++ b/browser/components/loop/test/mochitest/browser_fxa_login.js @@ -8,6 +8,7 @@ "use strict"; const BASE_URL = Services.prefs.getCharPref("loop.server"); +const { LoopAPI } = Cu.import("resource:///modules/loop/MozLoopAPI.jsm", {}); function* checkFxA401() { let err = MozLoopService.errors.get("login"); @@ -46,6 +47,11 @@ add_task(function* setup() { // Normally the same pushUrl would be registered but we change it in the test // to be able to check for success on the second registration. + LoopAPI.stubMessageHandlers({ + IsMultiProcessEnabled: function(message, reply) { + reply(false); + } + }); registerCleanupFunction(function* () { info("cleanup time"); yield promiseDeletedOAuthParams(BASE_URL); diff --git a/browser/components/loop/test/mochitest/browser_toolbarbutton.js b/browser/components/loop/test/mochitest/browser_toolbarbutton.js index 2575c317a3e..4023ce9db72 100644 --- a/browser/components/loop/test/mochitest/browser_toolbarbutton.js +++ b/browser/components/loop/test/mochitest/browser_toolbarbutton.js @@ -43,18 +43,18 @@ add_task(function* test_LoopUI_getters() { add_task(function* test_doNotDisturb() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); yield MozLoopService.doNotDisturb = true; Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "disabled", "Check button is in disabled state"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Do not disturb", "Check button has disabled tooltiptext"); yield MozLoopService.doNotDisturb = false; Assert.notStrictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "disabled", "Check button is not in disabled state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); }); add_task(function* test_doNotDisturb_with_login() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); yield MozLoopService.doNotDisturb = true; Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "disabled", "Check button is in disabled state"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Do not disturb", "Check button has disabled tooltiptext"); @@ -62,34 +62,34 @@ add_task(function* test_doNotDisturb_with_login() { MozLoopServiceInternal.fxAOAuthProfile = fxASampleProfile; yield MozLoopServiceInternal.notifyStatusChanged("login"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "active", "Check button is in active state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Active conversation", "Check button has active tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "You are sharing your tabs", "Check button has active tooltiptext"); yield loadLoopPanel(); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "disabled", "Check button is in disabled state after opening panel"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Do not disturb", "Check button has disabled tooltiptext"); LoopUI.panel.hidePopup(); yield MozLoopService.doNotDisturb = false; Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); MozLoopServiceInternal.fxAOAuthTokenData = null; yield MozLoopServiceInternal.notifyStatusChanged(); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); }); add_task(function* test_error() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); yield MozLoopServiceInternal.setError("testing", {}); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "error", "Check button is in error state"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Error!", "Check button has error tooltiptext"); yield MozLoopServiceInternal.clearError("testing"); Assert.notStrictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "error", "Check button is not in error state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); }); add_task(function* test_error_with_login() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); yield MozLoopServiceInternal.setError("testing", {}); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "error", "Check button is in error state"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Error!", "Check button has error tooltiptext"); @@ -99,34 +99,34 @@ add_task(function* test_error_with_login() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Error!", "Check button has error tooltiptext"); yield MozLoopServiceInternal.clearError("testing"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); MozLoopServiceInternal.fxAOAuthProfile = null; MozLoopServiceInternal.notifyStatusChanged(); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); }); add_task(function* test_active() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); MozLoopServiceInternal.fxAOAuthTokenData = fxASampleToken; MozLoopServiceInternal.fxAOAuthProfile = fxASampleProfile; yield MozLoopServiceInternal.notifyStatusChanged("login"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "active", "Check button is in active state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Active conversation", "Check button has active tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "You are sharing your tabs", "Check button has active tooltiptext"); yield loadLoopPanel(); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state after opening panel"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); LoopUI.panel.hidePopup(); MozLoopServiceInternal.fxAOAuthTokenData = null; MozLoopServiceInternal.notifyStatusChanged(); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); }); add_task(function* test_room_participants() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); let roomsCache = new Map([["test_room", { participants: [{ displayName: "hugh", id: "008", owner: true }] }]]); LoopRooms._setRoomsCache(roomsCache); MozLoopServiceInternal.notifyStatusChanged(); @@ -136,18 +136,18 @@ add_task(function* test_room_participants() { // And that's what the line below does, waits until the next tick yield new Promise(resolve => executeSoon(resolve)); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "active", "Check button is in active state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Active conversation", "Check button has active tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "You are sharing your tabs", "Check button has active tooltiptext"); roomsCache.set("test_room", { participants: [{ displayName: "hugh", id: "008", owner: false }] }); LoopRooms._setRoomsCache(roomsCache); MozLoopServiceInternal.notifyStatusChanged(); yield new Promise(resolve => executeSoon(resolve)); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "active", "Check button is in active state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Someone is waiting for you in a conversation", "Check button has participantswaiting tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Someone is waiting for you", "Check button has participantswaiting tooltiptext"); roomsCache.set("test_room", { participants: [] }); LoopRooms._setRoomsCache(roomsCache); MozLoopServiceInternal.notifyStatusChanged(); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); LoopRooms._setRoomsCache(); }); @@ -167,13 +167,13 @@ add_task(function* test_panelToggle_on_click() { add_task(function* test_screen_share() { Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); MozLoopService.setScreenShareState("1", true); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "action", "Check button is in action state"); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "You are sharing your screen", "Check button has sharingscreen tooltiptext"); MozLoopService.setScreenShareState("1", false); Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("state"), "", "Check button is in default state"); - Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Start a conversation", "Check button has default tooltiptext"); + Assert.strictEqual(LoopUI.toolbarButton.node.getAttribute("tooltiptext"), "Browse this page with a friend", "Check button has default tooltiptext"); }); add_task(function* test_private_browsing_window() { diff --git a/browser/components/loop/test/shared/index.html b/browser/components/loop/test/shared/index.html index f713eccc24c..6489871738e 100644 --- a/browser/components/loop/test/shared/index.html +++ b/browser/components/loop/test/shared/index.html @@ -14,24 +14,15 @@
+ + - @@ -40,7 +31,6 @@ - diff --git a/browser/components/loop/test/shared/loop_mocha_utils.js b/browser/components/loop/test/shared/loop_mocha_utils.js index 13d4bbc2d3c..54df304b572 100644 --- a/browser/components/loop/test/shared/loop_mocha_utils.js +++ b/browser/components/loop/test/shared/loop_mocha_utils.js @@ -8,6 +8,9 @@ var LoopMochaUtils = (function(global, _) { var gListenerCallbacks = []; var gPushListenerCallbacks = []; var gOldAddMessageListener, gOldSendAsyncMessage; + var gUncaughtError; + var gCaughtIssues = []; + /** * The messaging between chrome and content (pubsub.js) is using Promises which @@ -231,10 +234,75 @@ var LoopMochaUtils = (function(global, _) { loop.subscribe.reset(); } + /** + * Used to initiate trapping of errors and warnings when running tests. + * addErrorCheckingTests() should be called to add the actual processing of + * results. + */ + function trapErrors() { + window.addEventListener("error", function(error) { + gUncaughtError = error; + }); + var consoleWarn = console.warn; + var consoleError = console.error; + console.warn = function() { + var args = Array.slice(arguments); + try { + throw new Error(); + } catch (e) { + gCaughtIssues.push([args, e.stack]); + } + consoleWarn.apply(console, args); + }; + console.error = function() { + var args = Array.slice(arguments); + gCaughtIssues.push(args); + consoleError.apply(console, args); + }; + } + + /** + * Adds tests to check no warnings nor errors have occurred since trapErrors + * was called. + */ + function addErrorCheckingTests() { + describe("Uncaught Error Check", function() { + it("should load the tests without errors", function() { + chai.expect(gUncaughtError && gUncaughtError.message).to.be.undefined; + }); + }); + + describe("Unexpected Logged Warnings and Errors Check", function() { + it("should not log any warnings nor errors", function() { + if (gCaughtIssues.length) { + throw new Error(gCaughtIssues); + } else { + chai.expect(gCaughtIssues.length).to.eql(0); + } + }); + }); + } + + /** + * Utility function for starting the mocha test run. Adds a marker for when + * the tests have completed. + */ + function runTests() { + mocha.run(function() { + var completeNode = document.createElement("p"); + completeNode.setAttribute("id", "complete"); + completeNode.appendChild(document.createTextNode("Complete")); + document.getElementById("mocha").appendChild(completeNode); + }); + } + return { + addErrorCheckingTests: addErrorCheckingTests, createSandbox: createSandbox, - stubLoopRequest: stubLoopRequest, + publish: publish, restore: restore, - publish: publish + runTests: runTests, + stubLoopRequest: stubLoopRequest, + trapErrors: trapErrors }; })(this, _); diff --git a/browser/components/loop/test/shared/textChatView_test.js b/browser/components/loop/test/shared/textChatView_test.js index ca3ac9d3ad4..06636330f96 100644 --- a/browser/components/loop/test/shared/textChatView_test.js +++ b/browser/components/loop/test/shared/textChatView_test.js @@ -6,6 +6,7 @@ describe("loop.shared.views.TextChatView", function() { var expect = chai.expect; var sharedActions = loop.shared.actions; + var sharedUtils = loop.shared.utils; var sharedViews = loop.shared.views; var TestUtils = React.addons.TestUtils; var CHAT_MESSAGE_TYPES = loop.store.CHAT_MESSAGE_TYPES; @@ -15,7 +16,7 @@ describe("loop.shared.views.TextChatView", function() { var dispatcher, fakeSdkDriver, sandbox, store, fakeClock; beforeEach(function() { - sandbox = sinon.sandbox.create(); + sandbox = LoopMochaUtils.createSandbox(); fakeClock = sandbox.useFakeTimers(); dispatcher = new loop.Dispatcher(); diff --git a/browser/components/loop/test/shared/views_test.js b/browser/components/loop/test/shared/views_test.js index 85dc65ec138..3cf0188aeba 100644 --- a/browser/components/loop/test/shared/views_test.js +++ b/browser/components/loop/test/shared/views_test.js @@ -306,6 +306,8 @@ describe("loop.shared.views", function() { } } }); + + sandbox.stub(console, "error"); }); function mountTestComponent(props) { @@ -326,7 +328,7 @@ describe("loop.shared.views", function() { expect(comp.getDOMNode()).to.eql(null); }); - it("should not show an indefined menu option", function() { + it("should not show an undefined menu option", function() { var settingsMenuItems = [ { id: "not Defined" }, { id: "help" } @@ -336,7 +338,19 @@ describe("loop.shared.views", function() { expect(menuItems).to.have.length.of(1); }); - it("should not render anythin if not exists any valid item to show", function() { + it("should log an error for an undefined menu option", function() { + var settingsMenuItems = [ + { id: "not Defined" }, + { id: "help" } + ]; + + mountTestComponent({ menuItems: settingsMenuItems }); + + sinon.assert.calledOnce(console.error); + sinon.assert.calledWithMatch(console.error, "Invalid"); + }); + + it("should not render anything if not exists any valid item to show", function() { var settingsMenuItems = [ { id: "not Defined" }, { id: "another wrong menu item" } diff --git a/browser/components/loop/test/standalone/index.html b/browser/components/loop/test/standalone/index.html index dd1fd699834..5af0462cf56 100644 --- a/browser/components/loop/test/standalone/index.html +++ b/browser/components/loop/test/standalone/index.html @@ -14,24 +14,15 @@
+ + - @@ -68,24 +59,8 @@ + LoopMochaUtils.addErrorCheckingTests(); + LoopMochaUtils.runTests(); + diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index ee8828f5602..ce3a2555eb8 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -1375,6 +1375,8 @@ BrowserGlue.prototype = { #ifdef E10S_TESTING_ONLY E10SUINotification.checkStatus(); +#else + E10SAccessibilityCheck.init(); #endif }, @@ -3379,7 +3381,91 @@ var E10SUINotification = { win.PopupNotifications.show(browser, "a11y_enabled_with_e10s", promptMessage, null, mainAction, secondaryActions, options); }, }; -#endif + +#else // E10S_TESTING_ONLY + +var E10SAccessibilityCheck = { + init: function() { + Services.obs.addObserver(this, "a11y-init-or-shutdown", true); + if (Services.appinfo.accessibilityIsBlacklistedForE10S) { + this._showE10sAccessibilityWarning(); + } + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]), + + observe: function(subject, topic, data) { + if (topic == "a11y-init-or-shutdown" + && data == "1" && + Services.appinfo.accessibilityIsBlacklistedForE10S) { + this._showE10sAccessibilityWarning(); + } + }, + + _warnedAboutAccessibility: false, + + _showE10sAccessibilityWarning: function() { + try { + if (!Services.prefs.getBoolPref("browser.tabs.remote.disabled-for-a11y")) { + // Only return if the pref exists and was set to false, but not + // if the pref didn't exist (which will throw). + return; + } + } catch (e) { } + + Services.prefs.setBoolPref("browser.tabs.remote.disabled-for-a11y", true); + + if (this._warnedAboutAccessibility || + !Services.appinfo.browserTabsRemoteAutostart) { + return; + } + this._warnedAboutAccessibility = true; + + let win = RecentWindow.getMostRecentBrowserWindow(); + if (!win) { + // Just restart immediately. + Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart); + return; + } + + let browser = win.gBrowser.selectedBrowser; + + let promptMessage = win.gNavigatorBundle.getFormattedString( + "e10s.accessibilityNotice.mainMessage", + [gBrandBundle.GetStringFromName("brandShortName")] + ); + let mainAction = { + label: win.gNavigatorBundle.getString("e10s.accessibilityNotice.disableAndRestart.label"), + accessKey: win.gNavigatorBundle.getString("e10s.accessibilityNotice.disableAndRestart.accesskey"), + callback: function () { + // Restart the app + let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart"); + if (cancelQuit.data) + return; // somebody canceled our quit request + Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart); + } + }; + let secondaryActions = [ + { + label: win.gNavigatorBundle.getString("e10s.accessibilityNotice.dontDisable.label"), + accessKey: win.gNavigatorBundle.getString("e10s.accessibilityNotice.dontDisable.accesskey"), + callback: function () { + Services.prefs.setBoolPref("browser.tabs.remote.disabled-for-a11y", false); + } + } + ]; + let options = { + popupIconURL: "chrome://browser/skin/e10s-64@2x.png", + learnMoreURL: "https://wiki.mozilla.org/Electrolysis", + persistWhileVisible: true + }; + + win.PopupNotifications.show(browser, "a11y_enabled_with_e10s", promptMessage, null, mainAction, secondaryActions, options); + }, +}; + +#endif // E10S_TESTING_ONLY var components = [BrowserGlue, ContentPermissionPrompt, AboutNewTabService]; this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); diff --git a/browser/components/preferences/in-content/advanced.xul b/browser/components/preferences/in-content/advanced.xul index ecb31a30dc3..7515191e908 100644 --- a/browser/components/preferences/in-content/advanced.xul +++ b/browser/components/preferences/in-content/advanced.xul @@ -117,7 +117,9 @@ class="header" hidden="true" data-category="paneAdvanced"> - + +