browser/base/content/test/newtab/browser_newtab_search.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* Any copyright is dedicated to the Public Domain.
     2    http://creativecommons.org/publicdomain/zero/1.0/ */
     4 // See browser/components/search/test/browser_*_behavior.js for tests of actual
     5 // searches.
     7 const ENGINE_LOGO = "searchEngineLogo.xml";
     8 const ENGINE_NO_LOGO = "searchEngineNoLogo.xml";
    10 const SERVICE_EVENT_NAME = "ContentSearchService";
    12 const LOGO_LOW_DPI_SIZE = [65, 26];
    13 const LOGO_HIGH_DPI_SIZE = [130, 52];
    15 // The test has an expected search event queue and a search event listener.
    16 // Search events that are expected to happen are added to the queue, and the
    17 // listener consumes the queue and ensures that each event it receives is at
    18 // the head of the queue.
    19 //
    20 // Each item in the queue is an object { type, deferred }.  type is the
    21 // expected search event type.  deferred is a Promise.defer() value that is
    22 // resolved when the event is consumed.
    23 var gExpectedSearchEventQueue = [];
    25 var gNewEngines = [];
    27 function runTests() {
    28   let oldCurrentEngine = Services.search.currentEngine;
    30   yield addNewTabPageTab();
    31   yield whenSearchInitDone();
    33   // The tab is removed at the end of the test, so there's no need to remove
    34   // this listener at the end of the test.
    35   info("Adding search event listener");
    36   getContentWindow().addEventListener(SERVICE_EVENT_NAME, searchEventListener);
    38   let panel = searchPanel();
    39   is(panel.state, "closed", "Search panel should be closed initially");
    41   // The panel's animation often is not finished when the test clicks on panel
    42   // children, which makes the test click the wrong children, so disable it.
    43   panel.setAttribute("animate", "false");
    45   // Add the two test engines.
    46   let logoEngine = null;
    47   yield promiseNewSearchEngine(true).then(engine => {
    48     logoEngine = engine;
    49     TestRunner.next();
    50   });
    51   ok(!!logoEngine.getIconURLBySize(...LOGO_LOW_DPI_SIZE),
    52      "Sanity check: engine should have 1x logo");
    53   ok(!!logoEngine.getIconURLBySize(...LOGO_HIGH_DPI_SIZE),
    54      "Sanity check: engine should have 2x logo");
    56   let noLogoEngine = null;
    57   yield promiseNewSearchEngine(false).then(engine => {
    58     noLogoEngine = engine;
    59     TestRunner.next();
    60   });
    61   ok(!noLogoEngine.getIconURLBySize(...LOGO_LOW_DPI_SIZE),
    62      "Sanity check: engine should not have 1x logo");
    63   ok(!noLogoEngine.getIconURLBySize(...LOGO_HIGH_DPI_SIZE),
    64      "Sanity check: engine should not have 2x logo");
    66   // Use the search service to change the current engine to the logo engine.
    67   Services.search.currentEngine = logoEngine;
    68   yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
    69   checkCurrentEngine(ENGINE_LOGO);
    71   // Click the logo to open the search panel.
    72   yield Promise.all([
    73     promisePanelShown(panel),
    74     promiseClick(logoImg()),
    75   ]).then(TestRunner.next);
    77   // In the search panel, click the no-logo engine.  It should become the
    78   // current engine.
    79   let noLogoBox = null;
    80   for (let box of panel.childNodes) {
    81     if (box.getAttribute("engine") == noLogoEngine.name) {
    82       noLogoBox = box;
    83       break;
    84     }
    85   }
    86   ok(noLogoBox, "Search panel should contain the no-logo engine");
    87   yield Promise.all([
    88     promiseSearchEvents(["CurrentEngine"]),
    89     promiseClick(noLogoBox),
    90   ]).then(TestRunner.next);
    92   checkCurrentEngine(ENGINE_NO_LOGO);
    94   // Switch back to the logo engine.
    95   Services.search.currentEngine = logoEngine;
    96   yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
    97   checkCurrentEngine(ENGINE_LOGO);
    99   // Open the panel again.
   100   yield Promise.all([
   101     promisePanelShown(panel),
   102     promiseClick(logoImg()),
   103   ]).then(TestRunner.next);
   105   // In the search panel, click the Manage Engines box.
   106   let manageBox = $("manage");
   107   ok(!!manageBox, "The Manage Engines box should be present in the document");
   108   yield Promise.all([
   109     promiseManagerOpen(),
   110     promiseClick(manageBox),
   111   ]).then(TestRunner.next);
   113   // Done.  Revert the current engine and remove the new engines.
   114   Services.search.currentEngine = oldCurrentEngine;
   115   yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
   117   let events = [];
   118   for (let engine of gNewEngines) {
   119     Services.search.removeEngine(engine);
   120     events.push("State");
   121   }
   122   yield promiseSearchEvents(events).then(TestRunner.next);
   123 }
   125 function searchEventListener(event) {
   126   info("Got search event " + event.detail.type);
   127   let passed = false;
   128   let nonempty = gExpectedSearchEventQueue.length > 0;
   129   ok(nonempty, "Expected search event queue should be nonempty");
   130   if (nonempty) {
   131     let { type, deferred } = gExpectedSearchEventQueue.shift();
   132     is(event.detail.type, type, "Got expected search event " + type);
   133     if (event.detail.type == type) {
   134       passed = true;
   135       // Let gSearch respond to the event before continuing.
   136       executeSoon(() => deferred.resolve());
   137     }
   138   }
   139   if (!passed) {
   140     info("Didn't get expected event, stopping the test");
   141     getContentWindow().removeEventListener(SERVICE_EVENT_NAME,
   142                                            searchEventListener);
   143     // Set next() to a no-op so the test really does stop.
   144     TestRunner.next = function () {};
   145     TestRunner.finish();
   146   }
   147 }
   149 function $(idSuffix) {
   150   return getContentDocument().getElementById("newtab-search-" + idSuffix);
   151 }
   153 function promiseSearchEvents(events) {
   154   info("Expecting search events: " + events);
   155   events = events.map(e => ({ type: e, deferred: Promise.defer() }));
   156   gExpectedSearchEventQueue.push(...events);
   157   return Promise.all(events.map(e => e.deferred.promise));
   158 }
   160 function promiseNewSearchEngine(withLogo) {
   161   let basename = withLogo ? ENGINE_LOGO : ENGINE_NO_LOGO;
   162   info("Waiting for engine to be added: " + basename);
   164   // Wait for the search events triggered by adding the new engine.
   165   // engine-added engine-loaded
   166   let expectedSearchEvents = ["State", "State"];
   167   if (withLogo) {
   168     // an engine-changed for each of the two logos
   169     expectedSearchEvents.push("State", "State");
   170   }
   171   let eventPromise = promiseSearchEvents(expectedSearchEvents);
   173   // Wait for addEngine().
   174   let addDeferred = Promise.defer();
   175   let url = getRootDirectory(gTestPath) + basename;
   176   Services.search.addEngine(url, Ci.nsISearchEngine.TYPE_MOZSEARCH, "", false, {
   177     onSuccess: function (engine) {
   178       info("Search engine added: " + basename);
   179       gNewEngines.push(engine);
   180       addDeferred.resolve(engine);
   181     },
   182     onError: function (errCode) {
   183       ok(false, "addEngine failed with error code " + errCode);
   184       addDeferred.reject();
   185     },
   186   });
   188   // Make a new promise that wraps the previous promises.  The only point of
   189   // this is to pass the new engine to the yielder via deferred.resolve(),
   190   // which is a little nicer than passing an array whose first element is the
   191   // new engine.
   192   let deferred = Promise.defer();
   193   Promise.all([addDeferred.promise, eventPromise]).then(values => {
   194     let newEngine = values[0];
   195     deferred.resolve(newEngine);
   196   }, () => deferred.reject());
   197   return deferred.promise;
   198 }
   200 function checkCurrentEngine(basename) {
   201   let engine = Services.search.currentEngine;
   202   ok(engine.name.contains(basename),
   203      "Sanity check: current engine: engine.name=" + engine.name +
   204      " basename=" + basename);
   206   // gSearch.currentEngineName
   207   is(gSearch().currentEngineName, engine.name,
   208      "currentEngineName: " + engine.name);
   210   // search bar logo
   211   let logoSize = [px * window.devicePixelRatio for (px of LOGO_LOW_DPI_SIZE)];
   212   let logoURI = engine.getIconURLBySize(...logoSize);
   213   let logo = logoImg();
   214   is(logo.hidden, !logoURI,
   215      "Logo should be visible iff engine has a logo: " + engine.name);
   216   if (logoURI) {
   217     is(logo.style.backgroundImage, 'url("' + logoURI + '")', "Logo URI");
   218   }
   220   // "selected" attributes of engines in the panel
   221   let panel = searchPanel();
   222   for (let engineBox of panel.childNodes) {
   223     let engineName = engineBox.getAttribute("engine");
   224     if (engineName == engine.name) {
   225       is(engineBox.getAttribute("selected"), "true",
   226          "Engine box's selected attribute should be true for " +
   227          "selected engine: " + engineName);
   228     }
   229     else {
   230       ok(!engineBox.hasAttribute("selected"),
   231          "Engine box's selected attribute should be absent for " +
   232          "non-selected engine: " + engineName);
   233     }
   234   }
   235 }
   237 function promisePanelShown(panel) {
   238   let deferred = Promise.defer();
   239   info("Waiting for popupshown");
   240   panel.addEventListener("popupshown", function onEvent() {
   241     panel.removeEventListener("popupshown", onEvent);
   242     is(panel.state, "open", "Panel state");
   243     executeSoon(() => deferred.resolve());
   244   });
   245   return deferred.promise;
   246 }
   248 function promiseClick(node) {
   249   let deferred = Promise.defer();
   250   let win = getContentWindow();
   251   SimpleTest.waitForFocus(() => {
   252     EventUtils.synthesizeMouseAtCenter(node, {}, win);
   253     deferred.resolve();
   254   }, win);
   255   return deferred.promise;
   256 }
   258 function promiseManagerOpen() {
   259   info("Waiting for the search manager window to open...");
   260   let deferred = Promise.defer();
   261   let winWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"].
   262                    getService(Ci.nsIWindowWatcher);
   263   winWatcher.registerNotification(function onWin(subj, topic, data) {
   264     if (topic == "domwindowopened" && subj instanceof Ci.nsIDOMWindow) {
   265       subj.addEventListener("load", function onLoad() {
   266         subj.removeEventListener("load", onLoad);
   267         if (subj.document.documentURI ==
   268             "chrome://browser/content/search/engineManager.xul") {
   269           winWatcher.unregisterNotification(onWin);
   270           ok(true, "Observed search manager window opened");
   271           is(subj.opener, gWindow,
   272              "Search engine manager opener should be the chrome browser " +
   273              "window containing the newtab page");
   274           executeSoon(() => {
   275             subj.close();
   276             deferred.resolve();
   277           });
   278         }
   279       });
   280     }
   281   });
   282   return deferred.promise;
   283 }
   285 function searchPanel() {
   286   return $("panel");
   287 }
   289 function logoImg() {
   290   return $("logo");
   291 }
   293 function gSearch() {
   294   return getContentWindow().gSearch;
   295 }

mercurial