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.
5 GEN('#if defined(OS_CHROMEOS)');
7 function BluetoothWebUITest() {}
9 BluetoothWebUITest.prototype = {
10 __proto__: testing.Test.prototype,
13 * Start tests from the main-settings page.
15 browsePreload: 'chrome://settings-frame/',
21 this.makeAndRegisterMockHandler([
22 'bluetoothEnableChange',
23 'updateBluetoothDevice',
24 'findBluetoothDevices',
25 'stopBluetoothDeviceDiscovery',
30 * Retrieves the list item associated with a Bluetooth device.
31 * @param {!Element} listElement Element containing a list of devices.
32 * @param {string} deviceName The name of the device.
33 * @return {Element|undefined} List item matching the device name.
35 getElementForDevice: function(listElement, deviceName) {
36 var items = listElement.querySelectorAll('.bluetooth-device');
37 for (var i = 0; i < items.length; i++) {
38 var candidate = items[i];
39 var name = candidate.data.name;
40 if (name == deviceName)
46 * Selects a bluetooth device from the list with the matching address.
47 * @param {!Element} listElement A list of Bluetooth devices.
48 * @param {{address: string,
49 * connectable: boolean,
52 * paired: boolean}} device Description of the device.
54 selectDevice: function(listElement, device) {
55 listElement.selectedItem = device;
56 cr.dispatchSimpleEvent(listElement, 'change');
60 * Fake input of a pincode or passkey.
61 * @param {!Element} element Text input field.
62 * @param {string} text New value for the input field.
64 fakeInput: function(element, text) {
66 cr.dispatchSimpleEvent(element, 'input');
71 TEST_F('BluetoothWebUITest', 'testEnableBluetooth', function() {
72 assertEquals(this.browsePreload, document.location.href);
73 expectFalse($('enable-bluetooth').checked);
74 expectTrue($('bluetooth-paired-devices-list').parentNode.hidden);
76 this.mockHandler.expects(once()).bluetoothEnableChange([true]).will(
77 callFunction(function() {
78 options.BrowserOptions.setBluetoothState(true);
80 $('enable-bluetooth').click();
82 expectFalse($('bluetooth-paired-devices-list').parentNode.hidden);
85 TEST_F('BluetoothWebUITest', 'testAddDevices', function() {
86 assertEquals(this.browsePreload, document.location.href);
88 var pairedDeviceList = $('bluetooth-paired-devices-list');
89 var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
91 var fakePairedDevice = {
92 address: '00:11:22:33:44:55',
99 var fakeUnpairedDevice = {
100 address: '28:CF:DA:00:00:00',
103 name: 'Apple Magic Mouse',
107 var fakeUnpairedDevice2 = {
108 address: '28:37:37:00:00:00',
111 name: 'Apple Wireless Keyboard',
115 // Ensure data models for the paired and unpaired device lists are properly
117 var index = pairedDeviceList.find(fakePairedDevice.address);
118 expectEquals(undefined, index);
119 options.BrowserOptions.addBluetoothDevice(fakePairedDevice);
120 index = pairedDeviceList.find(fakePairedDevice.address);
121 expectEquals(0, index);
123 // Ensure the DOM contents of the list are properly updated. The default
124 // layout of a list creates DOM elements only for visible elements in the
125 // list, which is problematic if the list is hidden at the time of layout.
126 // The Bluetooth device lists overcomes this problem by using fixed sized
127 // elements in an auto-expanding list. This test ensures the problem stays
129 expectTrue(!!this.getElementForDevice(pairedDeviceList,
130 fakePairedDevice.name));
131 expectFalse(!!this.getElementForDevice(unpairedDeviceList,
132 fakePairedDevice.name));
134 options.BrowserOptions.addBluetoothDevice(fakeUnpairedDevice);
135 index = unpairedDeviceList.find(fakeUnpairedDevice.address);
136 expectEquals(0, index);
137 expectFalse(!!this.getElementForDevice(pairedDeviceList,
138 fakeUnpairedDevice.name));
139 expectTrue(!!this.getElementForDevice(unpairedDeviceList,
140 fakeUnpairedDevice.name));
142 // Test adding a second device to a list.
143 options.BrowserOptions.addBluetoothDevice(fakeUnpairedDevice2);
144 index = unpairedDeviceList.find(fakeUnpairedDevice2.address);
145 expectEquals(1, index);
146 expectTrue(!!this.getElementForDevice(unpairedDeviceList,
147 fakeUnpairedDevice2.name));
149 // Test clicking on the 'Add a device' button.
150 this.mockHandler.expects(once()).findBluetoothDevices();
151 $('bluetooth-add-device').click();
152 expectFalse($('bluetooth-options').hidden);
153 expectTrue($('bluetooth-add-device-apply-button').disabled);
154 expectFalse($('bluetooth-add-device-cancel-button').disabled);
156 Mock4JS.verifyAllMocks();
157 Mock4JS.clearMocksToVerify();
159 // Test selecting an element and clicking on the connect button.
160 this.mockHandler.expects(once()).stopBluetoothDeviceDiscovery();
161 this.mockHandler.expects(once()).updateBluetoothDevice(
162 [fakeUnpairedDevice2.address, 'connect']);
163 this.selectDevice(unpairedDeviceList, fakeUnpairedDevice2);
164 var connectButton = $('bluetooth-add-device-apply-button');
165 expectFalse(connectButton.disabled);
166 connectButton.click();
169 TEST_F('BluetoothWebUITest', 'testDevicePairing', function() {
170 assertEquals(this.browsePreload, document.location.href);
172 var pairedDeviceList = $('bluetooth-paired-devices-list');
173 var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
176 address: '00:24:BE:00:00:00',
183 options.BrowserOptions.addBluetoothDevice(fakeDevice);
184 var index = unpairedDeviceList.find(fakeDevice.address);
185 expectEquals(0, index);
186 expectTrue(!!this.getElementForDevice(unpairedDeviceList,
189 // Simulate process of pairing a device.
190 fakeDevice.pairing = 'bluetoothEnterPinCode';
191 options.BrowserOptions.addBluetoothDevice(fakeDevice);
193 // Verify that the pairing dialog is displayed with the proper options.
194 expectFalse($('bluetooth-pairing').hidden);
195 expectTrue($('bluetooth-pairing-passkey-display').hidden);
196 expectTrue($('bluetooth-pairing-passkey-entry').hidden);
197 expectFalse($('bluetooth-pairing-pincode-entry').hidden);
199 // Connect button should be visible but disabled until a pincode is entered.
200 expectFalse($('bluetooth-pair-device-connect-button').hidden);
201 expectFalse($('bluetooth-pair-device-cancel-button').hidden);
202 expectTrue($('bluetooth-pair-device-connect-button').disabled);
203 expectFalse($('bluetooth-pair-device-cancel-button').disabled);
205 // Simulate process of entering a pincode.
206 var pincode = '123456';
208 this.mockHandler.expects(once()).updateBluetoothDevice(
209 [fakeDevice.address, 'connect', pincode]).will(
210 callFunction(function() {
211 delete fakeDevice.pairing;
212 fakeDevice.paired = true;
213 options.BrowserOptions.addBluetoothDevice(fakeDevice);
216 this.fakeInput($('bluetooth-pincode'), pincode);
217 $('bluetooth-pair-device-connect-button').click();
219 // Verify that the device is removed from the unparied list and added to the
220 // paired device list.
221 expectTrue(!!this.getElementForDevice(pairedDeviceList,
223 expectFalse(!!this.getElementForDevice(unpairedDeviceList,
227 TEST_F('BluetoothWebUITest', 'testConnectionState', function() {
228 assertEquals(this.browsePreload, document.location.href);
230 var pairedDeviceList = $('bluetooth-paired-devices-list');
231 var connectButton = $('bluetooth-reconnect-device');
234 address: '00:24:BE:00:00:00',
241 options.BrowserOptions.addBluetoothDevice(fakeDevice);
242 var element = this.getElementForDevice(pairedDeviceList,
244 assertTrue(!!element);
245 expectFalse(!!element.getAttribute('connected'));
246 expectTrue(connectButton.disabled);
248 // Simulate connecting to a previously paired device.
249 this.selectDevice(pairedDeviceList, fakeDevice);
250 expectFalse(connectButton.disabled);
251 this.mockHandler.expects(once()).updateBluetoothDevice(
252 [fakeDevice.address, 'connect']).will(
253 callFunction(function() {
254 fakeDevice.connected = true;
255 options.BrowserOptions.addBluetoothDevice(fakeDevice);
257 connectButton.click();
258 element = this.getElementForDevice(pairedDeviceList,
260 assertTrue(!!element);
261 expectTrue(!!element.getAttribute('connected'));
262 var button = element.querySelector('.row-delete-button');
263 expectTrue(!!button);
265 Mock4JS.verifyAllMocks();
266 Mock4JS.clearMocksToVerify();
268 // Test disconnecting.
269 this.mockHandler.expects(once()).updateBluetoothDevice(
270 [fakeDevice.address, 'disconnect']).will(
271 callFunction(function() {
272 fakeDevice.connected = false;
273 options.BrowserOptions.addBluetoothDevice(fakeDevice);
276 element = this.getElementForDevice(pairedDeviceList,
278 assertTrue(!!element);
279 expectFalse(!!element.getAttribute('connected'));
280 button = element.querySelector('.row-delete-button');
281 expectTrue(!!button);
283 Mock4JS.verifyAllMocks();
284 Mock4JS.clearMocksToVerify();
286 // Test forgetting a disconnected device.
287 this.mockHandler.expects(once()).updateBluetoothDevice(
288 [fakeDevice.address, 'forget']).will(
289 callFunction(function() {
290 options.BrowserOptions.removeBluetoothDevice(fakeDevice.address);
293 expectFalse(!!this.getElementForDevice(pairedDeviceList,
298 TEST_F('BluetoothWebUITest', 'testMaliciousInput', function() {
299 assertEquals(this.browsePreload, document.location.href);
301 var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
302 var pairDeviceDialog = $('bluetooth-pairing');
304 var maliciousStrings = [
305 '<SCRIPT>alert(1)</SCRIPT>',
306 '>\'>\\"><SCRIPT>alert(1)</SCRIPT>',
307 '<IMG SRC=\\"javascript:alert(1)\\">',
308 '<A HREF=\\"data:text/html;base64,' +
309 'PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo=\\">..</A>',
313 '[0xC0][0xBC]SCRIPT[0xC0][0xBE]alert(1)[0xC0][0xBC]/SCRIPT[0xC0][0xBE]',
314 '+ADw-SCRIPT+AD4-alert(1)+ADw-/SCRIPT+AD4-',
315 '&#<script>alert(1)</script>;',
316 '<!-- Hello -- world > <SCRIPT>alert(1)</SCRIPT> -->',
317 '<!<!-- Hello world > <SCRIPT>alert(1)</SCRIPT> -->',
318 '\x3CSCRIPT\x3Ealert(1)\x3C/SCRIPT\x3E',
319 '<IMG SRC=\\"j[0x00]avascript:alert(1)\\">',
320 '<BASE HREF=\\"javascript:1;/**/\\"><IMG SRC=\\"alert(1)\\">',
321 'javascript:alert(1);',
322 ' xss_injection=\\"\\" ',
323 '\\" xss_injection=\\"',
324 '\' xss_injection=\'',
331 address: '11:22:33:44:55:66',
336 pairing: 'bluetoothStartConnecting'
339 options.BrowserOptions.addBluetoothDevice(fakeDevice);
341 var nodeCount = function(node) {
342 if (node.getAttribute)
343 assertFalse(!!node.getAttribute('xss_injection'));
344 var length = node.childNodes.length;
346 for (var i = 0; i < length; i++) {
347 tally += nodeCount(node.childNodes[i]);
352 // Determine the expected sizes.
353 var unpairedDeviceListSize = nodeCount(unpairedDeviceList);
354 var pairDeviceDialogSize = nodeCount(pairDeviceDialog);
356 // Ensure that updating the device with a malicious name does not corrupt the
357 // structure of the document. Tests the unpaired device list and bluetooth
359 for (var i = 0; i < maliciousStrings.length; i++) {
360 fakeDevice.name = maliciousStrings[i];
361 options.BrowserOptions.addBluetoothDevice(fakeDevice);
362 assertEquals(unpairedDeviceListSize, nodeCount(unpairedDeviceList));
363 var element = this.getElementForDevice(unpairedDeviceList,
365 assertTrue(!!element);
366 var label = element.querySelector('.bluetooth-device-label');
368 assertEquals(maliciousStrings[i], label.textContent);
369 assertEquals(pairDeviceDialogSize, nodeCount(pairDeviceDialog));