Chromium Code Reviews| 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 /** | |
| 19 * A test version of SearchEnginesBrowserProxy. Provides helper methods | |
| 20 * for allowing tests to know when a method was called, as well as | |
| 21 * specifying mock responses. | |
| 22 * | |
| 23 * @constructor | |
| 24 * @implements {settings.SearchEnginesBrowserProxy} | |
| 25 */ | |
| 26 var TestSearchEnginesBrowserProxy = function() { | |
| 27 /** @private {!Map<string, !PromiseResolver>} */ | |
| 28 this.resolverMap_ = new Map(); | |
| 29 var wrapperMethods = [ | |
| 30 'getSearchEnginesList', | |
| 31 'removeSearchEngine', | |
| 32 'searchEngineEditCancelled', | |
| 33 'searchEngineEditCompleted', | |
| 34 'searchEngineEditStarted', | |
| 35 'setDefaultSearchEngine', | |
| 36 'validateSearchEngineInput', | |
| 37 ]; | |
| 38 wrapperMethods.forEach(this.resetResolver.bind(this)); | |
|
Dan Beam
2016/02/18 23:27:41
nit: wrapperMethods.forEach(this.resetResolver, th
dpapad
2016/02/18 23:45:47
Done.
| |
| 39 | |
| 40 /** @private {!SearchEnginesInfo} */ | |
| 41 this.searchEnginesInfo_ = {}; | |
|
Dan Beam
2016/02/18 23:27:41
i'd say this should be
/** @private {?SearchEng
dpapad
2016/02/18 23:45:47
Done.
| |
| 42 }; | |
| 43 | |
| 44 TestSearchEnginesBrowserProxy.prototype = { | |
| 45 /** | |
| 46 * @param {string} methodName | |
| 47 * @return {!Promise} A promise that is resolved when the given method | |
| 48 * is called. | |
| 49 */ | |
| 50 whenCalled: function(methodName) { | |
| 51 return this.resolverMap_.get(methodName).promise; | |
| 52 }, | |
| 53 | |
| 54 /** | |
| 55 * Resets the PromiseResolver associated with the given method. | |
| 56 * @param {string} methodName | |
| 57 */ | |
| 58 resetResolver: function(methodName) { | |
| 59 this.resolverMap_.set(methodName, new PromiseResolver()); | |
| 60 }, | |
| 61 | |
| 62 /** @override */ | |
| 63 setDefaultSearchEngine: function(modelIndex) { | |
| 64 this.resolverMap_.get('setDefaultSearchEngine').resolve(modelIndex); | |
| 65 }, | |
| 66 | |
| 67 /** @override */ | |
| 68 removeSearchEngine: function(modelIndex) { | |
| 69 this.resolverMap_.get('removeSearchEngine').resolve(modelIndex); | |
| 70 }, | |
| 71 | |
| 72 /** @override */ | |
| 73 searchEngineEditStarted: function(modelIndex) { | |
| 74 this.resolverMap_.get('searchEngineEditStarted').resolve(modelIndex); | |
| 75 }, | |
| 76 | |
| 77 /** @override */ | |
| 78 searchEngineEditCancelled: function() { | |
| 79 this.resolverMap_.get('searchEngineEditCancelled').resolve(); | |
| 80 }, | |
| 81 | |
| 82 /** @override */ | |
| 83 searchEngineEditCompleted: function(searchEngine, keyword, queryUrl) { | |
| 84 this.resolverMap_.get('searchEngineEditCompleted').resolve(); | |
| 85 }, | |
| 86 | |
| 87 /** | |
| 88 * Sets the response to be returned by |getSearchEnginesList|. | |
| 89 * @param {!SearchEnginesInfo} | |
| 90 */ | |
| 91 setSearchEnginesInfo: function(searchEnginesInfo) { | |
| 92 this.searchEnginesInfo_ = searchEnginesInfo; | |
| 93 }, | |
| 94 | |
| 95 /** @override */ | |
| 96 getSearchEnginesList: function() { | |
| 97 this.resolverMap_.get('getSearchEnginesList').resolve(); | |
| 98 return Promise.resolve(this.searchEnginesInfo_); | |
|
Dan Beam
2016/02/18 23:27:41
if you end up making this.searchEnginesInfo_ = nul
dpapad
2016/02/18 23:45:47
I went with the non-null approach.
| |
| 99 }, | |
| 100 | |
| 101 /** @override */ | |
| 102 validateSearchEngineInput: function(fieldName, fieldValue) { | |
| 103 this.resolverMap_.get('validateSearchEngineInput').resolve(); | |
| 104 return Promise.resolve(true); | |
| 105 }, | |
| 106 }; | |
| 107 | |
| 108 /** @return {!SearchEngine} */ | |
| 109 var createSampleSearchEngine = function() { | |
| 110 return { | |
| 111 canBeDefault: false, | |
| 112 canBeEdited: true, | |
| 113 canBeRemoved: false, | |
| 114 default: false, | |
| 115 displayName: "Google", | |
| 116 iconURL: "http://www.google.com/favicon.ico", | |
| 117 isOmniboxExtension: false, | |
| 118 keyword: "google.com", | |
| 119 modelIndex: 0, | |
| 120 name: "Google", | |
| 121 url: "https://search.foo.com/search?p=%s", | |
| 122 urlLocked: false, | |
| 123 }; | |
| 124 }; | |
| 125 | |
| 126 function registerDialogTests() { | |
| 127 suite('AddSearchEngineDialogTests', function() { | |
| 128 /** @type {?SettingsAddSearchEngineDialog} */ | |
| 129 var dialog = null; | |
| 130 var browserProxy = null; | |
| 131 | |
| 132 setup(function() { | |
| 133 browserProxy = new TestSearchEnginesBrowserProxy(); | |
| 134 settings.SearchEnginesBrowserProxyImpl.instance_ = browserProxy; | |
| 135 PolymerTest.clearBody(); | |
| 136 dialog = document.createElement('settings-search-engine-dialog'); | |
| 137 document.body.appendChild(dialog); | |
| 138 }); | |
| 139 | |
| 140 teardown(function() { dialog.remove(); }); | |
| 141 | |
| 142 // Tests that the dialog calls 'searchEngineEditStarted' and | |
| 143 // 'searchEngineEditCancelled' when closed from the 'x' button. | |
| 144 test('DialogOpenAndClose', function() { | |
| 145 return browserProxy.whenCalled('searchEngineEditStarted').then( | |
| 146 function() { | |
| 147 MockInteractions.tap(dialog.$.close); | |
| 148 return browserProxy.whenCalled('searchEngineEditCancelled'); | |
| 149 }); | |
| 150 }); | |
| 151 | |
| 152 // Tests that the dialog calls 'searchEngineEditStarted' and | |
| 153 // 'searchEngineEditCancelled' when closed from the 'cancel' button. | |
| 154 test('DialogOpenAndCancel', function() { | |
| 155 return browserProxy.whenCalled('searchEngineEditStarted').then( | |
| 156 function() { | |
| 157 MockInteractions.tap(dialog.$.cancel); | |
| 158 return browserProxy.whenCalled('searchEngineEditCancelled'); | |
| 159 }); | |
| 160 }); | |
| 161 | |
| 162 // Tests the dialog to add a new search engine. Specifically | |
| 163 // - paper-input elements are empty initially. | |
| 164 // - action button initially disabled. | |
| 165 // - validation is triggered on 'focus'. 'change' is not teted because | |
| 166 // MockInteractions does not currently provide a way to trigger such | |
| 167 // events. | |
| 168 // - action button is enabled when all fields are valid. | |
| 169 // - action button triggers appropriate browser signal when tapped. | |
| 170 test('DialogAddSearchEngine', function() { | |
| 171 /** | |
| 172 * Asserts that the given paper-input element is empty. | |
| 173 * @param {string} inputId | |
| 174 */ | |
| 175 var assertInputEmpty = function(inputId) { | |
| 176 var inputElement = dialog.$[inputId]; | |
| 177 assertTrue(!!inputElement); | |
| 178 assertEquals(0, inputElement.value.length); | |
| 179 }; | |
| 180 | |
| 181 /** | |
| 182 * Asserts that the given paper-input element triggers validation when | |
| 183 * focused. | |
|
Dan Beam
2016/02/18 23:27:41
nit: update description now
dpapad
2016/02/18 23:45:47
Done.
| |
| 184 * @param {string} inputId | |
| 185 * @return {!Promise} A promise firing when assertion has completed. | |
| 186 */ | |
| 187 var focusAndValidate = function(inputId) { | |
| 188 browserProxy.resetResolver('validateSearchEngineInput'); | |
| 189 MockInteractions.focus(dialog.$[inputId]); | |
| 190 return browserProxy.whenCalled('validateSearchEngineInput'); | |
| 191 }; | |
| 192 | |
| 193 assertInputEmpty('searchEngine'); | |
|
Dan Beam
2016/02/18 23:27:41
nit:
assertEquals('', dialog.$.searchEngine.val
dpapad
2016/02/18 23:45:47
Done.
| |
| 194 assertInputEmpty('keyword'); | |
| 195 assertInputEmpty('queryUrl'); | |
| 196 var actionButton = dialog.$.actionButton; | |
| 197 assertTrue(actionButton.disabled); | |
| 198 | |
| 199 return focusAndValidate('searchEngine').then(function() { | |
| 200 return focusAndValidate('keyword'); | |
| 201 }).then(function() { | |
| 202 return focusAndValidate('queryUrl'); | |
| 203 }).then(function() { | |
| 204 // Manually set the text to a non-empty string for all fields. | |
| 205 dialog.$.searchEngine.value = 'foo'; | |
| 206 dialog.$.keyword.value = 'bar'; | |
| 207 dialog.$.queryUrl.value = 'baz'; | |
| 208 | |
| 209 // MockInteractions does not provide a way to trigger a 'change' event | |
| 210 // yet. Triggering the 'focus' event instead, to update the state of | |
| 211 // the action button. | |
| 212 return focusAndValidate('searchEngine'); | |
| 213 }).then(function() { | |
| 214 // Assert that the action button has been enabled now that all input | |
| 215 // is valid and non-empty. | |
| 216 assertFalse(actionButton.disabled); | |
| 217 MockInteractions.tap(actionButton); | |
| 218 return browserProxy.whenCalled('searchEngineEditCompleted'); | |
| 219 }); | |
| 220 }); | |
| 221 | |
| 222 }); | |
| 223 } | |
| 224 | |
| 225 function registerEntryTests() { | |
| 226 suite('SearchEngineEntryTests', function() { | |
| 227 /** @type {?SettingsSearchEngineEntryElement} */ | |
| 228 var entry = null; | |
| 229 | |
| 230 var browserProxy = null; | |
| 231 | |
| 232 setup(function() { | |
| 233 browserProxy = new TestSearchEnginesBrowserProxy(); | |
| 234 settings.SearchEnginesBrowserProxyImpl.instance_ = browserProxy; | |
| 235 PolymerTest.clearBody(); | |
| 236 entry = document.createElement('settings-search-engine-entry'); | |
| 237 entry.set('engine', createSampleSearchEngine()); | |
| 238 document.body.appendChild(entry); | |
| 239 }); | |
| 240 | |
| 241 teardown(function() { entry.remove(); }); | |
| 242 | |
| 243 test('RemoveSearchEngine', function() { | |
| 244 var deleteButton = entry.$.delete; | |
| 245 assertTrue(!!deleteButton); | |
| 246 MockInteractions.tap(deleteButton); | |
| 247 return browserProxy.whenCalled('removeSearchEngine').then( | |
| 248 function(modelIndex) { | |
| 249 assertEquals(entry.engine.modelIndex, modelIndex); | |
| 250 }); | |
| 251 }); | |
| 252 | |
| 253 test('MakeDefault', function() { | |
| 254 var makeDefaultButton = entry.$.makeDefault; | |
| 255 assertTrue(!!makeDefaultButton); | |
| 256 MockInteractions.tap(makeDefaultButton); | |
| 257 return browserProxy.whenCalled('setDefaultSearchEngine').then( | |
| 258 function(modelIndex) { | |
| 259 assertEquals(entry.engine.modelIndex, modelIndex); | |
| 260 }); | |
| 261 }); | |
| 262 | |
| 263 // Test that the "make default" and "remove" buttons are hidden for | |
| 264 // the default search engine. | |
| 265 test('DefaultSearchEngineHiddenButtons', function() { | |
| 266 assertFalse(entry.$.makeDefault.hidden); | |
| 267 assertFalse(entry.$.edit.hidden); | |
| 268 assertFalse(entry.$.delete.hidden); | |
| 269 | |
| 270 // Mark the engine as the "default" one. | |
| 271 var engine = createSampleSearchEngine(); | |
| 272 engine.default = true; | |
| 273 entry.set('engine', engine); | |
| 274 Polymer.dom.flush(); | |
| 275 | |
| 276 assertTrue(entry.$.makeDefault.hidden); | |
| 277 assertFalse(entry.$.edit.hidden); | |
| 278 assertTrue(entry.$.delete.hidden); | |
| 279 }); | |
| 280 | |
| 281 // Test that clicking the "edit" button brings up a dialog. | |
| 282 test('Edit', function() { | |
| 283 var engine = entry.engine; | |
| 284 var editButton = entry.$.edit; | |
| 285 assertTrue(!!editButton); | |
| 286 MockInteractions.tap(editButton); | |
| 287 return browserProxy.whenCalled('searchEngineEditStarted').then( | |
| 288 function(modelIndex) { | |
| 289 assertEquals(engine.modelIndex, modelIndex); | |
| 290 var dialog = entry.$$('settings-search-engine-dialog'); | |
| 291 assertTrue(!!dialog); | |
| 292 | |
| 293 // Check that the paper-input fields are pre-populated. | |
| 294 assertEquals(engine.displayName, dialog.$.searchEngine.value); | |
| 295 assertEquals(engine.keyword, dialog.$.keyword.value); | |
| 296 assertEquals(engine.url, dialog.$.queryUrl.value); | |
| 297 | |
| 298 assertFalse(dialog.$.actionButton.disabled); | |
| 299 }); | |
| 300 }); | |
| 301 }); | |
| 302 } | |
| 303 | |
| 304 function registerPageTests() { | |
| 305 suite('SearchEnginePageTests', function() { | |
| 306 /** @type {?SettingsSearchEnginesPageElement} */ | |
| 307 var page = null; | |
| 308 | |
| 309 var browserProxy = null; | |
| 310 | |
| 311 /** @type {!SearchEnginesInfo} */ | |
| 312 var searchEnginesInfo = { | |
| 313 defaults: [createSampleSearchEngine()], | |
| 314 others: [], | |
| 315 extensions: [], | |
| 316 }; | |
| 317 | |
| 318 setup(function() { | |
| 319 browserProxy = new TestSearchEnginesBrowserProxy(); | |
| 320 browserProxy.setSearchEnginesInfo(searchEnginesInfo); | |
| 321 settings.SearchEnginesBrowserProxyImpl.instance_ = browserProxy; | |
| 322 PolymerTest.clearBody(); | |
| 323 page = document.createElement('settings-search-engines-page'); | |
| 324 document.body.appendChild(page); | |
| 325 }); | |
| 326 | |
| 327 teardown(function() { page.remove(); }); | |
| 328 | |
| 329 // Tests that the page is querying and displaying search engine info on | |
| 330 // startup. | |
| 331 test('Initialization', function() { | |
| 332 return browserProxy.whenCalled('getSearchEnginesList').then(function() { | |
| 333 var searchEnginesLists = Polymer.dom(page.shadowRoot). | |
| 334 querySelectorAll('settings-search-engines-list'); | |
| 335 assertEquals(2, searchEnginesLists.length); | |
| 336 | |
| 337 Polymer.dom.flush(); | |
| 338 var defaultsList = searchEnginesLists[0]; | |
| 339 var defaultsEntries = Polymer.dom(defaultsList.shadowRoot). | |
| 340 querySelectorAll('settings-search-engine-entry'); | |
| 341 assertEquals( | |
| 342 searchEnginesInfo.defaults.length, defaultsEntries.length); | |
| 343 | |
| 344 var othersList = searchEnginesLists[1]; | |
| 345 var othersEntries = Polymer.dom(othersList.shadowRoot). | |
| 346 querySelectorAll('settings-search-engine-entry'); | |
| 347 assertEquals( | |
| 348 searchEnginesInfo.others.length, othersEntries.length); | |
| 349 }); | |
| 350 }); | |
| 351 | |
| 352 // Tests that the add search engine dialog opens when the corresponding | |
| 353 // button is tapped. | |
| 354 test('AddSearchEngineDialog', function() { | |
| 355 assertFalse(!!page.$$('settings-search-engine-dialog')); | |
| 356 var addSearchEngineButton = page.$.addSearchEngine; | |
| 357 assertTrue(!!addSearchEngineButton); | |
| 358 | |
| 359 MockInteractions.tap(addSearchEngineButton); | |
| 360 Polymer.dom.flush(); | |
| 361 assertTrue(!!page.$$('settings-search-engine-dialog')); | |
| 362 }); | |
| 363 }); | |
| 364 } | |
| 365 | |
| 366 return { | |
| 367 registerDialogTests: registerDialogTests, | |
| 368 registerEntryTests: registerEntryTests, | |
| 369 registerPageTests: registerPageTests, | |
| 370 }; | |
| 371 }); | |
| OLD | NEW |