From 0e5c640329b399e6826dac01c437c2d8b317fe50 Mon Sep 17 00:00:00 2001 From: Drew Willcoxon Date: Thu, 24 Apr 2014 19:09:23 -0700 Subject: [PATCH] Bug 962490 - Add a search field to the new tab page (part 2: about:newtab changes). r=ttaubert --- browser/base/content/newtab/grid.js | 8 +- browser/base/content/newtab/newTab.css | 171 +++++++++- browser/base/content/newtab/newTab.js | 2 + browser/base/content/newtab/newTab.xul | 19 ++ browser/base/content/newtab/page.js | 8 +- browser/base/content/newtab/search.js | 170 ++++++++++ browser/base/content/test/newtab/browser.ini | 6 +- .../test/newtab/browser_newtab_focus.js | 6 +- .../test/newtab/browser_newtab_search.js | 295 ++++++++++++++++++ .../browser_newtab_sponsored_icon_click.js | 4 + browser/base/content/test/newtab/head.js | 63 ++++ .../content/test/newtab/searchEngineLogo.xml | 7 + .../test/newtab/searchEngineNoLogo.xml | 5 + 13 files changed, 756 insertions(+), 8 deletions(-) create mode 100644 browser/base/content/newtab/search.js create mode 100644 browser/base/content/test/newtab/browser_newtab_search.js create mode 100644 browser/base/content/test/newtab/searchEngineLogo.xml create mode 100644 browser/base/content/test/newtab/searchEngineNoLogo.xml diff --git a/browser/base/content/newtab/grid.js b/browser/base/content/newtab/grid.js index 44029290bb72..0f2dab013abd 100644 --- a/browser/base/content/newtab/grid.js +++ b/browser/base/content/newtab/grid.js @@ -197,12 +197,18 @@ let gGrid = { } let availSpace = document.documentElement.clientHeight - this._cellMargin - - document.querySelector("#newtab-margin-undo-container").offsetHeight; + document.querySelector("#newtab-margin-undo-container").offsetHeight - + document.querySelector("#newtab-search-form").offsetHeight; let visibleRows = Math.floor(availSpace / this._cellHeight); this._node.style.height = this._computeHeight() + "px"; this._node.style.maxHeight = this._computeHeight(visibleRows) + "px"; this._node.style.maxWidth = gGridPrefs.gridColumns * this._cellWidth + GRID_WIDTH_EXTRA + "px"; + + // Resize the search bar. + let width = parseFloat(window.getComputedStyle(this._node).width); + let visibleCols = Math.floor(width / this._cellWidth); + gSearch.setWidth(visibleCols * this._cellWidth - this._cellMargin); }, _shouldRenderGrid : function Grid_shouldRenderGrid() { diff --git a/browser/base/content/newtab/newTab.css b/browser/base/content/newtab/newTab.css index 29143300d1d8..e4f99fc4802f 100644 --- a/browser/base/content/newtab/newTab.css +++ b/browser/base/content/newtab/newTab.css @@ -2,6 +2,11 @@ * 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/. */ +input { + font: message-box !important; + font-size: 16px !important; +} + input[type=button] { cursor: pointer; } @@ -12,6 +17,7 @@ input[type=button] { position: relative; -moz-box-flex: 1; -moz-user-focus: normal; + -moz-box-orient: vertical; } #newtab-scrollbox:not([page-disabled]) { @@ -54,6 +60,7 @@ input[type=button] { #newtab-margin-undo-container { display: -moz-box; -moz-box-pack: center; + margin-bottom: 26px; /* 32 - 6 search form top "padding" */ } #newtab-horizontal-margin { @@ -64,10 +71,17 @@ input[type=button] { #newtab-margin-top, #newtab-margin-bottom { display: -moz-box; - -moz-box-flex: 1; position: relative; } +#newtab-margin-top { + -moz-box-flex: 1; +} + +#newtab-margin-bottom { + -moz-box-flex: 2; +} + .newtab-side-margin { min-width: 16px; -moz-box-flex: 1; @@ -213,7 +227,7 @@ input[type=button] { opacity: 0.01; } -/* PANEL */ +/* SPONSORED PANEL */ #sponsored-panel { width: 330px; } @@ -225,3 +239,156 @@ input[type=button] { #sponsored-panel .text-link { margin: 12px 0 0; } + +/* SEARCH */ +#newtab-search-container { + display: -moz-box; + position: relative; + -moz-box-align: center; + -moz-box-pack: center; +} + +#newtab-search-container[page-disabled] { + opacity: 0; + pointer-events: none; +} + +#newtab-search-form { + display: -moz-box; + -moz-box-orient: horizontal; + -moz-box-align: center; + height: 44px; /* 32 + 6 logo top "padding" + 6 logo bottom "padding" */ + margin-bottom: 10px; /* 32 - 16 tiles top margin - 6 logo bottom "padding" */ +} + +#newtab-search-logo { + display: -moz-box; + width: 77px; /* 65 image width + 6 left "padding" + 6 right "padding" */ + height: 38px; /* 26 image height + 6 top "padding" + 6 bottom "padding" */ + border: 1px solid transparent; + -moz-margin-end: 8px; + background-repeat: no-repeat; + background-position: center; + background-size: 65px 26px; +} + +#newtab-search-logo[hidden] { + display: none; +} + +#newtab-search-logo[active], +#newtab-search-logo:hover { + background-color: #e9e9e9; + border: 1px solid rgb(226, 227, 229); + border-radius: 2.5px; +} + +#newtab-search-text { + height: 32px; + -moz-box-flex: 1; + + padding: 0 8px; + background: hsla(0,0%,100%,.9) padding-box; + border: 1px solid; + border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2); + box-shadow: 0 1px 0 hsla(210,65%,9%,.02) inset, + 0 0 2px hsla(210,65%,9%,.1) inset, + 0 1px 0 hsla(0,0%,100%,.2); + border-radius: 2.5px 0 0 2.5px; +} + +#newtab-search-text:-moz-dir(rtl) { + border-radius: 0 2.5px 2.5px 0; +} + +#newtab-search-text:focus, +#newtab-search-text[autofocus] { + border-color: hsla(206,100%,60%,.6) hsla(206,76%,52%,.6) hsla(204,100%,40%,.6); +} + +#newtab-search-submit { + height: 32px; + + -moz-margin-start: -1px; + background: linear-gradient(hsla(0,0%,100%,.8), hsla(0,0%,100%,.1)) padding-box; + padding: 0 9px; + border: 1px solid; + border-color: hsla(210,54%,20%,.15) hsla(210,54%,20%,.17) hsla(210,54%,20%,.2); + -moz-border-start: 1px solid transparent; + border-radius: 0 2.5px 2.5px 0; + box-shadow: 0 0 2px hsla(0,0%,100%,.5) inset, + 0 1px 0 hsla(0,0%,100%,.2); + cursor: pointer; + transition-property: background-color, border-color, box-shadow; + transition-duration: 150ms; +} + +#newtab-search-submit:-moz-dir(rtl) { + border-radius: 2.5px 0 0 2.5px; +} + +#newtab-search-text:focus + #newtab-search-submit, +#newtab-search-text + #newtab-search-submit:hover, +#newtab-search-text[autofocus] + #newtab-search-submit { + border-color: #59b5fc #45a3e7 #3294d5; + color: white; +} + +#newtab-search-text:focus + #newtab-search-submit, +#newtab-search-text[autofocus] + #newtab-search-submit { + background-image: linear-gradient(#4cb1ff, #1793e5); + box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset, + 0 0 0 1px hsla(0,0%,100%,.1) inset, + 0 1px 0 hsla(210,54%,20%,.03); +} + +#newtab-search-text + #newtab-search-submit:hover { + background-image: linear-gradient(#66bdff, #0d9eff); + box-shadow: 0 1px 0 hsla(0,0%,100%,.2) inset, + 0 0 0 1px hsla(0,0%,100%,.1) inset, + 0 1px 0 hsla(210,54%,20%,.03), + 0 0 4px hsla(206,100%,20%,.2); +} + +#newtab-search-text + #newtab-search-submit:hover:active { + box-shadow: 0 1px 1px hsla(211,79%,6%,.1) inset, + 0 0 1px hsla(211,79%,6%,.2) inset; + transition-duration: 0ms; +} + +#newtab-search-panel .panel-arrowcontent { + -moz-padding-start: 0; + -moz-padding-end: 0; + padding-top: 0; + padding-bottom: 0; + background: rgb(248, 250, 251); +} + +.newtab-search-panel-engine { + -moz-box-align: center; + padding-top: 4px; + padding-bottom: 4px; + -moz-padding-start: 24px; + -moz-padding-end: 24px; +} + +.newtab-search-panel-engine:not(:last-child) { + border-bottom: 1px solid #ccc; +} + +.newtab-search-panel-engine > image { + -moz-margin-end: 8px; + width: 16px; + height: 16px; + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); +} + +.newtab-search-panel-engine > label { + -moz-padding-start: 0; + -moz-margin-start: 0; + color: rgb(130, 132, 133); +} + +.newtab-search-panel-engine[selected] { + background: url("chrome://global/skin/menu/shared-menu-check.png") center left 4px no-repeat transparent; +} diff --git a/browser/base/content/newtab/newTab.js b/browser/base/content/newtab/newTab.js index a56a391bb017..66308468df94 100644 --- a/browser/base/content/newtab/newTab.js +++ b/browser/base/content/newtab/newTab.js @@ -41,6 +41,7 @@ function inPrivateBrowsingMode() { } const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; +const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; #include transformations.js #include page.js @@ -54,6 +55,7 @@ const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; #include dropPreview.js #include updater.js #include undo.js +#include search.js // Everything is loaded. Initialize the New Tab Page. gPage.init(); diff --git a/browser/base/content/newtab/newTab.xul b/browser/base/content/newtab/newTab.xul index b736379833be..b70512d2b9d0 100644 --- a/browser/base/content/newtab/newTab.xul +++ b/browser/base/content/newtab/newTab.xul @@ -11,6 +11,8 @@ %newTabDTD; + + %searchBarDTD; ]> + + + &cmd_engineManager.label; + + +
@@ -46,6 +55,16 @@
+
+
+
+
diff --git a/browser/base/content/newtab/page.js b/browser/base/content/newtab/page.js index 2c3bb8f26e8b..d0e286529505 100644 --- a/browser/base/content/newtab/page.js +++ b/browser/base/content/newtab/page.js @@ -111,6 +111,8 @@ let gPage = { this._initialized = true; + gSearch.init(); + this._mutationObserver = new MutationObserver(() => { if (this.allowBackgroundCaptures) { Services.telemetry.getHistogramById("NEWTAB_PAGE_SHOWN").add(true); @@ -138,6 +140,10 @@ let gPage = { let shownCount = Math.min(10, count); Services.telemetry.getHistogramById(shownId).add(shownCount); } + + // content.js isn't loaded for the page while it's in the preloader, + // which is why this is necessary. + gSearch.setUpInitialState(); } }); this._mutationObserver.observe(document.documentElement, { @@ -164,7 +170,7 @@ let gPage = { */ _updateAttributes: function Page_updateAttributes(aValue) { // Set the nodes' states. - let nodeSelector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid"; + let nodeSelector = "#newtab-scrollbox, #newtab-toggle, #newtab-grid, #newtab-search-container"; for (let node of document.querySelectorAll(nodeSelector)) { if (aValue) node.removeAttribute("page-disabled"); diff --git a/browser/base/content/newtab/search.js b/browser/base/content/newtab/search.js new file mode 100644 index 000000000000..35f9b987de1c --- /dev/null +++ b/browser/base/content/newtab/search.js @@ -0,0 +1,170 @@ +#ifdef 0 +/* 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/. */ +#endif + +let gSearch = { + + currentEngineName: null, + + init: function () { + for (let idSuffix of this._nodeIDSuffixes) { + this._nodes[idSuffix] = + document.getElementById("newtab-search-" + idSuffix); + } + + window.addEventListener("ContentSearchService", this); + this.setUpInitialState(); + }, + + setUpInitialState: function () { + this._send("GetState"); + }, + + showPanel: function () { + let panel = this._nodes.panel; + let logo = this._nodes.logo; + panel.openPopup(logo); + logo.setAttribute("active", "true"); + panel.addEventListener("popuphidden", function onHidden() { + panel.removeEventListener("popuphidden", onHidden); + logo.removeAttribute("active"); + }); + }, + + search: function (event) { + event.preventDefault(); + let searchStr = this._nodes.text.value; + if (this.currentEngineName && searchStr.length) { + this._send("Search", { + engineName: this.currentEngineName, + searchString: searchStr, + whence: "newtab", + }); + } + }, + + manageEngines: function () { + this._nodes.panel.hidePopup(); + this._send("ManageEngines"); + }, + + setWidth: function (width) { + this._nodes.form.style.width = width + "px"; + this._nodes.form.style.maxWidth = width + "px"; + }, + + handleEvent: function (event) { + this["on" + event.detail.type](event.detail.data); + }, + + onState: function (data) { + this._makePanel(data.engines); + this._setCurrentEngine(data.currentEngine); + this._initWhenInitalStateReceived(); + }, + + onCurrentEngine: function (engineName) { + this._setCurrentEngine(engineName); + }, + + _nodeIDSuffixes: [ + "form", + "logo", + "manage", + "panel", + "text", + ], + + _nodes: {}, + + _initWhenInitalStateReceived: function () { + this._nodes.form.addEventListener("submit", e => this.search(e)); + this._nodes.logo.addEventListener("click", e => this.showPanel()); + this._nodes.manage.addEventListener("click", e => this.manageEngines()); + this._initWhenInitalStateReceived = function () {}; + }, + + _send: function (type, data=null) { + window.dispatchEvent(new CustomEvent("ContentSearchClient", { + detail: { + type: type, + data: data, + }, + })); + }, + + _makePanel: function (engines) { + let panel = this._nodes.panel; + + // Empty the panel except for the Manage Engines row. + let i = 0; + while (i < panel.childNodes.length) { + let node = panel.childNodes[i]; + if (node != this._nodes.manage) { + panel.removeChild(node); + } + else { + i++; + } + } + + // Add all the engines. + for (let engine of engines) { + panel.insertBefore(this._makePanelEngine(panel, engine), + this._nodes.manage); + } + }, + + _makePanelEngine: function (panel, engine) { + let box = document.createElementNS(XUL_NAMESPACE, "hbox"); + box.className = "newtab-search-panel-engine"; + box.setAttribute("engine", engine.name); + + box.addEventListener("click", () => { + this._send("SetCurrentEngine", engine.name); + panel.hidePopup(); + this._nodes.text.focus(); + }); + + let image = document.createElementNS(XUL_NAMESPACE, "image"); + if (engine.iconURI) { + image.setAttribute("src", engine.iconURI); + } + box.appendChild(image); + + let label = document.createElementNS(XUL_NAMESPACE, "label"); + label.setAttribute("value", engine.name); + box.appendChild(label); + + return box; + }, + + _setCurrentEngine: function (engine) { + this.currentEngineName = engine.name; + + // Set the logo. + let logoURI = window.devicePixelRatio == 2 ? engine.logo2xURI : + engine.logoURI; + if (logoURI) { + this._nodes.logo.hidden = false; + this._nodes.logo.style.backgroundImage = "url(" + logoURI + ")"; + this._nodes.text.placeholder = ""; + } + else { + this._nodes.logo.hidden = true; + this._nodes.text.placeholder = engine.name; + } + + // Set the selected state of all the engines in the panel. + for (let box of this._nodes.panel.childNodes) { + if (box.getAttribute("engine") == engine.name) { + box.setAttribute("selected", "true"); + } + else { + box.removeAttribute("selected"); + } + } + }, +}; diff --git a/browser/base/content/test/newtab/browser.ini b/browser/base/content/test/newtab/browser.ini index cc9ecf15d622..da3c02891a3f 100644 --- a/browser/base/content/test/newtab/browser.ini +++ b/browser/base/content/test/newtab/browser.ini @@ -1,6 +1,9 @@ [DEFAULT] -support-files = head.js skip-if = e10s # Bug ?????? - about:newtab tests don't work in e10s +support-files = + head.js + searchEngineLogo.xml + searchEngineNoLogo.xml [browser_newtab_background_captures.js] [browser_newtab_block.js] @@ -25,6 +28,7 @@ skip-if = os == "mac" # Intermittent failures, bug 898317 [browser_newtab_focus.js] [browser_newtab_perwindow_private_browsing.js] [browser_newtab_reset.js] +[browser_newtab_search.js] [browser_newtab_sponsored_icon_click.js] [browser_newtab_tabsync.js] [browser_newtab_undo.js] diff --git a/browser/base/content/test/newtab/browser_newtab_focus.js b/browser/base/content/test/newtab/browser_newtab_focus.js index e841d353739b..a423e3397801 100644 --- a/browser/base/content/test/newtab/browser_newtab_focus.js +++ b/browser/base/content/test/newtab/browser_newtab_focus.js @@ -9,9 +9,9 @@ function runTests() { Services.prefs.setIntPref("accessibility.tabfocus", 7); // Focus count in new tab page. - // 28 = 9 * 3 + 1 = 9 sites and 1 toggle button, each site has a link, a pin - // and a remove button. - let FOCUS_COUNT = 28; + // 30 = 9 * 3 + 3 = 9 sites, each with link, pin and remove buttons; search + // bar; search button; and toggle button. + let FOCUS_COUNT = 30; // Create a new tab page. yield setLinks("0,1,2,3,4,5,6,7,8"); diff --git a/browser/base/content/test/newtab/browser_newtab_search.js b/browser/base/content/test/newtab/browser_newtab_search.js new file mode 100644 index 000000000000..84073927150e --- /dev/null +++ b/browser/base/content/test/newtab/browser_newtab_search.js @@ -0,0 +1,295 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// See browser/components/search/test/browser_*_behavior.js for tests of actual +// searches. + +const ENGINE_LOGO = "searchEngineLogo.xml"; +const ENGINE_NO_LOGO = "searchEngineNoLogo.xml"; + +const SERVICE_EVENT_NAME = "ContentSearchService"; + +const LOGO_LOW_DPI_SIZE = [65, 26]; +const LOGO_HIGH_DPI_SIZE = [130, 52]; + +// The test has an expected search event queue and a search event listener. +// Search events that are expected to happen are added to the queue, and the +// listener consumes the queue and ensures that each event it receives is at +// the head of the queue. +// +// Each item in the queue is an object { type, deferred }. type is the +// expected search event type. deferred is a Promise.defer() value that is +// resolved when the event is consumed. +var gExpectedSearchEventQueue = []; + +var gNewEngines = []; + +function runTests() { + let oldCurrentEngine = Services.search.currentEngine; + + yield addNewTabPageTab(); + yield whenSearchInitDone(); + + // The tab is removed at the end of the test, so there's no need to remove + // this listener at the end of the test. + info("Adding search event listener"); + getContentWindow().addEventListener(SERVICE_EVENT_NAME, searchEventListener); + + let panel = searchPanel(); + is(panel.state, "closed", "Search panel should be closed initially"); + + // The panel's animation often is not finished when the test clicks on panel + // children, which makes the test click the wrong children, so disable it. + panel.setAttribute("animate", "false"); + + // Add the two test engines. + let logoEngine = null; + yield promiseNewSearchEngine(true).then(engine => { + logoEngine = engine; + TestRunner.next(); + }); + ok(!!logoEngine.getIconURLBySize(...LOGO_LOW_DPI_SIZE), + "Sanity check: engine should have 1x logo"); + ok(!!logoEngine.getIconURLBySize(...LOGO_HIGH_DPI_SIZE), + "Sanity check: engine should have 2x logo"); + + let noLogoEngine = null; + yield promiseNewSearchEngine(false).then(engine => { + noLogoEngine = engine; + TestRunner.next(); + }); + ok(!noLogoEngine.getIconURLBySize(...LOGO_LOW_DPI_SIZE), + "Sanity check: engine should not have 1x logo"); + ok(!noLogoEngine.getIconURLBySize(...LOGO_HIGH_DPI_SIZE), + "Sanity check: engine should not have 2x logo"); + + // Use the search service to change the current engine to the logo engine. + Services.search.currentEngine = logoEngine; + yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next); + checkCurrentEngine(ENGINE_LOGO); + + // Click the logo to open the search panel. + yield Promise.all([ + promisePanelShown(panel), + promiseClick(logoImg()), + ]).then(TestRunner.next); + + // In the search panel, click the no-logo engine. It should become the + // current engine. + let noLogoBox = null; + for (let box of panel.childNodes) { + if (box.getAttribute("engine") == noLogoEngine.name) { + noLogoBox = box; + break; + } + } + ok(noLogoBox, "Search panel should contain the no-logo engine"); + yield Promise.all([ + promiseSearchEvents(["CurrentEngine"]), + promiseClick(noLogoBox), + ]).then(TestRunner.next); + + checkCurrentEngine(ENGINE_NO_LOGO); + + // Switch back to the logo engine. + Services.search.currentEngine = logoEngine; + yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next); + checkCurrentEngine(ENGINE_LOGO); + + // Open the panel again. + yield Promise.all([ + promisePanelShown(panel), + promiseClick(logoImg()), + ]).then(TestRunner.next); + + // In the search panel, click the Manage Engines box. + let manageBox = $("manage"); + ok(!!manageBox, "The Manage Engines box should be present in the document"); + yield Promise.all([ + promiseManagerOpen(), + promiseClick(manageBox), + ]).then(TestRunner.next); + + // Done. Revert the current engine and remove the new engines. + Services.search.currentEngine = oldCurrentEngine; + yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next); + + let events = []; + for (let engine of gNewEngines) { + Services.search.removeEngine(engine); + events.push("State"); + } + yield promiseSearchEvents(events).then(TestRunner.next); +} + +function searchEventListener(event) { + info("Got search event " + event.detail.type); + let passed = false; + let nonempty = gExpectedSearchEventQueue.length > 0; + ok(nonempty, "Expected search event queue should be nonempty"); + if (nonempty) { + let { type, deferred } = gExpectedSearchEventQueue.shift(); + is(event.detail.type, type, "Got expected search event " + type); + if (event.detail.type == type) { + passed = true; + // Let gSearch respond to the event before continuing. + executeSoon(() => deferred.resolve()); + } + } + if (!passed) { + info("Didn't get expected event, stopping the test"); + getContentWindow().removeEventListener(SERVICE_EVENT_NAME, + searchEventListener); + // Set next() to a no-op so the test really does stop. + TestRunner.next = function () {}; + TestRunner.finish(); + } +} + +function $(idSuffix) { + return getContentDocument().getElementById("newtab-search-" + idSuffix); +} + +function promiseSearchEvents(events) { + info("Expecting search events: " + events); + events = events.map(e => ({ type: e, deferred: Promise.defer() })); + gExpectedSearchEventQueue.push(...events); + return Promise.all(events.map(e => e.deferred.promise)); +} + +function promiseNewSearchEngine(withLogo) { + let basename = withLogo ? ENGINE_LOGO : ENGINE_NO_LOGO; + info("Waiting for engine to be added: " + basename); + + // Wait for the search events triggered by adding the new engine. + // engine-added engine-loaded + let expectedSearchEvents = ["State", "State"]; + if (withLogo) { + // an engine-changed for each of the two logos + expectedSearchEvents.push("State", "State"); + } + let eventPromise = promiseSearchEvents(expectedSearchEvents); + + // Wait for addEngine(). + let addDeferred = Promise.defer(); + let url = getRootDirectory(gTestPath) + basename; + Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, { + onSuccess: function (engine) { + info("Search engine added: " + basename); + gNewEngines.push(engine); + addDeferred.resolve(engine); + }, + onError: function (errCode) { + ok(false, "addEngine failed with error code " + errCode); + addDeferred.reject(); + }, + }); + + // Make a new promise that wraps the previous promises. The only point of + // this is to pass the new engine to the yielder via deferred.resolve(), + // which is a little nicer than passing an array whose first element is the + // new engine. + let deferred = Promise.defer(); + Promise.all([addDeferred.promise, eventPromise]).then(values => { + let newEngine = values[0]; + deferred.resolve(newEngine); + }, () => deferred.reject()); + return deferred.promise; +} + +function checkCurrentEngine(basename) { + let engine = Services.search.currentEngine; + ok(engine.name.contains(basename), + "Sanity check: current engine: engine.name=" + engine.name + + " basename=" + basename); + + // gSearch.currentEngineName + is(gSearch().currentEngineName, engine.name, + "currentEngineName: " + engine.name); + + // search bar logo + let logoSize = [px * window.devicePixelRatio for (px of LOGO_LOW_DPI_SIZE)]; + let logoURI = engine.getIconURLBySize(...logoSize); + let logo = logoImg(); + is(logo.hidden, !logoURI, + "Logo should be visible iff engine has a logo: " + engine.name); + if (logoURI) { + is(logo.style.backgroundImage, 'url("' + logoURI + '")', "Logo URI"); + } + + // "selected" attributes of engines in the panel + let panel = searchPanel(); + for (let engineBox of panel.childNodes) { + let engineName = engineBox.getAttribute("engine"); + if (engineName == engine.name) { + is(engineBox.getAttribute("selected"), "true", + "Engine box's selected attribute should be true for " + + "selected engine: " + engineName); + } + else { + ok(!engineBox.hasAttribute("selected"), + "Engine box's selected attribute should be absent for " + + "non-selected engine: " + engineName); + } + } +} + +function promisePanelShown(panel) { + let deferred = Promise.defer(); + info("Waiting for popupshown"); + panel.addEventListener("popupshown", function onEvent() { + panel.removeEventListener("popupshown", onEvent); + is(panel.state, "open", "Panel state"); + executeSoon(() => deferred.resolve()); + }); + return deferred.promise; +} + +function promiseClick(node) { + let deferred = Promise.defer(); + let win = getContentWindow(); + SimpleTest.waitForFocus(() => { + EventUtils.synthesizeMouseAtCenter(node, {}, win); + deferred.resolve(); + }, win); + return deferred.promise; +} + +function promiseManagerOpen() { + info("Waiting for the search manager window to open..."); + let deferred = Promise.defer(); + let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"]. + getService(Ci.nsIWindowWatcher); + winWatcher.registerNotification(function onWin(subj, topic, data) { + if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) { + subj.addEventListener("load", function onLoad() { + subj.removeEventListener("load", onLoad); + if (subj.document.documentURI == + "chrome://browser/content/search/engineManager.xul") { + winWatcher.unregisterNotification(onWin); + ok(true, "Observed search manager window opened"); + is(subj.opener, gWindow, + "Search engine manager opener should be the chrome browser " + + "window containing the newtab page"); + executeSoon(() => { + subj.close(); + deferred.resolve(); + }); + } + }); + } + }); + return deferred.promise; +} + +function searchPanel() { + return $("panel"); +} + +function logoImg() { + return $("logo"); +} + +function gSearch() { + return getContentWindow().gSearch; +} diff --git a/browser/base/content/test/newtab/browser_newtab_sponsored_icon_click.js b/browser/base/content/test/newtab/browser_newtab_sponsored_icon_click.js index 6253552c75c9..ed4147bb9264 100644 --- a/browser/base/content/test/newtab/browser_newtab_sponsored_icon_click.js +++ b/browser/base/content/test/newtab/browser_newtab_sponsored_icon_click.js @@ -5,6 +5,10 @@ function runTests() { yield setLinks("0"); yield addNewTabPageTab(); + // When gSearch modifies the DOM as it sets itself up, it can prevent the + // popup from opening, depending on the timing. Wait until that's done. + yield whenSearchInitDone(); + let site = getCell(0).node.querySelector(".newtab-site"); site.setAttribute("type", "sponsored"); diff --git a/browser/base/content/test/newtab/head.js b/browser/base/content/test/newtab/head.js index 4348867496a6..6699b4ab0d33 100644 --- a/browser/base/content/test/newtab/head.js +++ b/browser/base/content/test/newtab/head.js @@ -25,10 +25,41 @@ let isLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc); let isWindows = ("@mozilla.org/windows-registry-key;1" in Cc); let gWindow = window; +// The tests assume all three rows of sites are shown, but the window may be too +// short to actually show three rows. Resize it if necessary. +let requiredInnerHeight = + 40 + 32 + // undo container + bottom margin + 44 + 32 + // search bar + bottom margin + (3 * (150 + 32)) + // 3 rows * (tile height + title and bottom margin) + 100; // breathing room + +let oldInnerHeight = null; +if (gBrowser.contentWindow.innerHeight < requiredInnerHeight) { + oldInnerHeight = gBrowser.contentWindow.innerHeight; + info("Changing browser inner height from " + oldInnerHeight + " to " + + requiredInnerHeight); + gBrowser.contentWindow.innerHeight = requiredInnerHeight; + let screenHeight = {}; + Cc["@mozilla.org/gfx/screenmanager;1"]. + getService(Ci.nsIScreenManager). + primaryScreen. + GetAvailRectDisplayPix({}, {}, {}, screenHeight); + screenHeight = screenHeight.value; + if (screenHeight < gBrowser.contentWindow.outerHeight) { + info("Warning: Browser outer height is now " + + gBrowser.contentWindow.outerHeight + ", which is larger than the " + + "available screen height, " + screenHeight + + ". That may cause problems."); + } +} + registerCleanupFunction(function () { while (gWindow.gBrowser.tabs.length > 1) gWindow.gBrowser.removeTab(gWindow.gBrowser.tabs[1]); + if (oldInnerHeight) + gBrowser.contentWindow.innerHeight = oldInnerHeight; + Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED); Services.prefs.clearUserPref(PREF_NEWTAB_DIRECTORYSOURCE); @@ -549,3 +580,35 @@ function whenPagesUpdated(aCallback, aOnlyIfHidden=false) { NewTabUtils.allPages.unregister(page); }); } + +/** + * Waits a small amount of time for search events to stop occurring in the + * newtab page. + * + * newtab pages receive some search events around load time that are difficult + * to predict. There are two categories of such events: (1) "State" events + * triggered by engine notifications like engine-changed, due to the search + * service initializing itself on app startup. This can happen when a test is + * the first test to run. (2) "State" events triggered by the newtab page + * itself when gSearch first sets itself up. newtab preloading makes these a + * pain to predict. + */ +function whenSearchInitDone() { + info("Waiting for initial search events..."); + let numTicks = 0; + function reset(event) { + info("Got initial search event " + event.detail.type + + ", waiting for more..."); + numTicks = 0; + } + let eventName = "ContentSearchService"; + getContentWindow().addEventListener(eventName, reset); + let interval = window.setInterval(() => { + if (++numTicks >= 100) { + info("Done waiting for initial search events"); + window.clearInterval(interval); + getContentWindow().removeEventListener(eventName, reset); + TestRunner.next(); + } + }, 0); +} diff --git a/browser/base/content/test/newtab/searchEngineLogo.xml b/browser/base/content/test/newtab/searchEngineLogo.xml new file mode 100644 index 000000000000..0a8b35f859ef --- /dev/null +++ b/browser/base/content/test/newtab/searchEngineLogo.xml @@ -0,0 +1,7 @@ + + +browser_newtab_search searchEngineLogo.xml + +data:image/png;base64,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 +data:image/png;base64,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 + diff --git a/browser/base/content/test/newtab/searchEngineNoLogo.xml b/browser/base/content/test/newtab/searchEngineNoLogo.xml new file mode 100644 index 000000000000..bbff6cf8f77c --- /dev/null +++ b/browser/base/content/test/newtab/searchEngineNoLogo.xml @@ -0,0 +1,5 @@ + + +browser_newtab_search searchEngineNoLogo.xml + +