Merge pull request #10 from jvallelunga/ISSUE-9

[ISSUE-9] Reafactor Peripheral
This commit is contained in:
jvallelunga 2017-07-15 17:59:40 +02:00 committed by GitHub
commit bd9569c678
11 changed files with 139 additions and 37 deletions

View File

@ -1,3 +1,4 @@
{
"testPathIgnorePatterns": ["/build/"],
"collectCoverageFrom": ["src/**/*.js"]
}

View File

@ -1,5 +1,5 @@
import { createStore } from 'redux';
import startPeripheral from 'redux-bluetooth/build/peripheral';
import { connectSyncStore } from 'redux-bluetooth/build/peripheral';
import reducer from './reducer';
import output from './output';
@ -7,5 +7,4 @@ import output from './output';
const store = createStore(reducer);
output(store);
startPeripheral('Counter', store);
connectSyncStore('Counter', store);

View File

@ -6,25 +6,11 @@ export default function Characteristic(uuid, Parent, util, descriptor, { encode,
descriptors: [descriptor],
});
this.store = null;
this.state = null;
}
util.inherits(ReduxCharacteristic, Parent);
ReduxCharacteristic.prototype.connect = function (store) {
this.store = store;
this.store.subscribe(() => {
if (this.updateValueCallback && this.store) {
const state = this.store.getState();
this.updateValueCallback(encode(state));
}
});
};
ReduxCharacteristic.prototype.disconnect = function () {
this.store = null;
};
ReduxCharacteristic.prototype.onWriteRequest =
function (data, offset, withoutResponse, callback) {
if (offset) {
@ -32,7 +18,7 @@ export default function Characteristic(uuid, Parent, util, descriptor, { encode,
return;
}
if (this.store) this.store.dispatch(decode(data));
this.onAction(decode(data));
callback(this.RESULT_SUCCESS);
};
@ -47,7 +33,7 @@ export default function Characteristic(uuid, Parent, util, descriptor, { encode,
callback(this.RESULT_SUCCESS, null);
return;
}
callback(this.RESULT_SUCCESS, encode(this.store.getState()));
callback(this.RESULT_SUCCESS, this.state);
};
ReduxCharacteristic.prototype.onSubscribe = function (maxValueSize, updateValueCallback) {
@ -58,5 +44,16 @@ export default function Characteristic(uuid, Parent, util, descriptor, { encode,
this.updateValueCallback = null;
};
ReduxCharacteristic.prototype.onAction = function () {
return true;
};
ReduxCharacteristic.prototype.updateState = function (state) {
this.state = encode(state);
if (this.updateValueCallback) {
this.updateValueCallback(this.state);
}
};
return new ReduxCharacteristic();
}

View File

@ -22,27 +22,37 @@ export function Bleno(bleno, encoder, { SERVICE_UUID, CHARACTERISTIC_UUID, DESCR
const service = Service(SERVICE_UUID, bleno.PrimaryService, util, characteristic);
const start = (name, store) => {
bleno.on('stateChange', (state) => {
if (state === 'poweredOn') {
const start = (name, state) => {
bleno.on('stateChange', (status) => {
if (status === 'poweredOn') {
bleno.startAdvertising(name, [SERVICE_UUID], (err) => {
if (err) console.log('startAdvertising.err: ', err);
if (!err) characteristic.updateState(state);
});
} else {
bleno.stopAdvertising();
characteristic.disconnect();
}
});
bleno.on('advertisingStart', (err) => {
if (!err) {
bleno.setServices([service]);
characteristic.connect(store);
}
});
};
return { start };
const handler = (callback) => {
characteristic.onAction = callback;
};
const notify = (state) => {
characteristic.updateState(state);
};
return {
start,
handler,
notify,
};
}
export default new Bleno(BLENO, Encoder(TextEncoding), BLENO_CONFIG);

View File

@ -1,3 +1,5 @@
import bleno from './bleno';
import BLUETOOTH from './bleno';
import STORE from './store';
export default (name, store) => bleno.start(name, store);
export const bluetooth = BLUETOOTH;
export const connectSyncStore = STORE(BLUETOOTH);

View File

@ -1,11 +1,12 @@
/* global jest, test, expect */
import peripheral from '.';
import * as peripheral from '.';
jest.mock('./bleno', () => ({
start: jest.fn().mockReturnValue('mockStart'),
}));
jest.mock('./bleno', () => null);
jest.mock('./store', () => () => null);
test('peripheral', () => {
const result = peripheral(null, null);
expect(result).toEqual('mockStart');
test('actions', () => {
expect(Object.keys(peripheral)).toEqual([
'bluetooth',
'connectSyncStore',
]);
});

View File

@ -0,0 +1,16 @@
export default bluetooth => (name, store) => {
bluetooth.start(name, store.getState());
const handleSubscribe = () => {
bluetooth.notify(store.getState());
};
const handleActions = (action) => {
store.dispatch(action);
};
store.subscribe(handleSubscribe);
bluetooth.handler(handleActions);
return { handleSubscribe, handleActions };
};

View File

@ -0,0 +1,34 @@
/* global jest, test, expect, beforeEach */
import connectSyncStore from '.';
let store = null;
let bleno = null;
beforeEach(() => {
bleno = {
start: jest.fn(),
handler: jest.fn(),
notify: jest.fn(),
};
store = {
subscribe: jest.fn(),
getState: jest.fn().mockReturnValue('mockState'),
dispatch: jest.fn(),
};
});
test('connectSyncStore', () => {
const { handleSubscribe, handleActions } = connectSyncStore(bleno)('mockName', store);
expect(bleno.start).toBeCalledWith('mockName', 'mockState');
expect(store.subscribe).toBeCalled();
expect(bleno.handler).toBeCalled();
handleSubscribe();
expect(bleno.notify).toBeCalledWith('mockState');
expect(store.getState.mock.calls.length).toBe(2);
handleActions('mockAction');
expect(store.dispatch).toBeCalledWith('mockAction');
});

View File

@ -1,9 +1,11 @@
/* global navigator TextEncoder TextDecoder */
/* global window */
import { CENTRAL_CONFIG } from '../../common/config';
import Encoder from '../../common/encoder';
import Central from './central';
const { navigator, TextDecoder, TextEncoder } = window;
export default new Central(
navigator.bluetooth,
Encoder({ TextEncoder, TextDecoder }),

View File

@ -0,0 +1,20 @@
/* global jest, test, expect */
import central from '.';
import Central from './central';
import { CENTRAL_CONFIG } from '../../common/config';
jest.mock('../../common/encoder', () => () => true);
global.TextEncoder = null;
global.TextDecoder = null;
global.navigator = { bluetooth: null };
test('central', () => {
const result = new Central(
null,
true,
CENTRAL_CONFIG,
);
expect(Object.keys(central)).toEqual(Object.keys(result));
});

20
src/webapp/index.test.js Normal file
View File

@ -0,0 +1,20 @@
/* global jest, test, expect */
import * as webapp from '.';
jest.mock('./actions/types', () => true);
jest.mock('./central/status', () => true);
jest.mock('./actions', () => true);
jest.mock('./middleware', () => true);
jest.mock('./reducers', () => true);
jest.mock('./store', () => true);
test('actions', () => {
expect(Object.keys(webapp)).toEqual([
'types',
'status',
'actions',
'reducers',
'middleware',
'createSyncStore',
]);
});