VulpesOS/gaia/apps/system/test/unit/bluetooth_v2_test.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

507 lines
17 KiB
JavaScript
Executable file

/* global Bluetooth, MockSettingsListener, Service, MockL10n,
MockNavigatorSettings, MockNavigatormozSetMessageHandler,
MockMozBluetooth, MockBTAdapter, MocksHelper, MockLazyLoader */
'use strict';
require('/shared/test/unit/mocks/mock_navigator_moz_set_message_handler.js');
require('/shared/test/unit/mocks/mock_navigator_moz_bluetooth_v2.js');
require('/shared/test/unit/mocks/mock_settings_listener.js');
require('/shared/test/unit/mocks/mock_navigator_moz_settings.js');
require('/shared/test/unit/mocks/mock_lazy_loader.js');
requireApp('system/js/service.js');
requireApp('system/js/base_module.js');
requireApp('system/js/base_ui.js');
requireApp('system/js/base_icon.js');
requireApp('system/js/bluetooth_icon.js');
requireApp('system/js/bluetooth_transfer_icon.js');
requireApp('system/js/bluetooth_headphone_icon.js');
require('/shared/test/unit/mocks/mock_l10n.js');
function switchReadOnlyProperty(originObject, propName, targetObj) {
Object.defineProperty(originObject, propName, {
configurable: true,
get: function() { return targetObj; }
});
}
var mocksForBluetooth = new MocksHelper([
'SettingsListener',
'LazyLoader'
]).init();
suite('system/bluetooth_v2', function() {
var realSetMessageHandler;
var realSettings;
var realSettingsListener;
var realMozBluetooth;
var realL10n;
mocksForBluetooth.attachTestHelpers();
suiteSetup(function(done) {
MockLazyLoader.mLoadRightAway = true;
sinon.spy(MockLazyLoader, 'load');
realSetMessageHandler = navigator.mozSetMessageHandler;
navigator.mozSetMessageHandler = MockNavigatormozSetMessageHandler;
MockNavigatormozSetMessageHandler.mSetup();
realSettings = navigator.mozSettings;
navigator.mozSettings = MockNavigatorSettings;
realSettingsListener = window.SettingsListener;
window.SettingsListener = MockSettingsListener;
realMozBluetooth = navigator.mozBluetooth;
switchReadOnlyProperty(navigator, 'mozBluetooth', MockMozBluetooth);
realL10n = window.navigator.mozL10n;
window.navigator.mozL10n = MockL10n;
requireApp('system/js/bluetooth_v2.js', done);
});
suiteTeardown(function() {
MockNavigatormozSetMessageHandler.mTeardown();
navigator.mozSetMessageHandler = realSetMessageHandler;
window.SettingsListener = realSettingsListener;
switchReadOnlyProperty(navigator, 'mozBluetooth', realMozBluetooth);
navigator.mozL10n = realL10n;
});
setup(function() {
// instanciate bluetooth module
window.Bluetooth = new window.Bluetooth2();
});
teardown(function() {
window.Bluetooth.stop();
});
suite('setProfileConnected', function() {
var profiles = ['hfp', 'opp', 'a2dp', 'sco'];
setup(function() {
this.sinon.spy(window, 'dispatchEvent');
Bluetooth.icon = { update: function() {} };
this.sinon.stub(Bluetooth.icon, 'update');
});
test('nothing is called when wasConnected', function() {
profiles.forEach(function(profile){
Bluetooth['_' + profile + 'Connected'] = true;
Bluetooth._setProfileConnected(profile, true);
assert.isFalse(window.dispatchEvent.called);
assert.isFalse(Bluetooth.icon.update.called);
});
});
test('event is dispatched, Bluetooth icon is updated when disconnected',
function() {
profiles.forEach(function(profile){
Bluetooth['_' + profile + 'Connected'] = true;
Bluetooth._setProfileConnected(profile, false);
assert.ok(window.dispatchEvent.called);
assert.isTrue(Bluetooth.icon.update.called);
});
});
test('event is dispatched, Bluetooth icon is updated when first connect',
function() {
profiles.forEach(function(profile){
Bluetooth['_' + profile + 'Connected'] = false;
Bluetooth._setProfileConnected(profile, true);
assert.ok(window.dispatchEvent.called);
assert.isTrue(Bluetooth.icon.update.called);
});
});
test('event is dispatched with right detail object', function(done) {
Bluetooth._oppConnected = false;
var handler = function(evt) {
assert.equal(evt.detail.name, 'opp');
assert.isTrue(evt.detail.connected);
done();
};
var bindHandler = handler.bind(this);
window.addEventListener('bluetoothprofileconnectionchange',
bindHandler);
Bluetooth._setProfileConnected('opp', true);
window.removeEventListener('bluetoothprofileconnectionchange',
bindHandler);
});
test('transferIcon is not updated with non-OPP profile',
function() {
Bluetooth.transferIcon = { update: function() {} };
this.sinon.stub(Bluetooth.transferIcon, 'update');
Bluetooth._setProfileConnected('hfp', false);
assert.isFalse(Bluetooth.transferIcon.update.called);
Bluetooth._setProfileConnected('a2dp', false);
assert.isFalse(Bluetooth.transferIcon.update.called);
Bluetooth._setProfileConnected('sco', false);
});
test('transferIcon is updated with OPP profile', function() {
Bluetooth.transferIcon = { update: function() {} };
this.sinon.stub(Bluetooth.transferIcon, 'update');
Bluetooth._setProfileConnected('opp', false);
assert.isTrue(Bluetooth.transferIcon.update.called);
Bluetooth._setProfileConnected('opp', true);
assert.isTrue(Bluetooth.transferIcon.update.calledTwice);
});
});
suite('isProfileConnected', function() {
var profiles = ['hfp', 'opp', 'a2dp', 'sco'];
test('return true when profile is connected', function() {
profiles.forEach(function(profile) {
Bluetooth['_' + profile + 'Connected'] = false;
});
profiles.forEach(function(profile) {
assert.isFalse(Bluetooth._isProfileConnected(profile));
});
});
test('return true when profile is connected', function() {
profiles.forEach(function(profile) {
Bluetooth['_' + profile + 'Connected'] = true;
});
profiles.forEach(function(profile) {
assert.ok(Bluetooth._isProfileConnected(profile));
});
});
});
suite('Initialize', function() {
setup(function() {
this.sinon.spy(navigator.mozBluetooth, 'addEventListener');
this.sinon.stub(Bluetooth, '_setProfileConnected');
this.sinon.stub(Bluetooth, '_initDefaultAdapter');
this.sinon.spy(window, 'addEventListener');
this.sinon.spy(window, 'dispatchEvent');
this.sinon.spy(Service, 'register');
this.sinon.spy(Service, 'registerState');
window.BluetoothTransfer = { start: function() {} };
Bluetooth.start();
});
test('initDefaultAdapter is called', function() {
assert.ok(Bluetooth._initDefaultAdapter.called);
});
test('listener called', function() {
assert.ok(navigator.mozBluetooth.addEventListener.
calledWith('attributechanged'));
assert.ok(window.addEventListener
.calledWith('request-enable-bluetooth'));
assert.ok(window.addEventListener
.calledWith('request-disable-bluetooth'));
});
test('MessageHandler bluetooth-opp-transfer-start is called',
function() {
MockNavigatormozSetMessageHandler.mTrigger(
'bluetooth-opp-transfer-start', {
source: {
data: {}
}
});
assert.ok(Bluetooth._setProfileConnected.called);
assert.ok(window.dispatchEvent.called);
});
test('MessageHandler bluetooth-opp-transfer-complete is called',
function() {
MockNavigatormozSetMessageHandler.mTrigger(
'bluetooth-opp-transfer-complete', {
source: {
data: {}
}
});
assert.ok(Bluetooth._setProfileConnected.called);
assert.ok(window.dispatchEvent.called);
});
test('register request', function() {
assert.ok(Service.register.calledWith('adapter'));
assert.ok(Service.register.calledWith('pair'));
assert.ok(Service.register.calledWith('getPairedDevices'));
});
test('register state', function() {
assert.ok(Service.registerState.calledWith('isEnabled'));
assert.ok(Service.registerState.calledWith('getAdapter'));
assert.ok(Service.registerState.calledWith('isOPPProfileConnected'));
assert.ok(Service.registerState.calledWith('isA2DPProfileConnected'));
assert.ok(Service.registerState.calledWith('isSCOProfileConnected'));
});
test('Should lazy load icons', function() {
assert.isTrue(MockLazyLoader.load.calledWith(
['js/bluetooth_transfer.js',
'js/bluetooth_icon.js',
'js/bluetooth_transfer_icon.js',
'js/bluetooth_headphone_icon.js']
));
});
});
suite('initDefaultAdapter', function() {
setup(function() {
this.sinon.stub(Bluetooth, '_dispatchEnableState');
Bluetooth._bluetooth = MockMozBluetooth;
});
test('defaultAdapter is available', function() {
Bluetooth._bluetooth.defaultAdapter = MockBTAdapter;
Bluetooth._initDefaultAdapter();
assert.equal(Bluetooth._adapter, navigator.mozBluetooth.defaultAdapter);
assert.ok(Bluetooth._dispatchEnableState.called);
});
test('defaultAdapter is not available', function() {
Bluetooth._bluetooth.defaultAdapter = null;
Bluetooth._initDefaultAdapter();
assert.equal(Bluetooth._adapter, null);
});
});
suite('Adapter Available Handler', function() {
setup(function() {
Bluetooth._adapter = MockBTAdapter;
this.sinon.stub(Bluetooth._adapter, 'addEventListener');
Bluetooth._adapterAvailableHandler();
});
test('return true when profile is connected', function() {
assert.ok(MockBTAdapter.addEventListener.
calledWith('attributechanged'));
assert.ok(MockBTAdapter.addEventListener
.calledWith('hfpstatuschanged'));
assert.ok(MockBTAdapter.addEventListener
.calledWith('a2dpstatuschanged'));
assert.ok(MockBTAdapter.addEventListener
.calledWith('scostatuschanged'));
});
});
suite('Adapter Unavailable Handler', function() {
setup(function() {
Bluetooth._adapter = MockBTAdapter;
this.sinon.stub(Bluetooth._adapter, 'removeEventListener');
Bluetooth._adapterUnavailableHandler();
});
test('removeEventListener is called', function() {
assert.ok(Bluetooth._adapter.removeEventListener
.calledWith('hfpstatuschanged'));
assert.ok(Bluetooth._adapter.removeEventListener
.calledWith('a2dpstatuschanged'));
assert.ok(Bluetooth._adapter.removeEventListener
.calledWith('scostatuschanged'));
assert.ok(Bluetooth._adapter.removeEventListener
.calledWith('attributechanged'));
});
});
suite('handle Bluetooth states', function() {
setup(function() {
this.sinon.spy(Bluetooth, '_requestEnableHandler');
this.sinon.spy(Bluetooth, '_requestDisableHandler');
this.sinon.spy(Bluetooth, '_dispatchEnableState');
this.sinon.stub(Bluetooth, '_initDefaultAdapter');
this.sinon.stub(MockBTAdapter, 'enable', function() {
return { then: function(resolve) { resolve(); } };
});
this.sinon.stub(MockBTAdapter, 'disable', function() {
return { then: function(resolve) { resolve(); } };
});
});
test('request-enable-bluetooth is called', function() {
Bluetooth._adapter = MockBTAdapter;
Bluetooth.start();
window.dispatchEvent(new CustomEvent('request-enable-bluetooth'));
assert.ok(Bluetooth._requestEnableHandler.called);
assert.ok(MockBTAdapter.enable.called);
});
test('request-enable-bluetooth is called when adapter is not available',
function() {
Bluetooth._adapter = null;
Bluetooth.start();
window.dispatchEvent(new CustomEvent('request-enable-bluetooth'));
assert.ok(Bluetooth._dispatchEnableState.called);
});
test('request-disable-bluetooth is called', function() {
Bluetooth._adapter = MockBTAdapter;
Bluetooth.start();
window.dispatchEvent(new CustomEvent('request-disable-bluetooth'));
assert.ok(Bluetooth._requestDisableHandler.called);
assert.ok(MockBTAdapter.disable.called);
});
test('request-disable-bluetooth is called when adapter is not available',
function() {
Bluetooth._adapter = null;
Bluetooth.start();
window.dispatchEvent(new CustomEvent('request-disable-bluetooth'));
assert.ok(Bluetooth._dispatchEnableState.called);
});
});
suite('bluetoothAdapterHandler', function() {
setup(function() {
this.sinon.spy(MockNavigatorSettings, 'createLock');
this.sinon.stub(window, 'dispatchEvent');
Bluetooth._adapter = MockBTAdapter;
Bluetooth.icon = { update: function() {} };
this.sinon.stub(Bluetooth.icon, 'update');
});
teardown(function() {
Bluetooth._adapter = null;
Bluetooth.icon = null;
});
test('bluetooth state is enabled', function() {
Bluetooth._adapter.state = 'enabled';
Bluetooth._btAdapterHandler({attrs: ['state']});
assert.isTrue(Bluetooth._isEnabled);
assert.ok(window.dispatchEvent.called);
assert.ok(Bluetooth.icon.update.called);
});
test('bluetooth state is disabled', function() {
Bluetooth._adapter.state = 'disabled';
Bluetooth._btAdapterHandler({attrs: ['state']});
assert.isFalse(Bluetooth._isEnabled);
assert.ok(window.dispatchEvent.called);
assert.ok(Bluetooth.icon.update.called);
});
});
suite('btManagerHandler', function() {
setup(function() {
this.sinon.stub(Bluetooth, '_adapterUnavailableHandler');
Bluetooth._bluetooth = window.navigator.mozBluetooth;
});
teardown(function() {
Bluetooth._adapter = null;
MockBTAdapter.state = '';
});
test('default adapter and state are updated when defaultAdapter' +
'is changed', function() {
var evt = {
attrs: ['defaultAdapter']
};
MockMozBluetooth.defaultAdapter = MockBTAdapter;
MockBTAdapter.state = 'enabled';
Bluetooth._btManagerHandler(evt);
assert.equal(Bluetooth._adapter, MockBTAdapter);
assert.ok(Bluetooth._isEnabled, true);
});
test('functions are not called when defaultAdapter is null',
function() {
var evt = {
attrs: ['defaultAdapter']
};
MockMozBluetooth.defaultAdapter = null;
Bluetooth._btManagerHandler(evt);
assert.equal(Bluetooth._adapter, null);
assert.ok(Bluetooth._adapterUnavailableHandler.called);
});
test('functions are not called when no matched attribute',
function() {
var evt = {
attrs: []
};
MockMozBluetooth.defaultAdapter = null;
Bluetooth._btManagerHandler(evt);
assert.equal(Bluetooth._adapter, null);
assert.ok(!Bluetooth._adapterUnavailableHandler.called);
});
});
suite('oppTransferStartHandler', function() {
test('event is dispatched with right detail object', function(done) {
this.sinon.stub(Bluetooth, '_setProfileConnected');
var transferInfo = this.sinon.stub();
var handler = function(evt) {
assert.equal(evt.detail.transferInfo, transferInfo);
done();
};
var bindHandler = handler.bind(this);
window.addEventListener('bluetooth-opp-transfer-start',
bindHandler);
Bluetooth._oppTransferStartHandler(transferInfo);
assert.ok(Bluetooth._setProfileConnected.called);
window.removeEventListener('bluetooth-opp-transfer-start',
bindHandler);
});
});
suite('oppTransferCompleteHandler', function() {
test('event is dispatched with right detail object', function(done) {
this.sinon.stub(Bluetooth, '_setProfileConnected');
var transferInfo = this.sinon.stub();
var handler = function(evt) {
assert.equal(evt.detail.transferInfo, transferInfo);
done();
};
var bindHandler = handler.bind(this);
window.addEventListener('bluetooth-opp-transfer-complete',
bindHandler);
Bluetooth._oppTransferCompleteHandler(transferInfo);
assert.ok(Bluetooth._setProfileConnected.called);
window.removeEventListener('bluetooth-opp-transfer-complete',
bindHandler);
});
});
suite('service requests', function() {
test('request the adapter', function() {
Bluetooth._adapter = MockBTAdapter;
Service.request('Bluetooth:adapter').then(function(value) {
assert.equal(value, Bluetooth._adapter);
});
});
test('request pair', function() {
Bluetooth._adapter = MockBTAdapter;
var mac = '01:23:45:67:89:AB';
this.sinon.spy(MockBTAdapter, 'pair');
Service.request('Bluetooth:pair', mac).then(function() {
assert.ok(MockBTAdapter.pair.calledWith(mac));
});
});
test('request getPairedDevices', function() {
Bluetooth._adapter = MockBTAdapter;
this.sinon.spy(MockBTAdapter, 'getPairedDevices');
Service.request('Bluetooth:getPairedDevices')
.then(function() {
assert.ok(MockBTAdapter.getPairedDevices.called);
});
});
});
});