johnny-five
Version:
The JavaScript Arduino Programming Framework.
904 lines (690 loc) • 18.5 kB
JavaScript
var five = require("../lib/johnny-five.js"),
sinon = require("sinon"),
MockFirmata = require("./mock-firmata"),
Board = five.Board,
Led = five.Led;
function newBoard() {
return new Board({
io: new MockFirmata(),
debug: false,
repl: false
});
}
exports["Led - Digital"] = {
setUp: function(done) {
this.board = newBoard();
this.clock = sinon.useFakeTimers();
this.spy = sinon.spy(this.board.io, "digitalWrite");
this.led = new Led({
pin: 13,
board: this.board
});
this.proto = [{
name: "on"
}, {
name: "off"
}, {
name: "toggle"
}, {
name: "brightness"
}, {
name: "pulse"
}, {
name: "fade"
}, {
name: "fadeIn"
}, {
name: "fadeOut"
}, {
name: "strobe"
}, {
name: "blink"
}, {
name: "stop"
}];
this.instance = [{
name: "id"
}, {
name: "pin"
}, {
name: "value"
}, {
name: "interval"
}, {
name: "mode"
}];
done();
},
tearDown: function(done) {
this.clock.restore();
done();
},
shape: function(test) {
test.expect(this.proto.length + this.instance.length);
this.proto.forEach(function(method) {
test.equal(typeof this.led[method.name], "function");
}, this);
this.instance.forEach(function(property) {
test.notEqual(typeof this.led[property.name], "undefined");
}, this);
test.done();
},
defaultMode: function(test) {
test.expect(1);
test.equal(this.led.mode, 1);
test.done();
},
on: function(test) {
test.expect(1);
this.led.on();
test.ok(this.spy.calledWith(13, 1));
test.done();
},
off: function(test) {
test.expect(1);
this.led.off();
test.ok(this.spy.calledWith(13, 0));
test.done();
},
isOn: function(test) {
// https://github.com/rwaldron/johnny-five/issues/351
test.expect(6);
// Start in "off" state
this.led.off();
this.led.strobe(5);
this.clock.tick(6);
this.led.stop();
// After one cycle, the led is on,
// but stopped so not running
// and the value left behind is 1
test.equal(this.led.isOn, true);
test.equal(this.led.isRunning, false);
test.equal(this.led.value, 1);
// Now it will start out ON
this.led.strobe(5);
this.clock.tick(6);
// After one cycle, the led is off,
// but NOT stopped so still running
// and the value left behind is 0
test.equal(this.led.isOn, false);
test.equal(this.led.isRunning, true);
test.equal(this.led.value, 0);
test.done();
},
toggle: function(test) {
test.expect(2);
this.led.off();
this.led.toggle();
test.ok(this.spy.calledWith(13, 1));
this.led.toggle();
test.ok(this.spy.calledWith(13, 0));
test.done();
},
strobe: function(test) {
test.expect(3);
this.led.off();
this.led.strobe(100);
this.clock.tick(100);
test.ok(this.spy.calledWith(13, 1));
this.clock.tick(100);
test.ok(this.spy.calledWith(13, 0));
this.led.stop();
this.clock.tick(100);
test.equal(this.spy.callCount, 3);
test.done();
},
blink: function(test) {
test.expect(1);
test.equal(this.led.blink, this.led.strobe);
test.done();
}
};
exports["Led - PWM (Analog)"] = {
setUp: function(done) {
this.clock = sinon.useFakeTimers();
this.board = newBoard();
this.spy = sinon.spy(this.board.io, "analogWrite");
this.led = new Led({
pin: 11,
board: this.board
});
this.proto = [{
name: "on"
}, {
name: "off"
}, {
name: "toggle"
}, {
name: "brightness"
}, {
name: "pulse"
}, {
name: "fade"
}, {
name: "fadeIn"
}, {
name: "fadeOut"
}, {
name: "strobe"
}, {
name: "blink"
}, {
name: "stop"
}];
this.instance = [{
name: "id"
}, {
name: "pin"
}, {
name: "value"
}, {
name: "interval"
}];
done();
},
tearDown: function(done) {
this.clock.restore();
done();
},
shape: function(test) {
test.expect(this.proto.length + this.instance.length);
this.proto.forEach(function(method) {
test.equal(typeof this.led[method.name], "function");
}, this);
this.instance.forEach(function(property) {
test.notEqual(typeof this.led[property.name], "undefined");
}, this);
test.done();
},
defaultMode: function(test) {
test.expect(1);
test.equal(this.led.mode, 3);
test.done();
},
on: function(test) {
test.expect(1);
this.led.on();
test.ok(this.spy.calledWith(11, 255));
test.done();
},
off: function(test) {
test.expect(1);
this.led.off();
test.ok(this.spy.calledWith(11, 0));
test.done();
},
isOnTrue: function(test) {
// https://github.com/rwaldron/johnny-five/issues/351
// test.expect(3);
// Start in "off" state
this.led.off();
this.led.fade(255, 500);
this.clock.tick(500);
this.led.stop();
// After one cycle, the led is on,
// but stopped so not running
// and the value left behind is 255
test.equal(this.led.isOn, true);
test.equal(this.led.isRunning, false);
test.equal(this.led.value, 255);
test.done();
},
isOnFalse: function(test) {
// https://github.com/rwaldron/johnny-five/issues/351
test.expect(3);
this.led.on();
this.led.fade(0, 500);
this.clock.tick(500);
this.led.stop();
// After one cycle, the led is on,
// but stopped so not running
// and the value left behind is 255
test.equal(this.led.isOn, false);
test.equal(this.led.isRunning, false);
test.equal(this.led.value, 0);
test.done();
},
toggle: function(test) {
test.expect(2);
this.led.off();
this.led.toggle();
test.ok(this.spy.calledWith(11, 255));
this.led.toggle();
test.ok(this.spy.calledWith(11, 0));
test.done();
},
brightness: function(test) {
test.expect(3);
this.led.off();
this.led.brightness(255);
test.ok(this.spy.calledWith(11, 255));
this.led.brightness(100);
test.ok(this.spy.calledWith(11, 100));
this.led.brightness(0);
test.ok(this.spy.calledWith(11, 0));
test.done();
},
pulse: function(test) {
sinon.spy(global, "clearInterval");
sinon.spy(global, "setInterval");
test.expect(3);
this.led.off();
test.equal(this.led.interval, null);
this.led.pulse();
test.equal(setInterval.callCount, 1);
this.led.stop();
test.equal(clearInterval.callCount, 1);
clearInterval.restore();
setInterval.restore();
test.done();
},
autoMode: function(test) {
test.expect(4);
this.led.mode = 1;
this.led.brightness(255);
test.equal(this.led.mode, 3);
this.led.mode = 1;
this.led.pulse();
test.equal(this.led.mode, 3);
this.led.mode = 1;
this.led.fade();
test.equal(this.led.mode, 3);
this.led.strobe();
// pre 0.8.13, this would change to 1
test.equal(this.led.mode, 3);
test.done();
},
fade: function(test) {
test.expect(4);
this.led.fade(50, 500);
this.clock.tick(500);
test.equal(this.led.value, 50);
this.led.fade(0, 500);
this.clock.tick(500);
test.equal(this.led.value, 0);
this.led.fade(0, 500);
this.clock.tick(500);
test.equal(this.led.value, 0);
this.led.fade(255, 500);
this.clock.tick(500);
test.equal(this.led.value, 255);
test.done();
},
fadeIn: function(test) {
test.expect(7);
test.equal(this.led.value, null);
test.equal(this.led.isOn, false);
test.equal(this.led.isRunning, false);
this.led.fadeIn(10);
this.clock.tick(5);
test.equal(this.led.isRunning, true);
this.clock.tick(6);
test.equal(this.led.value, 255);
test.equal(this.led.isOn, true);
test.equal(this.led.isRunning, false);
test.done();
},
fadeOut: function(test) {
test.expect(10);
test.equal(this.led.value, null);
test.equal(this.led.isOn, false);
test.equal(this.led.isRunning, false);
this.led.fadeIn(10);
this.clock.tick(11);
test.equal(this.led.value, 255);
test.equal(this.led.isOn, true);
test.equal(this.led.isRunning, false);
this.led.fadeOut(10);
this.clock.tick(5);
test.equal(this.led.isRunning, true);
this.clock.tick(6);
test.equal(this.led.value, 0);
test.equal(this.led.isOn, false);
test.equal(this.led.isRunning, false);
test.done();
},
fadeCallback: function(test) {
test.expect(1);
var spy = sinon.spy();
this.led.on().fade(0, 100, spy);
this.clock.tick(101);
test.equal(spy.calledOnce, true);
test.done();
},
fadeInCallback: function(test) {
test.expect(1);
var spy = sinon.spy();
this.led.off().fadeIn(spy);
this.clock.tick(1001);
test.equal(spy.calledOnce, true);
test.done();
},
fadeOutCallback: function(test) {
test.expect(1);
var spy = sinon.spy();
this.led.on().fadeOut(spy);
this.clock.tick(1001);
test.equal(spy.calledOnce, true);
test.done();
},
pulseCallback: function(test) {
test.expect(1);
var spy = sinon.spy();
this.led.pulse(spy);
this.clock.tick(1001);
test.equal(spy.calledOnce, true);
test.done();
}
};
// TODO
// exports["Led.Array"] = {
// };
exports["Led.RGB"] = {
setUp: function(done) {
this.board = newBoard();
this.ledRgb = new Led.RGB({
pins: {
red: 9,
green: 10,
blue: 11,
},
board: this.board
});
this.analog = sinon.spy(this.board.io, "analogWrite");
this.proto = [{
name: "on"
}, {
name: "off"
}, {
name: "color"
}, {
name: "toggle"
}, {
name: "strobe"
}, {
name: "blink"
}, {
name: "stop"
}];
this.instance = [{
name: "red"
}, {
name: "green"
}, {
name: "blue"
}, ];
done();
},
shape: function(test) {
test.expect(this.proto.length + this.instance.length);
this.proto.forEach(function(method) {
test.equal(typeof this.ledRgb[method.name], "function");
}, this);
this.instance.forEach(function(property) {
test.notEqual(typeof this.ledRgb[property.name], "undefined");
}, this);
test.done();
},
color: function(test) {
var redPin = 9,
greenPin = 10,
bluePin = 11;
test.expect(9);
this.ledRgb.color("#0000ff");
test.ok(this.analog.calledWith(redPin, 0x00));
test.ok(this.analog.calledWith(greenPin, 0x00));
test.ok(this.analog.calledWith(bluePin, 0xff));
this.ledRgb.color("#ffff00");
test.ok(this.analog.calledWith(redPin, 0xff));
test.ok(this.analog.calledWith(greenPin, 0xff));
test.ok(this.analog.calledWith(bluePin, 0x00));
this.ledRgb.color("#bbccaa");
test.ok(this.analog.calledWith(redPin, 0xbb));
test.ok(this.analog.calledWith(greenPin, 0xcc));
test.ok(this.analog.calledWith(bluePin, 0xaa));
test.done();
},
on: function(test) {
var redPin = 9,
greenPin = 10,
bluePin = 11;
test.expect(18);
// Should default to #ffffff
this.ledRgb.on();
test.ok(this.analog.calledWith(redPin, 255));
test.ok(this.analog.calledWith(greenPin, 255));
test.ok(this.analog.calledWith(bluePin, 255));
var color = this.ledRgb.color();
test.equal(color.red, 255);
test.equal(color.green, 255);
test.equal(color.blue, 255);
// Set a color and make sure .on() doesn't override
this.ledRgb.color("#bbccaa");
this.ledRgb.on();
color = this.ledRgb.color();
test.equal(color.red, 0xbb);
test.equal(color.green, 0xcc);
test.equal(color.blue, 0xaa);
// And that those values are actually live
var values = this.ledRgb.values;
test.equal(values.red, 0xbb);
test.equal(values.green, 0xcc);
test.equal(values.blue, 0xaa);
// Turn led off and back on to see if state restored
this.ledRgb.off();
this.ledRgb.on();
color = this.ledRgb.color();
test.equal(color.red, 0xbb);
test.equal(color.green, 0xcc);
test.equal(color.blue, 0xaa);
values = this.ledRgb.values;
test.equal(values.red, 0xbb);
test.equal(values.green, 0xcc);
test.equal(values.blue, 0xaa);
test.done();
},
off: function(test) {
var redPin = 9,
greenPin = 10,
bluePin = 11;
test.expect(9);
this.ledRgb.color("#bbccaa");
this.ledRgb.off();
test.ok(this.analog.calledWith(redPin, 0));
test.ok(this.analog.calledWith(greenPin, 0));
test.ok(this.analog.calledWith(bluePin, 0));
// Test saved state
var color = this.ledRgb.color();
test.equal(color.red, 0xbb);
test.equal(color.green, 0xcc);
test.equal(color.blue, 0xaa);
// Test live values
var values = this.ledRgb.values;
test.equal(values.red, 0);
test.equal(values.green, 0);
test.equal(values.blue, 0);
test.done();
},
toggle: function(test) {
var redPin = 9,
greenPin = 10,
bluePin = 11,
color,
values;
test.expect(9);
this.ledRgb.color("#bbccaa");
this.ledRgb.toggle();
// Color should still be #bbccaa
// but values should be 0
color = this.ledRgb.color();
test.equal(color.red, 0xbb);
test.equal(color.green, 0xcc);
test.equal(color.blue, 0xaa);
values = this.ledRgb.values;
test.equal(values.red, 0);
test.equal(values.green, 0);
test.equal(values.blue, 0);
this.ledRgb.toggle();
// Should have gone back to #bbccaa
values = this.ledRgb.values;
test.equal(values.red, 0xbb);
test.equal(values.green, 0xcc);
test.equal(values.blue, 0xaa);
test.done();
},
blink: function(test) {
test.expect(1);
test.equal(this.ledRgb.blink, this.ledRgb.strobe);
test.done();
}
};
exports["Led.RGB - Common Anode"] = {
setUp: function(done) {
this.board = newBoard();
this.ledRgb = new Led.RGB({
pins: {
red: 9,
green: 10,
blue: 11,
},
isAnode: true,
board: this.board
});
this.io = {
analogWrite: function(pin, value) {}
};
this.board.io.analogWrite = function(pin, value) {
value = 255 - value;
this.io.analogWrite(pin, value);
}.bind(this);
this.analog = sinon.spy(this.io, "analogWrite");
done();
},
color: function(test) {
var redPin = 9,
greenPin = 10,
bluePin = 11;
test.expect(9);
this.ledRgb.color("#0000ff");
test.ok(this.analog.calledWith(redPin, 0xff));
test.ok(this.analog.calledWith(greenPin, 0xff));
test.ok(this.analog.calledWith(bluePin, 0x00));
this.ledRgb.color("#ffff00");
test.ok(this.analog.calledWith(redPin, 0x00));
test.ok(this.analog.calledWith(greenPin, 0x00));
test.ok(this.analog.calledWith(bluePin, 0xff));
this.ledRgb.color("#bbccaa");
test.ok(this.analog.calledWith(redPin, 0x44));
test.ok(this.analog.calledWith(greenPin, 0x33));
test.ok(this.analog.calledWith(bluePin, 0x55));
test.done();
},
on: function(test) {
var redPin = 9,
greenPin = 10,
bluePin = 11;
test.expect(18);
// Should default to #ffffff
this.ledRgb.on();
test.ok(this.analog.calledWith(redPin, 0));
test.ok(this.analog.calledWith(greenPin, 0));
test.ok(this.analog.calledWith(bluePin, 0));
var color = this.ledRgb.color();
test.equal(color.red, 255);
test.equal(color.green, 255);
test.equal(color.blue, 255);
// Set a color and make sure .on() doesn't override
this.ledRgb.color("#bbccaa");
this.ledRgb.on();
color = this.ledRgb.color();
test.equal(color.red, 0xbb);
test.equal(color.green, 0xcc);
test.equal(color.blue, 0xaa);
// And that those values are actually live
var values = this.ledRgb.values;
test.equal(values.red, 0xbb);
test.equal(values.green, 0xcc);
test.equal(values.blue, 0xaa);
// Turn led off and back on to see if state restored
this.ledRgb.off();
this.ledRgb.on();
color = this.ledRgb.color();
test.equal(color.red, 0xbb);
test.equal(color.green, 0xcc);
test.equal(color.blue, 0xaa);
values = this.ledRgb.values;
test.equal(values.red, 0xbb);
test.equal(values.green, 0xcc);
test.equal(values.blue, 0xaa);
test.done();
},
off: function(test) {
var redPin = 9,
greenPin = 10,
bluePin = 11;
test.expect(9);
this.ledRgb.color("#bbccaa");
this.ledRgb.off();
test.ok(this.analog.calledWith(redPin, 255));
test.ok(this.analog.calledWith(greenPin, 255));
test.ok(this.analog.calledWith(bluePin, 255));
// Test saved state
var color = this.ledRgb.color();
test.equal(color.red, 0xbb);
test.equal(color.green, 0xcc);
test.equal(color.blue, 0xaa);
// Test live values
var values = this.ledRgb.values;
test.equal(values.red, 0);
test.equal(values.green, 0);
test.equal(values.blue, 0);
test.done();
}
};
exports["Led - Default Pin w/ Firmata"] = {
shape: function(test) {
test.expect(8);
test.equal(new Led().pin, 13);
test.equal(new Led(0).pin, 0);
test.equal(new Led("A0").pin, 14);
test.equal(new Led(14).pin, 14);
// 13 & 14 are OUTPUT
test.equal(new Led(13).mode, 1);
test.equal(new Led(14).mode, 1);
// 12 is PWM, but the mechanism is stubbed
sinon.stub(five.Board.Pins.prototype, "isPwm").returns(true);
test.equal(new Led(12).mode, 3);
test.equal(new Led({
type: "PWM"
}).mode, 3);
test.done();
}
};
exports["Led - Pulse"] = {
setUp: function(done) {
this.board = newBoard();
this.clock = sinon.useFakeTimers();
this.spy = sinon.spy(this.board.io, "analogWrite");
this.led = new Led({
pin: 11,
board: this.board
});
done();
},
tearDown: function(done) {
this.clock.restore();
done();
},
pulse: function(test) {
test.expect(1);
// pulse length 1s
this.led.pulse(1000);
// move the clock forwards 1001 ms so we have a complete set of values
this.clock.tick(1001);
// stop pulsing
this.led.stop();
// make sure NaN was not passed to io
test.ok(!isNaN(this.spy.firstCall.args[1]));
test.done();
}
};