| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 cr.define('settings_search_engines_page', function() { |
| 6 /** |
| 7 * TODO(dpapad): Similar class exists in webui_resource_async_browsertest.js. |
| 8 * Move somewhere else and re-use. |
| 9 * @constructor |
| 10 */ |
| 11 var PromiseResolver = function() { |
| 12 this.promise = new Promise(function(resolve, reject) { |
| 13 this.resolve = resolve; |
| 14 this.reject = reject; |
| 15 }.bind(this)); |
| 16 }; |
| 17 |
| 18 // See |defineTestBrowserProxy| function below (this class can only be defined |
| 19 // after search_engines_browser_proxy.html has been imported. |
| 20 var TestSearchEnginesBrowserProxy = null; |
| 21 |
| 22 /** |
| 23 * @return {!Promise} A promise resolved after the |
| 24 * TestSearchEnginesBrowserProxy class is defined. |
| 25 */ |
| 26 function defineTestBrowserProxy() { |
| 27 if (TestSearchEnginesBrowserProxy != null) |
| 28 return Promise.resolve(); |
| 29 |
| 30 var browserProxyImportPath = |
| 31 'chrome://md-settings/search_engines_page/search_engines_browser_proxy.h
tml'; |
| 32 return PolymerTest.importHtml(browserProxyImportPath).then(function() { |
| 33 /** |
| 34 * A test version of SearchEnginesBrowserProxy. Provides helper methods fo
r |
| 35 * allowing tests to know when a method was called, as well as specifying |
| 36 * mock responses. |
| 37 * |
| 38 * @constructor |
| 39 * @extends {settings.SearchEnginesBrowserProxy} |
| 40 */ |
| 41 TestSearchEnginesBrowserProxy = function() { |
| 42 /** @private {!Map<string, !PromiseResolver>} */ |
| 43 this.resolverMap_ = this.buildResolverMap_(); |
| 44 |
| 45 /** @private {!SearchEnginesInfo} */ |
| 46 this.searchEnginesInfo_ = {}; |
| 47 }; |
| 48 |
| 49 TestSearchEnginesBrowserProxy.prototype = { |
| 50 __proto__: settings.SearchEnginesBrowserProxy.prototype, |
| 51 |
| 52 /** |
| 53 * @return {!Map<string, !PromiseResolver>} |
| 54 * @private |
| 55 */ |
| 56 buildResolverMap_: function() { |
| 57 var resolverMap = new Map(); |
| 58 var wrapperMethods = [ |
| 59 'getSearchEnginesList', |
| 60 'removeSearchEngine', |
| 61 'searchEngineEditCancelled', |
| 62 'searchEngineEditCompleted', |
| 63 'searchEngineEditStarted', |
| 64 'setDefaultSearchEngine', |
| 65 'validateSearchEngineInput', |
| 66 ]; |
| 67 wrapperMethods.forEach(function(methodName) { |
| 68 resolverMap.set(methodName, new PromiseResolver()); |
| 69 }); |
| 70 return resolverMap; |
| 71 }, |
| 72 |
| 73 /** |
| 74 * @param {string} methodName |
| 75 * @return {!Promise} A promise that is resolved when the given method i
s |
| 76 * called. |
| 77 */ |
| 78 whenCalled: function(methodName) { |
| 79 return this.resolverMap_.get(methodName).promise; |
| 80 }, |
| 81 |
| 82 /** |
| 83 * Resets the PromiseResolver associated with the given method. |
| 84 * @param {string} methodName |
| 85 */ |
| 86 resetResolver: function(methodName) { |
| 87 this.resolverMap_.set(methodName, new PromiseResolver()); |
| 88 }, |
| 89 |
| 90 /** @override */ |
| 91 setDefaultSearchEngine: function(modelIndex) { |
| 92 this.resolverMap_.get('setDefaultSearchEngine').resolve(modelIndex); |
| 93 }, |
| 94 |
| 95 /** @override */ |
| 96 removeSearchEngine: function(modelIndex) { |
| 97 this.resolverMap_.get('removeSearchEngine').resolve(modelIndex); |
| 98 }, |
| 99 |
| 100 /** @override */ |
| 101 searchEngineEditStarted: function(modelIndex) { |
| 102 this.resolverMap_.get('searchEngineEditStarted').resolve(modelIndex); |
| 103 }, |
| 104 |
| 105 /** @override */ |
| 106 searchEngineEditCancelled: function() { |
| 107 this.resolverMap_.get('searchEngineEditCancelled').resolve(); |
| 108 }, |
| 109 |
| 110 /** @override */ |
| 111 searchEngineEditCompleted: function(searchEngine, keyword, queryUrl) { |
| 112 this.resolverMap_.get('searchEngineEditCompleted').resolve(); |
| 113 }, |
| 114 |
| 115 /** |
| 116 * Sets the response to be returned by |getSearchEnginesList|. |
| 117 * @param {!SearchEnginesInfo} |
| 118 */ |
| 119 setGetSearchEnginesList: function(searchEnginesInfo) { |
| 120 this.searchEnginesInfo_ = searchEnginesInfo; |
| 121 }, |
| 122 |
| 123 /** @override */ |
| 124 getSearchEnginesList: function() { |
| 125 this.resolverMap_.get('getSearchEnginesList').resolve(); |
| 126 return Promise.resolve(this.searchEnginesInfo_); |
| 127 }, |
| 128 |
| 129 /** @override */ |
| 130 validateSearchEngineInput: function(fieldName, fieldValue) { |
| 131 this.resolverMap_.get('validateSearchEngineInput').resolve(); |
| 132 return Promise.resolve(true); |
| 133 }, |
| 134 }; |
| 135 }); |
| 136 } |
| 137 |
| 138 /** @return {!SearchEngine} */ |
| 139 var getSampleSearchEngine = function() { |
| 140 return { |
| 141 canBeDefault: false, |
| 142 canBeEdited: true, |
| 143 canBeRemoved: false, |
| 144 default: false, |
| 145 displayName: "Google", |
| 146 iconURL: "http://www.google.com/favicon.ico", |
| 147 isOmniboxExtension: false, |
| 148 keyword: "google.com", |
| 149 modelIndex: 0, |
| 150 name: "Google", |
| 151 url: "https://search.foo.com/search?p=%s", |
| 152 urlLocked: false, |
| 153 }; |
| 154 }; |
| 155 |
| 156 |
| 157 function registerDialogTests() { |
| 158 suite('AddSearchEngineDialogTests', function() { |
| 159 /** @type {?SettingsAddSearchEngineDialog} */ |
| 160 var dialog = null; |
| 161 var browserProxy = null; |
| 162 |
| 163 suiteSetup(function() { |
| 164 return Promise.all([ |
| 165 defineTestBrowserProxy(), |
| 166 PolymerTest.importHtml('chrome://md-settings/i18n_setup.html'), |
| 167 PolymerTest.importHtml( |
| 168 'chrome://md-settings/search_engines_page/search_engine_dialog.htm
l'), |
| 169 ]); |
| 170 }); |
| 171 |
| 172 setup(function() { |
| 173 browserProxy = new TestSearchEnginesBrowserProxy(); |
| 174 settings.SearchEnginesBrowserProxy.instance_ = browserProxy; |
| 175 PolymerTest.clearBody(); |
| 176 dialog = document.createElement('settings-search-engine-dialog'); |
| 177 document.body.appendChild(dialog); |
| 178 }); |
| 179 |
| 180 teardown(function() { dialog.remove(); }); |
| 181 |
| 182 // Tests that the dialog calls 'searchEngineEditStarted' and |
| 183 // 'searchEngineEditCancelled' when closed from the 'x' button. |
| 184 test('DialogOpenAndClose', function() { |
| 185 return browserProxy.whenCalled('searchEngineEditStarted').then( |
| 186 function() { |
| 187 MockInteractions.tap(dialog.$.close); |
| 188 return browserProxy.whenCalled('searchEngineEditCancelled'); |
| 189 }); |
| 190 }); |
| 191 |
| 192 // Tests that the dialog calls 'searchEngineEditStarted' and |
| 193 // 'searchEngineEditCancelled' when closed from the 'cancel' button. |
| 194 test('DialogOpenAndCancel', function() { |
| 195 return browserProxy.whenCalled('searchEngineEditStarted').then( |
| 196 function() { |
| 197 MockInteractions.tap(dialog.$.cancel); |
| 198 return browserProxy.whenCalled('searchEngineEditCancelled'); |
| 199 }); |
| 200 }); |
| 201 |
| 202 // Tests the dialog to add a new search engine. Specifically |
| 203 // - paper-input elements are empty initially. |
| 204 // - action button initially disabled. |
| 205 // - validation is triggered on 'focus'. 'change' is not teted because |
| 206 // MockInteractions does not currently provide a way to trigger such |
| 207 // events. |
| 208 // - action button is enabled when all fields are valid. |
| 209 // - action button triggers appropriate browser signal when tapped. |
| 210 test('DialogAddSearchEngine', function() { |
| 211 /** |
| 212 * Asserts that the given paper-input element is empty. |
| 213 * @param {string} inputId |
| 214 */ |
| 215 var assertInputEmpty = function(inputId) { |
| 216 var inputElement = dialog.$[inputId]; |
| 217 assertTrue(!!inputElement); |
| 218 assertEquals(0, inputElement.value.length); |
| 219 }; |
| 220 |
| 221 /** |
| 222 * Asserts that the given paper-input element triggers validation when |
| 223 * focused. |
| 224 * @param {string} inputId |
| 225 * @return {!Promise} A promise firing when assertion has completed. |
| 226 */ |
| 227 var assertInputValidation = function(inputId) { |
| 228 browserProxy.resetResolver('validateSearchEngineInput'); |
| 229 MockInteractions.focus(dialog.$[inputId]); |
| 230 return browserProxy.whenCalled('validateSearchEngineInput'); |
| 231 }; |
| 232 |
| 233 assertInputEmpty('searchEngine'); |
| 234 assertInputEmpty('keyword'); |
| 235 assertInputEmpty('queryUrl'); |
| 236 var actionButton = dialog.$.actionButton; |
| 237 assertTrue(actionButton.disabled); |
| 238 |
| 239 return assertInputValidation('searchEngine').then(function() { |
| 240 return assertInputValidation('keyword'); |
| 241 }).then(function() { |
| 242 return assertInputValidation('queryUrl'); |
| 243 }).then(function() { |
| 244 // Manually set the text to a non-empty string for all fields. |
| 245 dialog.$.searchEngine.value = 'foo'; |
| 246 dialog.$.keyword.value = 'bar'; |
| 247 dialog.$.queryUrl.value = 'baz'; |
| 248 |
| 249 // MockInteractions does not provide a way to trigger a 'change' event |
| 250 // yet. Triggering the 'focus' event instead, to update the state of |
| 251 // the action button. |
| 252 return assertInputValidation('searchEngine'); |
| 253 }).then(function() { |
| 254 // Assert that the action button has been enabled now that all input |
| 255 // is valid and non-empty. |
| 256 assertFalse(actionButton.disabled); |
| 257 MockInteractions.tap(actionButton); |
| 258 return browserProxy.whenCalled('searchEngineEditCompleted'); |
| 259 }); |
| 260 }); |
| 261 |
| 262 }); |
| 263 } |
| 264 |
| 265 function registerEntryTests() { |
| 266 suite('SearchEngineEntryTests', function() { |
| 267 /** @type {?SettingsSearchEngineEntryElement} */ |
| 268 var entry = null; |
| 269 |
| 270 var browserProxy = null; |
| 271 |
| 272 suiteSetup(function() { |
| 273 return Promise.all([ |
| 274 defineTestBrowserProxy(), |
| 275 PolymerTest.importHtml( |
| 276 'chrome://md-settings/search_engines_page/search_engine_entry.html
'), |
| 277 ]); |
| 278 }); |
| 279 |
| 280 setup(function() { |
| 281 browserProxy = new TestSearchEnginesBrowserProxy(); |
| 282 settings.SearchEnginesBrowserProxy.instance_ = browserProxy; |
| 283 PolymerTest.clearBody(); |
| 284 entry = document.createElement('settings-search-engine-entry'); |
| 285 entry.set('engine', getSampleSearchEngine()); |
| 286 document.body.appendChild(entry); |
| 287 }); |
| 288 |
| 289 teardown(function() { entry.remove(); }); |
| 290 |
| 291 test('RemoveSearchEngine', function() { |
| 292 var deleteButton = entry.$.delete; |
| 293 assertTrue(!!deleteButton); |
| 294 MockInteractions.tap(deleteButton); |
| 295 return browserProxy.whenCalled('removeSearchEngine').then( |
| 296 function(modelIndex) { |
| 297 assertEquals(entry.engine.modelIndex, modelIndex); |
| 298 }); |
| 299 }); |
| 300 |
| 301 test('MakeDefault', function() { |
| 302 var makeDefaultButton = entry.$.makeDefault; |
| 303 assertTrue(!!makeDefaultButton); |
| 304 MockInteractions.tap(makeDefaultButton); |
| 305 return browserProxy.whenCalled('setDefaultSearchEngine').then( |
| 306 function(modelIndex) { |
| 307 assertEquals(entry.engine.modelIndex, modelIndex); |
| 308 }); |
| 309 }); |
| 310 |
| 311 // Test that the "make default" and "remove" buttons are hidden for |
| 312 // the default search engine. |
| 313 test('DefaultSearchEngineHiddenButtons', function() { |
| 314 /** |
| 315 * @param {string} buttonId |
| 316 * @param {boolean} visible |
| 317 */ |
| 318 var assertButtonVisibility = function(buttonId, visible) { |
| 319 var buttonEl = entry.$[buttonId]; |
| 320 assertTrue(!!buttonEl); |
| 321 assertEquals(!visible, buttonEl.hidden); |
| 322 }; |
| 323 assertButtonVisibility('makeDefault', true); |
| 324 assertButtonVisibility('edit', true); |
| 325 assertButtonVisibility('delete', true); |
| 326 |
| 327 // Mark the engine as the "default" one. |
| 328 var engine = getSampleSearchEngine(); |
| 329 engine.default = true; |
| 330 entry.set('engine', engine); |
| 331 |
| 332 assertButtonVisibility('makeDefault', false); |
| 333 assertButtonVisibility('edit', true); |
| 334 assertButtonVisibility('delete', false); |
| 335 }); |
| 336 |
| 337 // Test that clicking the "edit" button brings up a dialog. |
| 338 test('Edit', function() { |
| 339 var engine = entry.engine; |
| 340 var editButton = entry.$.edit; |
| 341 assertTrue(!!editButton); |
| 342 MockInteractions.tap(editButton); |
| 343 return browserProxy.whenCalled('searchEngineEditStarted').then( |
| 344 function(modelIndex) { |
| 345 assertEquals(engine.modelIndex, modelIndex); |
| 346 var dialog = entry.$$('settings-search-engine-dialog'); |
| 347 assertTrue(!!dialog); |
| 348 |
| 349 // Check that the paper-input fields are pre-populated. |
| 350 assertEquals(engine.displayName, dialog.$.searchEngine.value); |
| 351 assertEquals(engine.keyword, dialog.$.keyword.value); |
| 352 assertEquals(engine.url, dialog.$.queryUrl.value); |
| 353 |
| 354 assertFalse(dialog.$.actionButton.disabled); |
| 355 }); |
| 356 }); |
| 357 }); |
| 358 } |
| 359 |
| 360 function registerPageTests() { |
| 361 suite('SearchEnginePageTests', function() { |
| 362 /** @type {?SettingsSearchEnginesPageElement} */ |
| 363 var page = null; |
| 364 |
| 365 var browserProxy = null; |
| 366 |
| 367 /** @type {!SearchEnginesInfo} */ |
| 368 var searchEnginesInfo = { |
| 369 defaults: [getSampleSearchEngine()], |
| 370 others: [], |
| 371 extensions: [], |
| 372 }; |
| 373 |
| 374 suiteSetup(function() { |
| 375 return Promise.all([ |
| 376 defineTestBrowserProxy(), |
| 377 PolymerTest.importHtml('chrome://md-settings/i18n_setup.html'), |
| 378 PolymerTest.importHtml( |
| 379 'chrome://md-settings/search_engines_page/search_engines_page.html
'), |
| 380 ]); |
| 381 }); |
| 382 |
| 383 setup(function() { |
| 384 browserProxy = new TestSearchEnginesBrowserProxy(); |
| 385 browserProxy.setGetSearchEnginesList(searchEnginesInfo); |
| 386 settings.SearchEnginesBrowserProxy.instance_ = browserProxy; |
| 387 PolymerTest.clearBody(); |
| 388 page = document.createElement('settings-search-engines-page'); |
| 389 document.body.appendChild(page); |
| 390 }); |
| 391 |
| 392 teardown(function() { page.remove(); }); |
| 393 |
| 394 // Tests that the page is querying and displaying search engine info on |
| 395 // startup. |
| 396 test('Initialization', function() { |
| 397 return browserProxy.whenCalled('getSearchEnginesList').then(function() { |
| 398 var searchEnginesLists = Polymer.dom(page.shadowRoot). |
| 399 querySelectorAll('settings-search-engines-list'); |
| 400 assertEquals(2, searchEnginesLists.length); |
| 401 |
| 402 Polymer.dom.flush(); |
| 403 var defaultsList = searchEnginesLists[0]; |
| 404 var defaultsEntries = Polymer.dom(defaultsList.shadowRoot). |
| 405 querySelectorAll('settings-search-engine-entry'); |
| 406 assertEquals( |
| 407 searchEnginesInfo.defaults.length, defaultsEntries.length); |
| 408 |
| 409 var othersList = searchEnginesLists[1]; |
| 410 var othersEntries = Polymer.dom(othersList.shadowRoot). |
| 411 querySelectorAll('settings-search-engine-entry'); |
| 412 assertEquals( |
| 413 searchEnginesInfo.others.length, othersEntries.length); |
| 414 }); |
| 415 }); |
| 416 |
| 417 // Tests that the add search engine dialog opens when the corresponding |
| 418 // button is tapped. |
| 419 test('AddSearchEngineDialog', function() { |
| 420 assertFalse(!!page.$$('settings-search-engine-dialog')); |
| 421 var addSearchEngineButton = page.$['addSearchEngine']; |
| 422 assertTrue(!!addSearchEngineButton); |
| 423 |
| 424 MockInteractions.tap(addSearchEngineButton); |
| 425 Polymer.dom.flush(); |
| 426 assertTrue(!!page.$$('settings-search-engine-dialog')); |
| 427 }); |
| 428 }); |
| 429 } |
| 430 |
| 431 return { |
| 432 registerDialogTests: registerDialogTests, |
| 433 registerEntryTests: registerEntryTests, |
| 434 registerPageTests: registerPageTests, |
| 435 }; |
| 436 }); |
| OLD | NEW |