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
));