UNPKG

browser-serialport

Version:

Robots in the browser. Just like node-serialport but for browser/chrome apps.

435 lines (371 loc) 12.2 kB
'use strict'; var sinon = require('sinon'); var chai = require('chai'); var without = require('lodash/array/without'); var expect = chai.expect; var MockedSerialPort = require('../'); var SerialPort = MockedSerialPort.SerialPort; var options; function unset(msg){ return function(){ throw new Error(msg); }; } var serialListeners = []; var hardware = { ports: {}, createPort: function(path){ this.ports[path] = true; }, reset: function(){ this.ports = {}; this.onReceive = unset('onreceive unset'); this.onReceiveError = unset('onReceiveError unset'); }, onReceive: unset('onReceive unset'), onReceiveError: unset('onReceiveError unset'), emitData: function(buffer){ process.nextTick(function(){ var readInfo = {data: MockedSerialPort.buffer2ArrayBuffer(buffer), connectionId: 1}; serialListeners.forEach(function(cb){ cb(readInfo); }); }); }, disconnect: function(path){ this.ports[path] = false; var info = {error: 'disconnected', connectionId: 1}; this.onReceiveError(info); }, timeout: function(path){ this.ports[path] = false; var info = {error: 'timeout', connectionId: 1}; this.onReceiveError(info); }, loseDevice: function(path){ this.ports[path] = false; var info = {error: 'device_lost', connectionId: 1}; this.onReceiveError(info); }, systemError: function(path){ this.ports[path] = false; var info = {error: 'system_error', connectionId: 1}; this.onReceiveError(info); } }; describe('SerialPort', function () { var sandbox; beforeEach(function () { sandbox = sinon.sandbox.create(); global.chrome = { runtime: { lastError: null } }; serialListeners = []; options = { serial: { connect: function(path, options, cb){ if (!hardware.ports[path]) { global.chrome.runtime.lastError = new Error({message: 'Failed to connect to the port.'}); } chai.assert.ok(options.bitrate, 'baudrate not set'); chai.assert.ok(options.dataBits, 'databits not set'); chai.assert.ok(options.parityBit, 'parity not set'); chai.assert.ok(options.stopBits, 'stopbits not set'); chai.assert.isBoolean(options.ctsFlowControl, 'flowcontrol not set'); cb({ bitrate: 9600, bufferSize: 4096, connectionId: 1, ctsFlowControl: true, dataBits: 'eight', name: '', parityBit: 'no', paused: false, persistent: false, receiveTimeout: 0, sendTimeout: 0, stopBits: 'one' }); }, onReceive: { addListener: function(cb){ serialListeners.push(cb); }, removeListener: function(cb){ serialListeners = without(serialListeners, cb); } }, onReceiveError: { addListener: function(cb){ hardware.onReceiveError = cb; } }, send: function(connectionId, buffer, cb){ }, disconnect: function(connectionId, cb){ cb(); }, setControlSignals: function(connectionId, options, cb){ cb(); } } }; // Create a port for fun and profit hardware.reset(); hardware.createPort('/dev/exists'); }); afterEach(function () { options = null; sandbox.restore(); }); describe('Constructor', function () { it('opens the port immediately', function (done) { var port = new SerialPort('/dev/exists', options, function (err) { expect(err).to.not.be.ok; done(); }); }); it('emits the open event', function (done) { var port = new SerialPort('/dev/exists', options); port.on('open', function(){ done(); }); }); it.skip('emits an error on the factory when erroring without a callback', function (done) { // finish the test on error MockedSerialPort.once('error', function (err) { chai.assert.isDefined(err, 'didn\'t get an error'); done(); }); var port = new SerialPort('/dev/johnJacobJingleheimerSchmidt'); }); it('emits an error on the serialport when explicit error handler present', function (done) { var port = new SerialPort('/dev/johnJacobJingleheimerSchmidt', options); port.once('error', function(err) { chai.assert.isDefined(err); done(); }); }); it('errors with invalid databits', function (done) { var errorCallback = function (err) { chai.assert.isDefined(err, 'err is not defined'); done(); }; var port = new SerialPort('/dev/exists', { databits : 19 }, false, errorCallback); }); it('errors with invalid stopbits', function (done) { var errorCallback = function (err) { chai.assert.isDefined(err, 'err is not defined'); done(); }; var port = new SerialPort('/dev/exists', { stopbits : 19 }, false, errorCallback); }); it('errors with invalid parity', function (done) { var errorCallback = function (err) { chai.assert.isDefined(err, 'err is not defined'); done(); }; var port = new SerialPort('/dev/exists', { parity : 'pumpkins' }, false, errorCallback); }); it('errors with invalid flow control', function (done) { var errorCallback = function (err) { chai.assert.isDefined(err, 'err is not defined'); done(); }; var port = new SerialPort('/dev/exists', { flowcontrol : ['pumpkins'] }, false, errorCallback); }); it('errors with invalid path', function (done) { var errorCallback = function (err) { chai.assert.isDefined(err, 'err is not defined'); done(); }; var port = new SerialPort(null, false, errorCallback); }); it('allows optional options', function (done) { global.chrome.serial = options.serial; var cb = function () {}; var port = new SerialPort('/dev/exists', cb); // console.log(port); expect(typeof port.options).to.eq('object'); delete global.chrome.serial; done(); }); }); describe('Functions', function () { it('write errors when serialport not open', function (done) { var cb = function () {}; var port = new SerialPort('/dev/exists', options, false, cb); port.write(null, function(err){ chai.assert.isDefined(err, 'err is not defined'); done(); }); }); it('close errors when serialport not open', function (done) { var cb = function () {}; var port = new SerialPort('/dev/exists', options, false, cb); port.close(function(err){ chai.assert.isDefined(err, 'err is not defined'); done(); }); }); it('flush errors when serialport not open', function (done) { var cb = function () {}; var port = new SerialPort('/dev/exists', options, false, cb); port.flush(function(err){ chai.assert.isDefined(err, 'err is not defined'); done(); }); }); it('set errors when serialport not open', function (done) { var cb = function () {}; var port = new SerialPort('/dev/exists', options, false, cb); port.set({}, function(err){ chai.assert.isDefined(err, 'err is not defined'); done(); }); }); it('drain errors when serialport not open', function (done) { var cb = function () {}; var port = new SerialPort('/dev/exists', options, false, cb); port.drain(function(err){ chai.assert.isDefined(err, 'err is not defined'); done(); }); }); }); describe('reading data', function () { it('emits data events by default', function (done) { var testData = new Buffer('I am a really short string'); var port = new SerialPort('/dev/exists', options, function () { port.once('data', function(recvData) { expect(recvData).to.eql(testData); done(); }); hardware.emitData(testData); }); }); it('calls the dataCallback if set', function (done) { var testData = new Buffer('I am a really short string'); options.dataCallback = function (recvData) { expect(recvData).to.eql(testData); done(); }; var port = new SerialPort('/dev/exists', options, function () { hardware.emitData(testData); }); }); }); describe('#open', function () { it('passes the port to the bindings', function (done) { var openSpy = sandbox.spy(options.serial, 'connect'); var port = new SerialPort('/dev/exists', options, false); port.open(function (err) { expect(err).to.not.be.ok; expect(openSpy.calledWith('/dev/exists')); done(); }); }); it('calls back an error when opening an invalid port', function (done) { var port = new SerialPort('/dev/unhappy', options, false); port.open(function (err) { expect(err).to.be.ok; done(); }); }); it('emits data after being reopened', function (done) { var data = new Buffer('Howdy!'); var port = new SerialPort('/dev/exists', options, function () { port.close(function () { port.open(function () { port.once('data', function (res) { expect(res).to.eql(data); done(); }); hardware.emitData(data); }); }); }); }); it('does not emit data twice if reopened', function (done) { var data = new Buffer('Howdy!'); var port = new SerialPort('/dev/exists', options, function () { port.close(function () { port.open(function () { var count = 0; port.on('data', function (res) { count++; }); hardware.emitData(data); setTimeout(function(){ expect(count).to.equal(1); done(); }, 200); }); }); }); }); }); describe('#send', function () { it('errors when writing a closed port', function (done) { var port = new SerialPort('/dev/exists', options, false); port.write(new Buffer(''), function(err){ expect(err).to.be.ok; done(); }); }); }); describe('close', function () { it('fires a close event when it\'s closed', function (done) { var port = new SerialPort('/dev/exists', options, function () { var closeSpy = sandbox.spy(); port.on('close', closeSpy); port.close(); expect(closeSpy.calledOnce); done(); }); }); it('fires a close event after being reopened', function (done) { var port = new SerialPort('/dev/exists', options, function () { var closeSpy = sandbox.spy(); port.on('close', closeSpy); port.close(); port.open(); port.close(); expect(closeSpy.calledTwice); done(); }); }); it('errors when closing an invalid port', function (done) { var port = new SerialPort('/dev/exists', options, false); port.close(function(err){ expect(err).to.be.ok; done(); }); }); it('emits a close event', function (done) { var port = new SerialPort('/dev/exists', options, function () { port.on('close', function () { done(); }); port.close(); }); }); }); describe('disconnect', function () { it('fires a disconnect event', function (done) { options.disconnectedCallback = function (err) { expect(err).to.be.ok; done(); }; var port = new SerialPort('/dev/exists', options, function () { hardware.disconnect('/dev/exists'); }); }); it('emits a disconnect event', function (done) { var port = new SerialPort('/dev/exists', options, function () { port.on('disconnect', function () { done(); }); hardware.disconnect('/dev/exists'); }); }); }); });