| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 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 GEN('#if defined(OS_CHROMEOS)'); | |
| 6 | |
| 7 GEN_INCLUDE(['../options_browsertest_base.js']); | |
| 8 | |
| 9 function BluetoothWebUITestAsync() {} | |
| 10 | |
| 11 BluetoothWebUITestAsync.prototype = { | |
| 12 __proto__: OptionsBrowsertestBase.prototype, | |
| 13 | |
| 14 /** @override */ | |
| 15 isAsync: true, | |
| 16 | |
| 17 /** | |
| 18 * Start tests from the main-settings page. | |
| 19 */ | |
| 20 browsePreload: 'chrome://settings-frame/', | |
| 21 | |
| 22 // These entries match the fake entries in FakeBluetoothDeviceClient. | |
| 23 fakePairedDevice: { | |
| 24 address: '00:11:22:33:44:55', | |
| 25 connectable: true, | |
| 26 connected: false, | |
| 27 name: 'Fake Device (name)', | |
| 28 paired: true | |
| 29 }, | |
| 30 | |
| 31 fakePairedDevice2: { | |
| 32 address: '20:7D:74:00:00:04', | |
| 33 connectable: false, | |
| 34 connected: false, | |
| 35 name: 'Paired Unconnectable Device (name)', | |
| 36 paired: true | |
| 37 }, | |
| 38 | |
| 39 fakeUnpairedDevice: { | |
| 40 address: '28:CF:DA:00:00:00', | |
| 41 connectable: true, | |
| 42 connected: false, | |
| 43 name: 'Bluetooth 2.0 Mouse', | |
| 44 paired: false | |
| 45 }, | |
| 46 | |
| 47 fakeUnpairedDevice2: { | |
| 48 address: '00:24:BE:00:00:00', | |
| 49 connectable: true, | |
| 50 connected: false, | |
| 51 name: 'PIN Device', | |
| 52 paired: false | |
| 53 }, | |
| 54 | |
| 55 /** @override */ | |
| 56 setUp: function() { | |
| 57 OptionsBrowsertestBase.prototype.setUp.call(this); | |
| 58 | |
| 59 var unsupportedAriaAttributeSelectors = [ | |
| 60 '#bluetooth-paired-devices-list', | |
| 61 '#bluetooth-unpaired-devices-list', | |
| 62 ]; | |
| 63 | |
| 64 // Enable when failure is resolved. | |
| 65 // AX_ARIA_10: http://crbug.com/570564 | |
| 66 this.accessibilityAuditConfig.ignoreSelectors( | |
| 67 'unsupportedAriaAttribute', | |
| 68 unsupportedAriaAttributeSelectors); | |
| 69 }, | |
| 70 | |
| 71 /** | |
| 72 * Retrieves the list item associated with a Bluetooth device. | |
| 73 * @param {!Element} listElement Element containing a list of devices. | |
| 74 * @param {string} deviceName The name of the device. | |
| 75 * @return {Element|undefined} List item matching the device name. | |
| 76 */ | |
| 77 getElementForDevice: function(listElement, deviceName) { | |
| 78 var items = listElement.querySelectorAll('.bluetooth-device'); | |
| 79 for (var i = 0; i < items.length; i++) { | |
| 80 var candidate = items[i]; | |
| 81 var name = candidate.data.name; | |
| 82 if (name == deviceName) | |
| 83 return candidate; | |
| 84 } | |
| 85 return undefined; | |
| 86 }, | |
| 87 | |
| 88 /** | |
| 89 * Selects a bluetooth device from the list with the matching address. | |
| 90 * @param {!Element} listElement A list of Bluetooth devices. | |
| 91 * @param {string} address Device address. | |
| 92 */ | |
| 93 selectDevice: function(listElement, address) { | |
| 94 listElement.setSelectedDevice_(address); | |
| 95 cr.dispatchSimpleEvent(listElement, 'change'); | |
| 96 }, | |
| 97 | |
| 98 /** | |
| 99 * Fake input of a pincode or passkey. | |
| 100 * @param {!Element} element Text input field. | |
| 101 * @param {string} text New value for the input field. | |
| 102 */ | |
| 103 fakeInput: function(element, text) { | |
| 104 element.value = text; | |
| 105 cr.dispatchSimpleEvent(element, 'input'); | |
| 106 }, | |
| 107 }; | |
| 108 | |
| 109 TEST_F('BluetoothWebUITestAsync', 'testEnableBluetooth', function() { | |
| 110 assertEquals(this.browsePreload, document.location.href); | |
| 111 expectFalse($('enable-bluetooth').checked); | |
| 112 expectTrue($('bluetooth-paired-devices-list').parentNode.hidden); | |
| 113 | |
| 114 $('enable-bluetooth').click(); | |
| 115 | |
| 116 // The UI may not be updated until all callbacks have been handled, so | |
| 117 // send a new request that will get processed after any currently pending | |
| 118 // callbacks. | |
| 119 chrome.bluetooth.getAdapterState(function(state) { | |
| 120 expectTrue(state.powered); | |
| 121 expectFalse($('bluetooth-paired-devices-list').parentNode.hidden); | |
| 122 testDone(); | |
| 123 }.bind(this)); | |
| 124 }); | |
| 125 | |
| 126 // TODO(crbug.com/603499) Test is flaky. | |
| 127 TEST_F('BluetoothWebUITestAsync', 'DISABLED_testAddDevice', function() { | |
| 128 assertEquals(this.browsePreload, document.location.href); | |
| 129 | |
| 130 // Enable bluetooth. | |
| 131 $('enable-bluetooth').click(); | |
| 132 | |
| 133 // Wait for the UI to process any pending messages. | |
| 134 window.setTimeout(function() { | |
| 135 // Wait for fake bluetooth impl to send any updates. | |
| 136 chrome.bluetooth.getAdapterState(function(state) { | |
| 137 var pairedDeviceList = $('bluetooth-paired-devices-list'); | |
| 138 var unpairedDeviceList = $('bluetooth-unpaired-devices-list'); | |
| 139 | |
| 140 // Verify that devices are in the correct list. | |
| 141 var index = pairedDeviceList.find(this.fakePairedDevice.address); | |
| 142 expectEquals(1, index); | |
| 143 index = pairedDeviceList.find(this.fakePairedDevice2.address); | |
| 144 expectEquals(0, index); | |
| 145 index = pairedDeviceList.find(this.fakeUnpairedDevice.address); | |
| 146 expectEquals(undefined, index); | |
| 147 expectTrue(!!this.getElementForDevice(pairedDeviceList, | |
| 148 this.fakePairedDevice.name)); | |
| 149 expectFalse(!!this.getElementForDevice(unpairedDeviceList, | |
| 150 this.fakePairedDevice.name)); | |
| 151 | |
| 152 // Test clicking on the 'Add a device' button. This should send a | |
| 153 // startDiscovering request. | |
| 154 $('bluetooth-add-device').click(); | |
| 155 expectFalse($('bluetooth-options').hidden); | |
| 156 | |
| 157 // Wait for fake bluetooth impl to send any updates. | |
| 158 chrome.bluetooth.getAdapterState(function(state) { | |
| 159 expectTrue(state.discovering); | |
| 160 expectFalse(unpairedDeviceList.parentNode.hidden); | |
| 161 | |
| 162 index = unpairedDeviceList.find(this.fakeUnpairedDevice.address); | |
| 163 expectEquals(0, index); | |
| 164 | |
| 165 var connectButton = $('bluetooth-add-device-apply-button'); | |
| 166 expectTrue(connectButton.disabled); | |
| 167 expectFalse($('bluetooth-add-device-cancel-button').disabled); | |
| 168 | |
| 169 // Test selecting an element and clicking on the connect button. | |
| 170 this.selectDevice(unpairedDeviceList, this.fakeUnpairedDevice.address); | |
| 171 expectFalse(connectButton.disabled); | |
| 172 connectButton.click(); | |
| 173 | |
| 174 // Wait for fake bluetooth impl to send any updates. | |
| 175 chrome.bluetooth.getAdapterState(function(state) { | |
| 176 // Verify that the pairing UI is shown. | |
| 177 expectFalse($('bluetooth-pairing').hidden); | |
| 178 testDone(); | |
| 179 }.bind(this)); | |
| 180 }.bind(this)); | |
| 181 }.bind(this)); | |
| 182 }.bind(this)); | |
| 183 }); | |
| 184 | |
| 185 TEST_F('BluetoothWebUITestAsync', 'testDevicePairing', function() { | |
| 186 assertEquals(this.browsePreload, document.location.href); | |
| 187 | |
| 188 // Enable bluetooth. | |
| 189 $('enable-bluetooth').click(); | |
| 190 | |
| 191 // Wait for the UI to process any pending messages. | |
| 192 window.setTimeout(function() { | |
| 193 // Wait for fake bluetooth impl to send any updates. | |
| 194 chrome.bluetooth.getAdapterState(function(state) { | |
| 195 var pairedDeviceList = $('bluetooth-paired-devices-list'); | |
| 196 var unpairedDeviceList = $('bluetooth-unpaired-devices-list'); | |
| 197 | |
| 198 $('bluetooth-add-device').click(); | |
| 199 | |
| 200 // Wait for fake bluetooth impl to send any updates. | |
| 201 chrome.bluetooth.getAdapterState(function(state) { | |
| 202 expectFalse(unpairedDeviceList.parentNode.hidden); | |
| 203 | |
| 204 // Test selecting an element and clicking on the connect button. | |
| 205 var index = unpairedDeviceList.find(this.fakeUnpairedDevice2.address); | |
| 206 expectNotEquals(undefined, index); | |
| 207 this.selectDevice(unpairedDeviceList, this.fakeUnpairedDevice2.address); | |
| 208 var connectButton = $('bluetooth-add-device-apply-button'); | |
| 209 expectFalse(connectButton.disabled); | |
| 210 connectButton.click(); | |
| 211 | |
| 212 // Wait for fake bluetooth impl to send any updates. | |
| 213 chrome.bluetooth.getAdapterState(function(state) { | |
| 214 // Verify that the pairing UI is shown. | |
| 215 expectFalse($('bluetooth-pairing').hidden); | |
| 216 expectTrue($('bluetooth-pairing-passkey-display').hidden); | |
| 217 expectTrue($('bluetooth-pairing-passkey-entry').hidden); | |
| 218 expectFalse($('bluetooth-pairing-pincode-entry').hidden); | |
| 219 | |
| 220 var pincode = '123456'; | |
| 221 this.fakeInput($('bluetooth-pincode'), pincode); | |
| 222 $('bluetooth-pair-device-connect-button').click(); | |
| 223 | |
| 224 // Wait for fake bluetooth impl to send any updates. | |
| 225 chrome.bluetooth.getAdapterState(function(state) { | |
| 226 expectTrue($('bluetooth-pairing-pincode-entry').hidden); | |
| 227 testDone(); | |
| 228 }.bind(this)); | |
| 229 }.bind(this)); | |
| 230 }.bind(this)); | |
| 231 }.bind(this)); | |
| 232 }.bind(this)); | |
| 233 }); | |
| 234 | |
| 235 // TODO(crbug.com/608126) Test is flaky. | |
| 236 TEST_F('BluetoothWebUITestAsync', 'DISABLED_testConnect', function() { | |
| 237 assertEquals(this.browsePreload, document.location.href); | |
| 238 | |
| 239 // Enable bluetooth. | |
| 240 $('enable-bluetooth').click(); | |
| 241 | |
| 242 // Wait for the UI to process any pending messages. | |
| 243 window.setTimeout(function() { | |
| 244 // Wait for fake bluetooth impl to send any updates. | |
| 245 chrome.bluetooth.getAdapterState(function(state) { | |
| 246 var pairedDeviceList = $('bluetooth-paired-devices-list'); | |
| 247 var element = this.getElementForDevice( | |
| 248 pairedDeviceList, this.fakePairedDevice.name); | |
| 249 assertTrue(!!element, this.fakePairedDevice.name); | |
| 250 expectFalse(!!element.getAttribute('connected')); | |
| 251 | |
| 252 var connectButton = $('bluetooth-reconnect-device'); | |
| 253 expectTrue(connectButton.disabled); | |
| 254 | |
| 255 // Simulate connecting to a previously paired device. | |
| 256 this.selectDevice(pairedDeviceList, this.fakePairedDevice.address); | |
| 257 expectFalse(connectButton.disabled); | |
| 258 connectButton.click(); | |
| 259 | |
| 260 // Call bluetooth.getAdapterState to ensure that all state has been | |
| 261 // updated. | |
| 262 chrome.bluetooth.getAdapterState(function(state) { | |
| 263 element = this.getElementForDevice( | |
| 264 pairedDeviceList, this.fakePairedDevice.name); | |
| 265 expectTrue(!!element.getAttribute('connected')); | |
| 266 var deleteButton = element.querySelector('.row-delete-button'); | |
| 267 expectTrue(!!deleteButton); | |
| 268 testDone(); | |
| 269 }.bind(this)); | |
| 270 }.bind(this)); | |
| 271 }.bind(this)); | |
| 272 }); | |
| 273 | |
| 274 TEST_F('BluetoothWebUITestAsync', 'testDisconnect', function() { | |
| 275 assertEquals(this.browsePreload, document.location.href); | |
| 276 | |
| 277 // Enable bluetooth. | |
| 278 $('enable-bluetooth').click(); | |
| 279 | |
| 280 // Wait for the UI to process any pending messages. | |
| 281 window.setTimeout(function() { | |
| 282 // Wait for fake bluetooth impl to send any updates. | |
| 283 chrome.bluetooth.getAdapterState(function(state) { | |
| 284 var pairedDeviceList = $('bluetooth-paired-devices-list'); | |
| 285 | |
| 286 // First connect to the device so that the fake implementation state is | |
| 287 // connected. | |
| 288 chrome.bluetoothPrivate.connect( | |
| 289 this.fakePairedDevice.address, function(result) { | |
| 290 assertEquals( | |
| 291 chrome.bluetoothPrivate.ConnectResultType.SUCCESS, result); | |
| 292 | |
| 293 var element = this.getElementForDevice( | |
| 294 pairedDeviceList, this.fakePairedDevice.name); | |
| 295 assertTrue(!!element, this.fakePairedDevice.name); | |
| 296 expectTrue(!!element.getAttribute('connected')); | |
| 297 | |
| 298 // Simulate disconnecting from a connected device. | |
| 299 var button = element.querySelector('.row-delete-button'); | |
| 300 button.click(); | |
| 301 | |
| 302 // Wait for fake bluetooth impl to send any updates. | |
| 303 chrome.bluetooth.getAdapterState(function(state) { | |
| 304 element = this.getElementForDevice( | |
| 305 pairedDeviceList, this.fakePairedDevice.name); | |
| 306 expectFalse(!!element.getAttribute('connected')); | |
| 307 button = element.querySelector('.row-delete-button'); | |
| 308 expectTrue(!!button); | |
| 309 testDone(); | |
| 310 }.bind(this)); | |
| 311 }.bind(this)); | |
| 312 }.bind(this)); | |
| 313 }.bind(this)); | |
| 314 }); | |
| 315 | |
| 316 // TODO(crbug.com/605090): Disabled because of flakiness. | |
| 317 TEST_F('BluetoothWebUITestAsync', 'DISABLED_testForget', function() { | |
| 318 assertEquals(this.browsePreload, document.location.href); | |
| 319 | |
| 320 // Enable bluetooth. | |
| 321 $('enable-bluetooth').click(); | |
| 322 | |
| 323 // Wait for the UI to process any pending messages. | |
| 324 window.setTimeout(function() { | |
| 325 // Wait for fake bluetooth impl to send any updates. | |
| 326 chrome.bluetooth.getAdapterState(function(state) { | |
| 327 var pairedDeviceList = $('bluetooth-paired-devices-list'); | |
| 328 | |
| 329 var element = this.getElementForDevice(pairedDeviceList, | |
| 330 this.fakePairedDevice.name); | |
| 331 var button = element.querySelector('.row-delete-button'); | |
| 332 button.click(); | |
| 333 | |
| 334 // Wait for fake bluetooth impl to send any updates. | |
| 335 chrome.bluetooth.getAdapterState(function(state) { | |
| 336 expectFalse(!!this.getElementForDevice(pairedDeviceList, | |
| 337 this.fakePairedDevice.name)); | |
| 338 testDone(); | |
| 339 }.bind(this)); | |
| 340 }.bind(this)); | |
| 341 }.bind(this)); | |
| 342 }); | |
| 343 | |
| 344 | |
| 345 TEST_F('BluetoothWebUITestAsync', 'testMaliciousInput', function() { | |
| 346 assertEquals(this.browsePreload, document.location.href); | |
| 347 | |
| 348 var maliciousStrings = [ | |
| 349 '<SCRIPT>alert(1)</SCRIPT>', | |
| 350 '>\'>\\"><SCRIPT>alert(1)</SCRIPT>', | |
| 351 '<IMG SRC=\\"javascript:alert(1)\\">', | |
| 352 '<A HREF=\\"data:text/html;base64,' + | |
| 353 'PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo=\\">..</A>', | |
| 354 '<div>', | |
| 355 '<textarea>', | |
| 356 '<style>', | |
| 357 '[0xC0][0xBC]SCRIPT[0xC0][0xBE]alert(1)[0xC0][0xBC]/SCRIPT[0xC0][0xBE]', | |
| 358 '+ADw-SCRIPT+AD4-alert(1)+ADw-/SCRIPT+AD4-', | |
| 359 '&#<script>alert(1)</script>;', | |
| 360 '<!-- Hello -- world > <SCRIPT>alert(1)</SCRIPT> -->', | |
| 361 '<!<!-- Hello world > <SCRIPT>alert(1)</SCRIPT> -->', | |
| 362 '\x3CSCRIPT\x3Ealert(1)\x3C/SCRIPT\x3E', | |
| 363 '<IMG SRC=\\"j[0x00]avascript:alert(1)\\">', | |
| 364 '<BASE HREF=\\"javascript:1;/**/\\"><IMG SRC=\\"alert(1)\\">', | |
| 365 'javascript:alert(1);', | |
| 366 ' xss_injection=\\"\\" ', | |
| 367 '\\" xss_injection=\\"', | |
| 368 '\' xss_injection=\'', | |
| 369 '<!--', | |
| 370 '\'', | |
| 371 '\\"' | |
| 372 ]; | |
| 373 | |
| 374 var fakeEvent = { | |
| 375 device: { | |
| 376 address: '28:CF:DA:00:00:00', | |
| 377 connectable: true, | |
| 378 connected: false, | |
| 379 name: 'Bluetooth 2.0 Mouse', | |
| 380 paired: false | |
| 381 }, | |
| 382 pairing: 'bluetoothStartConnecting' | |
| 383 }; | |
| 384 | |
| 385 var nodeCount = function(node) { | |
| 386 if (node.getAttribute) | |
| 387 assertFalse(!!node.getAttribute('xss_injection')); | |
| 388 var length = node.childNodes.length; | |
| 389 var tally = length; | |
| 390 for (var i = 0; i < length; i++) { | |
| 391 tally += nodeCount(node.childNodes[i]); | |
| 392 } | |
| 393 return tally; | |
| 394 }; | |
| 395 | |
| 396 // Enable bluetooth. | |
| 397 $('enable-bluetooth').click(); | |
| 398 | |
| 399 // Wait for the UI to process any pending messages. | |
| 400 window.setTimeout(function() { | |
| 401 // Wait for fake bluetooth impl to send any updates. | |
| 402 chrome.bluetooth.getAdapterState(function(state) { | |
| 403 var unpairedDeviceList = $('bluetooth-unpaired-devices-list'); | |
| 404 var pairDeviceDialog = $('bluetooth-pairing'); | |
| 405 | |
| 406 // Show the pairing dialog. | |
| 407 $('bluetooth-add-device').click(); | |
| 408 BluetoothPairing.showDialog(fakeEvent); | |
| 409 | |
| 410 // Wait for fake bluetooth impl to send any updates. | |
| 411 chrome.bluetooth.getAdapterState(function(state) { | |
| 412 expectFalse(unpairedDeviceList.parentNode.hidden); | |
| 413 | |
| 414 // Determine the expected sizes. | |
| 415 var unpairedDeviceListSize = nodeCount(unpairedDeviceList); | |
| 416 var pairDeviceDialogSize = nodeCount(pairDeviceDialog); | |
| 417 | |
| 418 // Ensure that updating the device with a malicious name does not | |
| 419 // corrupt the structure of the document. Tests the unpaired device | |
| 420 // list and bluetooth pairing dialog. | |
| 421 for (var i = 0; i < maliciousStrings.length; i++) { | |
| 422 fakeEvent.device.name = maliciousStrings[i]; | |
| 423 BluetoothPairing.showDialog(fakeEvent); | |
| 424 assertEquals(unpairedDeviceListSize, nodeCount(unpairedDeviceList)); | |
| 425 var element = this.getElementForDevice( | |
| 426 unpairedDeviceList, fakeEvent.device.name); | |
| 427 assertTrue(!!element, fakeEvent.device.name); | |
| 428 var label = element.querySelector('.bluetooth-device-label'); | |
| 429 assertTrue(!!label); | |
| 430 assertEquals(maliciousStrings[i], label.textContent); | |
| 431 assertEquals(pairDeviceDialogSize, nodeCount(pairDeviceDialog)); | |
| 432 } | |
| 433 | |
| 434 testDone(); | |
| 435 }.bind(this)); | |
| 436 }.bind(this)); | |
| 437 }.bind(this)); | |
| 438 }); | |
| 439 | |
| 440 GEN('#endif'); | |
| OLD | NEW |