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.

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

mercurial