blob: 981cf684623f7e16186197ba3f049facf8d857ee [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
GEN('#if defined(OS_CHROMEOS)');
function BluetoothWebUITest() {}
BluetoothWebUITest.prototype = {
__proto__: testing.Test.prototype,
/**
* Start tests from the main-settings page.
*/
browsePreload: 'chrome://settings-frame/',
/**
* @override
*/
preLoad: function() {
this.makeAndRegisterMockHandler([
'bluetoothEnableChange',
'updateBluetoothDevice',
'findBluetoothDevices',
'stopBluetoothDeviceDiscovery',
]);
},
/**
* Retrieves the list item associated with a Bluetooth device.
* @param {!Element} listElement Element containing a list of devices.
* @param {string} deviceName The name of the device.
* @return {Element|undefined} List item matching the device name.
*/
getElementForDevice: function(listElement, deviceName) {
var items = listElement.querySelectorAll('.bluetooth-device');
for (var i = 0; i < items.length; i++) {
var candidate = items[i];
var name = candidate.data.name;
if (name == deviceName)
return candidate;
}
},
/**
* Selects a bluetooth device from the list with the matching address.
* @param {!Element} listElement A list of Bluetooth devices.
* @param {{address: string,
* connectable: boolean,
* connected: boolean,
* name: string,
* paired: boolean}} device Description of the device.
*/
selectDevice: function(listElement, device) {
listElement.selectedItem = device;
cr.dispatchSimpleEvent(listElement, 'change');
},
/**
* Fake input of a pincode or passkey.
* @param {!Element} element Text input field.
* @param {string} text New value for the input field.
*/
fakeInput: function(element, text) {
element.value = text;
cr.dispatchSimpleEvent(element, 'input');
},
};
TEST_F('BluetoothWebUITest', 'testEnableBluetooth', function() {
assertEquals(this.browsePreload, document.location.href);
expectFalse($('enable-bluetooth').checked);
expectTrue($('bluetooth-paired-devices-list').parentNode.hidden);
this.mockHandler.expects(once()).bluetoothEnableChange([true]).will(
callFunction(function() {
options.BrowserOptions.setBluetoothState(true);
}));
$('enable-bluetooth').click();
expectFalse($('bluetooth-paired-devices-list').parentNode.hidden);
});
TEST_F('BluetoothWebUITest', 'testAddDevices', function() {
assertEquals(this.browsePreload, document.location.href);
var pairedDeviceList = $('bluetooth-paired-devices-list');
var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
var fakePairedDevice = {
address: '00:11:22:33:44:55',
connectable: true,
connected: false,
name: 'Fake device',
paired: true
};
var fakeUnpairedDevice = {
address: '28:CF:DA:00:00:00',
connectable: true,
connected: false,
name: 'Apple Magic Mouse',
paired: false
};
var fakeUnpairedDevice2 = {
address: '28:37:37:00:00:00',
connectable: true,
connected: false,
name: 'Apple Wireless Keyboard',
paired: false
};
// Ensure data models for the paired and unpaired device lists are properly
// updated.
var index = pairedDeviceList.find(fakePairedDevice.address);
expectEquals(undefined, index);
options.BrowserOptions.addBluetoothDevice(fakePairedDevice);
index = pairedDeviceList.find(fakePairedDevice.address);
expectEquals(0, index);
// Ensure the DOM contents of the list are properly updated. The default
// layout of a list creates DOM elements only for visible elements in the
// list, which is problematic if the list is hidden at the time of layout.
// The Bluetooth device lists overcomes this problem by using fixed sized
// elements in an auto-expanding list. This test ensures the problem stays
// fixed.
expectTrue(!!this.getElementForDevice(pairedDeviceList,
fakePairedDevice.name));
expectFalse(!!this.getElementForDevice(unpairedDeviceList,
fakePairedDevice.name));
options.BrowserOptions.addBluetoothDevice(fakeUnpairedDevice);
index = unpairedDeviceList.find(fakeUnpairedDevice.address);
expectEquals(0, index);
expectFalse(!!this.getElementForDevice(pairedDeviceList,
fakeUnpairedDevice.name));
expectTrue(!!this.getElementForDevice(unpairedDeviceList,
fakeUnpairedDevice.name));
// Test adding a second device to a list.
options.BrowserOptions.addBluetoothDevice(fakeUnpairedDevice2);
index = unpairedDeviceList.find(fakeUnpairedDevice2.address);
expectEquals(1, index);
expectTrue(!!this.getElementForDevice(unpairedDeviceList,
fakeUnpairedDevice2.name));
// Test clicking on the 'Add a device' button.
this.mockHandler.expects(once()).findBluetoothDevices();
$('bluetooth-add-device').click();
expectFalse($('bluetooth-options').hidden);
expectTrue($('bluetooth-add-device-apply-button').disabled);
expectFalse($('bluetooth-add-device-cancel-button').disabled);
Mock4JS.verifyAllMocks();
Mock4JS.clearMocksToVerify();
// Test selecting an element and clicking on the connect button.
this.mockHandler.expects(once()).stopBluetoothDeviceDiscovery();
this.mockHandler.expects(once()).updateBluetoothDevice(
[fakeUnpairedDevice2.address, 'connect']);
this.selectDevice(unpairedDeviceList, fakeUnpairedDevice2);
var connectButton = $('bluetooth-add-device-apply-button');
expectFalse(connectButton.disabled);
connectButton.click();
});
TEST_F('BluetoothWebUITest', 'testDevicePairing', function() {
assertEquals(this.browsePreload, document.location.href);
var pairedDeviceList = $('bluetooth-paired-devices-list');
var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
var fakeDevice = {
address: '00:24:BE:00:00:00',
connectable: true,
connected: false,
name: 'Sony BT-00',
paired: false
};
options.BrowserOptions.addBluetoothDevice(fakeDevice);
var index = unpairedDeviceList.find(fakeDevice.address);
expectEquals(0, index);
expectTrue(!!this.getElementForDevice(unpairedDeviceList,
fakeDevice.name));
// Simulate process of pairing a device.
fakeDevice.pairing = 'bluetoothEnterPinCode';
options.BrowserOptions.addBluetoothDevice(fakeDevice);
// Verify that the pairing dialog is displayed with the proper options.
expectFalse($('bluetooth-pairing').hidden);
expectTrue($('bluetooth-pairing-passkey-display').hidden);
expectTrue($('bluetooth-pairing-passkey-entry').hidden);
expectFalse($('bluetooth-pairing-pincode-entry').hidden);
// Connect button should be visible but disabled until a pincode is entered.
expectFalse($('bluetooth-pair-device-connect-button').hidden);
expectFalse($('bluetooth-pair-device-cancel-button').hidden);
expectTrue($('bluetooth-pair-device-connect-button').disabled);
expectFalse($('bluetooth-pair-device-cancel-button').disabled);
// Simulate process of entering a pincode.
var pincode = '123456';
this.mockHandler.expects(once()).updateBluetoothDevice(
[fakeDevice.address, 'connect', pincode]).will(
callFunction(function() {
delete fakeDevice.pairing;
fakeDevice.paired = true;
options.BrowserOptions.addBluetoothDevice(fakeDevice);
}));
this.fakeInput($('bluetooth-pincode'), pincode);
$('bluetooth-pair-device-connect-button').click();
// Verify that the device is removed from the unparied list and added to the
// paired device list.
expectTrue(!!this.getElementForDevice(pairedDeviceList,
fakeDevice.name));
expectFalse(!!this.getElementForDevice(unpairedDeviceList,
fakeDevice.name));
});
TEST_F('BluetoothWebUITest', 'testConnectionState', function() {
assertEquals(this.browsePreload, document.location.href);
var pairedDeviceList = $('bluetooth-paired-devices-list');
var connectButton = $('bluetooth-reconnect-device');
var fakeDevice = {
address: '00:24:BE:00:00:00',
connectable: true,
connected: false,
name: 'Sony BT-00',
paired: true
};
options.BrowserOptions.addBluetoothDevice(fakeDevice);
var element = this.getElementForDevice(pairedDeviceList,
fakeDevice.name);
assertTrue(!!element);
expectFalse(!!element.getAttribute('connected'));
expectTrue(connectButton.disabled);
// Simulate connecting to a previously paired device.
this.selectDevice(pairedDeviceList, fakeDevice);
expectFalse(connectButton.disabled);
this.mockHandler.expects(once()).updateBluetoothDevice(
[fakeDevice.address, 'connect']).will(
callFunction(function() {
fakeDevice.connected = true;
options.BrowserOptions.addBluetoothDevice(fakeDevice);
}));
connectButton.click();
element = this.getElementForDevice(pairedDeviceList,
fakeDevice.name);
assertTrue(!!element);
expectTrue(!!element.getAttribute('connected'));
var button = element.querySelector('.row-delete-button');
expectTrue(!!button);
Mock4JS.verifyAllMocks();
Mock4JS.clearMocksToVerify();
// Test disconnecting.
this.mockHandler.expects(once()).updateBluetoothDevice(
[fakeDevice.address, 'disconnect']).will(
callFunction(function() {
fakeDevice.connected = false;
options.BrowserOptions.addBluetoothDevice(fakeDevice);
}));
button.click();
element = this.getElementForDevice(pairedDeviceList,
fakeDevice.name);
assertTrue(!!element);
expectFalse(!!element.getAttribute('connected'));
button = element.querySelector('.row-delete-button');
expectTrue(!!button);
Mock4JS.verifyAllMocks();
Mock4JS.clearMocksToVerify();
// Test forgetting a disconnected device.
this.mockHandler.expects(once()).updateBluetoothDevice(
[fakeDevice.address, 'forget']).will(
callFunction(function() {
options.BrowserOptions.removeBluetoothDevice(fakeDevice.address);
}));
button.click();
expectFalse(!!this.getElementForDevice(pairedDeviceList,
fakeDevice.name));
});
TEST_F('BluetoothWebUITest', 'testMaliciousInput', function() {
assertEquals(this.browsePreload, document.location.href);
var unpairedDeviceList = $('bluetooth-unpaired-devices-list');
var pairDeviceDialog = $('bluetooth-pairing');
var maliciousStrings = [
'<SCRIPT>alert(1)</SCRIPT>',
'>\'>\\"><SCRIPT>alert(1)</SCRIPT>',
'<IMG SRC=\\"javascript:alert(1)\\">',
'<A HREF=\\"data:text/html;base64,' +
'PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pgo=\\">...</A>',
'<div>',
'<textarea>',
'<style>',
'[0xC0][0xBC]SCRIPT[0xC0][0xBE]alert(1)[0xC0][0xBC]/SCRIPT[0xC0][0xBE]',
'+ADw-SCRIPT+AD4-alert(1)+ADw-/SCRIPT+AD4-',
'&#<script>alert(1)</script>;',
'<!-- Hello -- world > <SCRIPT>alert(1)</SCRIPT> -->',
'<!<!-- Hello world > <SCRIPT>alert(1)</SCRIPT> -->',
'\x3CSCRIPT\x3Ealert(1)\x3C/SCRIPT\x3E',
'<IMG SRC=\\"j[0x00]avascript:alert(1)\\">',
'<BASE HREF=\\"javascript:1;/**/\\"><IMG SRC=\\"alert(1)\\">',
'javascript:alert(1);',
' xss_injection=\\"\\" ',
'\\" xss_injection=\\"',
'\' xss_injection=\'',
'<!--',
'\'',
'\\"'
];
var fakeDevice = {
address: '11:22:33:44:55:66',
connectable: true,
connected: false,
name: 'fake',
paired: false,
pairing: 'bluetoothStartConnecting'
};
options.BrowserOptions.addBluetoothDevice(fakeDevice);
var nodeCount = function(node) {
if (node.getAttribute)
assertFalse(!!node.getAttribute('xss_injection'));
var length = node.childNodes.length;
var tally = length;
for (var i = 0; i < length; i++) {
tally += nodeCount(node.childNodes[i]);
}
return tally;
};
// Determine the expected sizes.
var unpairedDeviceListSize = nodeCount(unpairedDeviceList);
var pairDeviceDialogSize = nodeCount(pairDeviceDialog);
// Ensure that updating the device with a malicious name does not corrupt the
// structure of the document. Tests the unpaired device list and bluetooth
// pairing dialog.
for (var i = 0; i < maliciousStrings.length; i++) {
fakeDevice.name = maliciousStrings[i];
options.BrowserOptions.addBluetoothDevice(fakeDevice);
assertEquals(unpairedDeviceListSize, nodeCount(unpairedDeviceList));
var element = this.getElementForDevice(unpairedDeviceList,
fakeDevice.name);
assertTrue(!!element);
var label = element.querySelector('.bluetooth-device-label');
assertTrue(!!label);
assertEquals(maliciousStrings[i], label.textContent);
assertEquals(pairDeviceDialogSize, nodeCount(pairDeviceDialog));
}
});
GEN('#endif');