bluetooth-terminal
Advanced tools
Comparing version 1.2.2 to 1.2.3
@@ -420,4 +420,5 @@ /** | ||
// Export class as a module to support requiring | ||
/* istanbul ignore next */ | ||
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { | ||
module.exports = BluetoothTerminal; | ||
} |
{ | ||
"name": "bluetooth-terminal", | ||
"version": "1.2.2", | ||
"version": "1.2.3", | ||
"description": "ES6 class for serial communication with Bluetooth Low Energy (Smart) devices", | ||
@@ -28,5 +28,6 @@ "keywords": [ | ||
"coveralls": "^3.0.0", | ||
"eslint": "^4.12.0", | ||
"eslint": "^4.12.1", | ||
"eslint-config-google": "^0.9.1", | ||
"istanbul": "^0.4.5", | ||
"jsdom": "^11.5.1", | ||
"mocha": "^4.0.1", | ||
@@ -33,0 +34,0 @@ "sinon": "^4.1.2", |
const chai = require('chai'); | ||
const chaiAsPromised = require('chai-as-promised'); | ||
const {DeviceMock, WebBluetoothMock} = require('web-bluetooth-mock'); | ||
const {JSDOM} = require('jsdom'); | ||
const path = require('path'); | ||
const sinon = require('sinon'); | ||
const {DeviceMock, WebBluetoothMock} = require('web-bluetooth-mock'); | ||
const {TextDecoder, TextEncoder} = require('util'); | ||
@@ -13,8 +15,15 @@ chai.use(chaiAsPromised); | ||
global.navigator = global.navigator || {}; | ||
global.TextEncoder = require('util').TextEncoder; | ||
// Provide testing environment with `window` object to support DOM events and | ||
// with `navigator` to spy for bluetooth features | ||
global.window = new JSDOM('').window; | ||
global.navigator = window.navigator; | ||
// Use node text encoding features from `util` module | ||
global.TextDecoder = TextDecoder; | ||
global.TextEncoder = TextEncoder; | ||
describe('BluetoothTerminal', () => { | ||
let bt; | ||
// Create new instance before each test | ||
beforeEach(() => { | ||
@@ -143,3 +152,3 @@ bt = new BluetoothTerminal(); | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
@@ -151,6 +160,5 @@ return assert.isFulfilled(bt.connect()); | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
const requestDeviceSpy = sinon.spy(global.navigator.bluetooth, | ||
'requestDevice'); | ||
const requestDeviceSpy = sinon.spy(navigator.bluetooth, 'requestDevice'); | ||
@@ -164,3 +172,3 @@ return bt.connect(). | ||
const device = new DeviceMock('Simon', [bt._serviceUuid + 42]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
@@ -172,9 +180,16 @@ return assert.isRejected(bt.connect()); | ||
describe('disconnect', () => { | ||
it('should disconnect once', () => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
let connectPromise; | ||
let device; | ||
let disconnectSpy; | ||
const disconnectSpy = sinon.spy(device.gatt, 'disconnect'); | ||
// Connect to the device and set up the spy before each test | ||
beforeEach(() => { | ||
device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
connectPromise = bt.connect(); | ||
disconnectSpy = sinon.spy(device.gatt, 'disconnect'); | ||
}); | ||
return bt.connect(). | ||
it('should disconnect once', () => { | ||
return connectPromise. | ||
then(() => { | ||
@@ -189,8 +204,3 @@ bt.disconnect(); | ||
() => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
const disconnectSpy = sinon.spy(device.gatt, 'disconnect'); | ||
return bt.connect(). | ||
return connectPromise. | ||
then(() => { | ||
@@ -205,3 +215,69 @@ // Hard mock used here to cover the case | ||
describe('receive', () => { | ||
let characteristicValueChangedEvent = new window. | ||
CustomEvent('characteristicvaluechanged'); | ||
let connectPromise; | ||
let receiveSpy; | ||
// Connect to the device and set up the spy before each test | ||
beforeEach(() => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
connectPromise = bt.connect(); | ||
receiveSpy = sinon.spy(bt, 'receive'); | ||
}); | ||
it('should not be called when a value provided does not have a separator', | ||
() => { | ||
let value = 'Hello, world!'; | ||
return connectPromise. | ||
then(() => { | ||
const characteristic = bt._characteristic; | ||
characteristic.value = new TextEncoder().encode(value); | ||
characteristic.dispatchEvent(characteristicValueChangedEvent); | ||
return assert(receiveSpy.notCalled); | ||
}); | ||
}); | ||
it('should be called when a value provided have a separator', () => { | ||
let value = 'Hello, world!' + bt._receiveSeparator; | ||
return connectPromise. | ||
then(() => { | ||
const characteristic = bt._characteristic; | ||
characteristic.value = new TextEncoder().encode(value); | ||
characteristic.dispatchEvent(characteristicValueChangedEvent); | ||
return assert(receiveSpy.calledOnce); | ||
}); | ||
}); | ||
it('should be called twice when a value provided have three separators, ' + | ||
'but there is no data data between the first and second', () => { | ||
let value = 'Hello, world!' + bt._receiveSeparator + | ||
bt._receiveSeparator + 'Ciao, mondo!' + bt._receiveSeparator; | ||
return connectPromise. | ||
then(() => { | ||
const characteristic = bt._characteristic; | ||
characteristic.value = new TextEncoder().encode(value); | ||
characteristic.dispatchEvent(characteristicValueChangedEvent); | ||
return assert(receiveSpy.calledTwice); | ||
}); | ||
}); | ||
}); | ||
describe('send', () => { | ||
// Set up Web Bluetooth mock before each test | ||
beforeEach(() => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
}); | ||
it('should reject empty data', () => { | ||
@@ -216,5 +292,2 @@ return assert.isRejected(bt.send()); | ||
it('should write to characteristic', () => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
let writeValueSpy; | ||
@@ -231,5 +304,2 @@ | ||
it('should write long data to characteristic consistently', () => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
let writeValueSpy; | ||
@@ -252,5 +322,2 @@ let data = ''; | ||
it('should reject if device suddenly disconnects', () => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
let writeValueSpy; | ||
@@ -274,2 +341,8 @@ let data = ''; | ||
describe('getDeviceName', () => { | ||
// Set up Web Bluetooth mock before each test | ||
beforeEach(() => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
}); | ||
it('should return empty string if not connected', () => { | ||
@@ -281,4 +354,2 @@ assert.strictEqual(bt.getDeviceName(), ''); | ||
const value = 'Simon'; | ||
const device = new DeviceMock(value, [bt._serviceUuid]); | ||
global.navigator.bluetooth = new WebBluetoothMock([device]); | ||
@@ -290,3 +361,99 @@ return bt.connect(). | ||
describe('_splitByLength', function() { | ||
describe('_stopNotifications', () => { | ||
let characteristicValueChangedEvent = new window. | ||
CustomEvent('characteristicvaluechanged'); | ||
let connectPromise; | ||
let receiveSpy; | ||
// Connect to the device and set up the spy before each test | ||
beforeEach(() => { | ||
const device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
connectPromise = bt.connect(); | ||
receiveSpy = sinon.spy(bt, 'receive'); | ||
}); | ||
it('should stop data receiving', () => { | ||
let value = 'Hello, world!' + bt._receiveSeparator; | ||
let characteristic; | ||
return connectPromise. | ||
then(() => { | ||
characteristic = bt._characteristic; | ||
characteristic.value = new TextEncoder().encode(value); | ||
characteristic.dispatchEvent(characteristicValueChangedEvent); | ||
return assert(receiveSpy.calledOnce); | ||
}). | ||
then(() => { | ||
// Call for private method only to test it | ||
return bt._stopNotifications(bt._characteristic); | ||
}). | ||
then(() => { | ||
characteristic.value = new TextEncoder().encode(value); | ||
characteristic.dispatchEvent(characteristicValueChangedEvent); | ||
return assert(receiveSpy.calledOnce); // Remains the same | ||
}); | ||
}); | ||
}); | ||
describe('_handleDisconnection', () => { | ||
let connectDeviceAndCacheCharacteristicSpy; | ||
let connectPromise; | ||
let device; | ||
let gattServerDisconnectedEvent = new window. | ||
CustomEvent('gattserverdisconnected'); | ||
// Set up Web Bluetooth mock before each test | ||
beforeEach(() => { | ||
device = new DeviceMock('Simon', [bt._serviceUuid]); | ||
navigator.bluetooth = new WebBluetoothMock([device]); | ||
connectDeviceAndCacheCharacteristicSpy = sinon.spy(bt, | ||
'_connectDeviceAndCacheCharacteristic'); | ||
connectPromise = bt.connect(); | ||
}); | ||
it('should reconnect', () => { | ||
return connectPromise. | ||
then(() => { | ||
return assert(connectDeviceAndCacheCharacteristicSpy.calledOnce); | ||
}). | ||
then(() => { | ||
device.dispatchEvent(gattServerDisconnectedEvent); | ||
}). | ||
then(() => { | ||
return assert(connectDeviceAndCacheCharacteristicSpy.calledTwice); | ||
}); | ||
}); | ||
it('should fail to reconnect and call `log` with the error', (done) => { | ||
const error = 'Simulated error'; | ||
const logSpy = sinon.spy(bt, '_log'); | ||
connectPromise. | ||
then(() => { | ||
return assert(connectDeviceAndCacheCharacteristicSpy.calledOnce); | ||
}). | ||
then(() => { | ||
// Simulate disconnection | ||
device.gatt.connected = false; | ||
device.gatt.connect = () => Promise.reject(error); | ||
device.dispatchEvent(gattServerDisconnectedEvent); | ||
}). | ||
then(() => { | ||
// Make sure the assert will be executed after the promise | ||
setTimeout(() => { | ||
assert(logSpy.lastCall.calledWith(error)); | ||
done(); | ||
}, 0); | ||
return assert(connectDeviceAndCacheCharacteristicSpy.calledTwice); | ||
}); | ||
}); | ||
}); | ||
describe('_splitByLength', () => { | ||
it('should split string shorter than specified length to one chunk', () => { | ||
@@ -293,0 +460,0 @@ assert.equal(bt.constructor._splitByLength('abcde', 6).length, 1); |
38849
748
10