Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unit tests draft #100

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
561 changes: 552 additions & 9 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
"build:node": "tsc",
"build:browser": "webpack --mode=production",
"build:all": "npm run build:node && npm run build:browser",
"lint": "tslint -c tslint.json \"./src/**/*.ts\"",
"lint": "tslint -c tslint.json \"./src/**/*.ts\" \"./test/**/*.ts\"",
"build": "npm run lint && npm run build:all",
"docs": "jsdoc -d docs -c jsdoc.conf.json -t ./node_modules/ink-docstrap/template -R README.md dist/node/**/*.js",
"all": "npm run build && npm run docs",
"prepublishOnly": "npm run lint && npm run build:node"
"all": "npm run build:all && npm run docs",
"prepublishOnly": "npm run lint && npm run build:node",
"test": "ts-mocha test/*.ts"
},
"author": "Nathan Kellenicki <nathan@kellenicki.com>",
"license": "MIT",
Expand All @@ -24,12 +25,15 @@
},
"devDependencies": {
"@types/debug": "4.1.5",
"@types/mocha": "^7.0.2",
"@types/node": "^14.14.14",
"@types/web-bluetooth": "0.0.9",
"buffer": "^6.0.3",
"ink-docstrap": "^1.3.2",
"jsdoc": "^3.6.6",
"jsdoc-to-markdown": "^6.0.1",
"mocha": "^8.0.1",
"ts-mocha": "^7.0.0",
"ts-loader": "^8.0.12",
"tslint": "^6.1.3",
"typescript": "^4.1.3",
Expand Down
4 changes: 2 additions & 2 deletions src/hubs/basehub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,13 @@ export class BaseHub extends EventEmitter {
* @param {number} deviceType The device type to lookup.
* @returns {Promise} Resolved once a device is attached, or resolved immediately if a device is already attached.
*/
public waitForDeviceByType (deviceType: number) {
public waitForDeviceByType (deviceType: number): Promise<Device> {
return new Promise((resolve) => {
const existingDevices = this.getDevicesByType(deviceType);
if (existingDevices.length >= 1) {
return resolve(existingDevices[0]);
}
this._attachCallbacks.push((device) => {
this._attachCallbacks.push((device: Device) => {
if (device.type === deviceType) {
resolve(device);
return true;
Expand Down
8 changes: 6 additions & 2 deletions src/hubs/lpf2hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,13 @@ export class LPF2Hub extends BaseHub {


private _requestHubPropertyValue (property: number) {
return new Promise<void>((resolve) => {
return new Promise<void>((resolve, reject) => {
this._propertyRequestCallbacks[property] = (message) => {
this._parseHubPropertyResponse(message);
try {
this._parseHubPropertyResponse(message);
} catch (error) {
return reject(error);
}
return resolve();
};
this.send(Buffer.from([0x01, property, 0x05]), Consts.BLECharacteristic.LPF2_ALL);
Expand Down
8 changes: 8 additions & 0 deletions test/devices.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import hubLED from "./devices/hubled";
import remoteControlButton from "./devices/remotecontrolbutton";


export default function devices() {
describe("Hub LED", hubLED);
describe("Remote control button", remoteControlButton);
};
36 changes: 36 additions & 0 deletions test/devices/hubled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { ok } from "assert";

import { FakeBLEDevice } from "../utils/fakebledevice";
import { getAttachMessage, includeMessage } from "../utils/commons";

import { LPF2Hub } from "../../src/hubs/lpf2hub";
import * as Consts from "../../src/consts";

import { HubLED } from "../../src/devices/hubled";


export default function hubled() {
let bleDevice: FakeBLEDevice
let hub: LPF2Hub;
let device: HubLED

beforeEach(async () => {
bleDevice = new FakeBLEDevice("fakebledevice", "LPF2 Hub");
hub = new LPF2Hub(bleDevice, {A: 0, B: 1});
await hub.connect()
bleDevice.send(getAttachMessage(0, Consts.DeviceType.HUB_LED));
device = await hub.waitForDeviceByType(Consts.DeviceType.HUB_LED) as HubLED;
})

it('should set color to BLUE using color codes', () => {
device.setColor(Consts.Color.BLUE)
includeMessage(bleDevice, "0a004100000100000001"); // Set mode to COLOR
includeMessage(bleDevice, "0800810011510003"); // Send color command
})

it('should set color to RED using RGB', () => {
device.setRGB(255, 0, 0)
includeMessage(bleDevice, "0a004100010100000001"); // Set mode to RGB
includeMessage(bleDevice, "0a008100115101ff0000"); // Send color command
})
}
43 changes: 43 additions & 0 deletions test/devices/remotecontrolbutton.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { strictEqual } from "assert";

import { FakeBLEDevice } from "../utils/fakebledevice";
import { getAttachMessage, includeMessage } from "../utils/commons";

import { LPF2Hub } from "../../src/hubs/lpf2hub";
import * as Consts from "../../src/consts";

import { RemoteControlButton, ButtonState } from "../../src/devices/remotecontrolbutton";

export default function remoteControlButton() {
let bleDevice: FakeBLEDevice
let hub: LPF2Hub;
let device: RemoteControlButton;

function testEvent(eventType: number, eventContant: number) {
return done => {
device.on('remoteButton', ({event})=> {
strictEqual(event, eventContant);
done()
});
const message = Buffer.alloc(3);
message[0] = 0x45;
message[1] = 0;
message[2] = eventType;
bleDevice.send(message);
}
}

beforeEach(async () => {
bleDevice = new FakeBLEDevice("fakebledevice", "LPF2 Hub");
hub = new LPF2Hub(bleDevice, {A: 0, B: 1});
await hub.connect()
bleDevice.send(getAttachMessage(0, Consts.DeviceType.REMOTE_CONTROL_BUTTON));
device = await hub.waitForDeviceByType(Consts.DeviceType.REMOTE_CONTROL_BUTTON) as RemoteControlButton;
})

it('should detect UP', testEvent(0x01, ButtonState.UP))
it('should detect DOWN', testEvent(0xff, ButtonState.DOWN))
it('should detect STOP', testEvent(0x7f, ButtonState.STOP))
it('should detect RELEASED', testEvent(0x00, ButtonState.RELEASED))

}
16 changes: 16 additions & 0 deletions test/hubs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import moveHub from "./hubs/movehub";
import technicMediumHub from "./hubs/technicmediumhub";
import hub from "./hubs/hub";
import duploTrainBase from "./hubs/duplotrainbase";
import remoteControl from "./hubs/remotecontrol";
import lpf2Hub from "./hubs/lpf2";


export default function hubs() {
describe("Technic Medium Hub", technicMediumHub);
describe("PoweredUp Hub", hub);
describe("Boost Move Hub", moveHub);
describe("Duplo Train Base", duploTrainBase);
describe("Remote controller", remoteControl);
describe("Common LPF2 methods", lpf2Hub);
};
15 changes: 15 additions & 0 deletions test/hubs/duplotrainbase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FakeBLEDevice } from "../utils/fakebledevice";
import {commonsConnectTests } from '../utils/commons';

import { DuploTrainBase } from "../../src/hubs/duplotrainbase";

export default function duploTrainBase() {
const state = { connectEvent: false };
const bleDevice = new FakeBLEDevice("fakebledevice", "Duplo Train Base")
const hub = new DuploTrainBase(bleDevice);
hub.on("connect", () => state.connectEvent = true);
describe("connect", () => {
before(async () => await hub.connect());
commonsConnectTests(state, hub, bleDevice);
});
}
25 changes: 25 additions & 0 deletions test/hubs/hub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { rejects } from "assert";

import { FakeBLEDevice } from "../utils/fakebledevice";
import {commonsConnectTests } from '../utils/commons';

import { Hub } from "../../src/hubs/hub";

export default function hub() {
const state = { connectEvent: false };
const bleDevice = new FakeBLEDevice("fakebledevice", "PoweredUp Hub", "1.1.00.0004")
const hub = new Hub(bleDevice);
hub.on("connect", () => state.connectEvent = true);

describe("connect", () => {
before(async () => await hub.connect());
it("should reject due to unsupported firmware (<1.1.00.0004)", async () => {
const badHub = new Hub(new FakeBLEDevice("fakebledevice", "PoweredUp Hub", "1.1.00.0003"));
await rejects(
async () => await badHub.connect(),
{ name: "Error", message: "Your Powered Up Hub's (PoweredUp Hub) firmware is out of date and unsupported by this library. Please update it via the official Powered Up app." }
)
});
commonsConnectTests(state, hub, bleDevice, "1.1.00.0004");
});
}
136 changes: 136 additions & 0 deletions test/hubs/lpf2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { strictEqual, ok } from "assert";

import { FakeBLEDevice } from "../utils/fakebledevice";
import { getAttachMessage, includeMessage } from "../utils/commons";

import { LPF2Hub } from "../../src/hubs/lpf2hub";
import * as Consts from "../../src/consts";

import { Device } from "../../src/devices/device"
import { ColorDistanceSensor } from "../../src/devices/colordistancesensor"
import { SimpleMediumLinearMotor } from "../../src/devices/simplemediumlinearmotor";
import { TrainMotor } from "../../src/devices/trainmotor";
import { Light } from "../../src/devices/light";
import { VoltageSensor } from "../../src/devices/voltagesensor";
import { CurrentSensor } from "../../src/devices/currentsensor";
import { PiezoBuzzer } from "../../src/devices/piezobuzzer";
import { HubLED } from "../../src/devices/hubled";
import { TiltSensor } from "../../src/devices/tiltsensor";
import { MotionSensor } from "../../src/devices/motionsensor";
import { MediumLinearMotor } from "../../src/devices/mediumlinearmotor";
import { MoveHubMediumLinearMotor } from "../../src/devices/movehubmediumlinearmotor";
import { MoveHubTiltSensor } from "../../src/devices/movehubtiltsensor";
import { DuploTrainBaseMotor } from "../../src/devices/duplotrainbasemotor";
import { DuploTrainBaseSpeaker } from "../../src/devices/duplotrainbasespeaker";
import { DuploTrainBaseColorSensor } from "../../src/devices/duplotrainbasecolorsensor";
import { DuploTrainBaseSpeedometer } from "../../src/devices/duplotrainbasespeedometer";
import { TechnicLargeLinearMotor } from "../../src/devices/techniclargelinearmotor";
import { TechnicLargeAngularMotor } from "../../src/devices/techniclargeangularmotor";
import { TechnicMediumAngularMotor } from "../../src/devices/technicmediumangularmotor";
import { TechnicXLargeLinearMotor } from "../../src/devices/technicxlargelinearmotor";
import { RemoteControlButton } from "../../src/devices/remotecontrolbutton";
import { TechnicMediumHubAccelerometerSensor } from "../../src/devices/technicmediumhubaccelerometersensor";
import { TechnicMediumHubGyroSensor } from "../../src/devices/technicmediumhubgyrosensor";
import { TechnicMediumHubTiltSensor } from "../../src/devices/technicmediumhubtiltsensor";
import { TechnicColorSensor } from "../../src/devices/techniccolorsensor";
import { TechnicDistanceSensor } from "../../src/devices/technicdistancesensor";
import { TechnicForceSensor } from "../../src/devices/technicforcesensor";

export default function lpf2Hub() {
let bleDevice: FakeBLEDevice
let hub: LPF2Hub;

function deviceAttach(type: number, Constructor: typeof Device) {
return () => {
it("should emit an 'attach' event with device", done => {
hub.on("attach", device => {
strictEqual(device.type, type);
ok(device instanceof Constructor);
done();
});

bleDevice.send(getAttachMessage(0, type));
});

it("should resolve 'waitForDeviceByType'", done => {
hub.waitForDeviceByType(type).then((d) => {
const device = d as Device;
strictEqual(device.type, type);
ok(device instanceof Constructor);
done();
});

bleDevice.send(getAttachMessage(0, type));
});
};
}

beforeEach(async () => {
bleDevice = new FakeBLEDevice("fakebledevice", "LPF2 Hub");
hub = new LPF2Hub(bleDevice, {A: 0, B: 1});
await hub.connect()
});

describe("attach", () => {
describe("waitForDeviceAtPort", () => {
it("should resolve with already attached device", async () => {
await bleDevice.send(getAttachMessage(0, Consts.DeviceType.UNKNOWN));
const device = await hub.waitForDeviceAtPort("A") as Device;

strictEqual(device.type, Consts.DeviceType.UNKNOWN);
ok(device instanceof Device);
return;
});

it("should resolve when device attached", done => {
hub.waitForDeviceAtPort("A").then(d=> {
const device = d as Device;
strictEqual(device.type, Consts.DeviceType.UNKNOWN);
ok(device instanceof Device);
done();
});
bleDevice.send(getAttachMessage(0, Consts.DeviceType.UNKNOWN));
});
});

describe("Simple Medium Linear Motor", deviceAttach(Consts.DeviceType.SIMPLE_MEDIUM_LINEAR_MOTOR, SimpleMediumLinearMotor));
describe("Train Motor", deviceAttach(Consts.DeviceType.TRAIN_MOTOR, TrainMotor));
describe("Light", deviceAttach(Consts.DeviceType.LIGHT, Light));
describe("Voltage sensor", deviceAttach(Consts.DeviceType.VOLTAGE_SENSOR, VoltageSensor));
describe("Current sensor", deviceAttach(Consts.DeviceType.CURRENT_SENSOR, CurrentSensor));
describe("Piezzo buzzer", deviceAttach(Consts.DeviceType.PIEZO_BUZZER, PiezoBuzzer));
describe("Hub LED", deviceAttach(Consts.DeviceType.HUB_LED, HubLED));
describe("Tilt sensor", deviceAttach(Consts.DeviceType.TILT_SENSOR, TiltSensor));
describe("Motion sensor", deviceAttach(Consts.DeviceType.MOTION_SENSOR, MotionSensor));
describe("Color and distance sensor", deviceAttach(Consts.DeviceType.COLOR_DISTANCE_SENSOR, ColorDistanceSensor));
describe("Medium linear motor", deviceAttach(Consts.DeviceType.MEDIUM_LINEAR_MOTOR, MediumLinearMotor));
describe("Move hub medium linear motor", deviceAttach(Consts.DeviceType.MOVE_HUB_MEDIUM_LINEAR_MOTOR, MoveHubMediumLinearMotor));
describe("Move hub tilt sensor", deviceAttach(Consts.DeviceType.MOVE_HUB_TILT_SENSOR, MoveHubTiltSensor));
describe("Duplo train base motor", deviceAttach(Consts.DeviceType.DUPLO_TRAIN_BASE_MOTOR, DuploTrainBaseMotor));
describe("Duplo train base speaker", deviceAttach(Consts.DeviceType.DUPLO_TRAIN_BASE_SPEAKER, DuploTrainBaseSpeaker));
describe("Duplo train base color sensor", deviceAttach(Consts.DeviceType.DUPLO_TRAIN_BASE_COLOR_SENSOR, DuploTrainBaseColorSensor));
describe("Duplo train base speedometer", deviceAttach(Consts.DeviceType.DUPLO_TRAIN_BASE_SPEEDOMETER, DuploTrainBaseSpeedometer));
describe("Technic large linear motor", deviceAttach(Consts.DeviceType.TECHNIC_LARGE_LINEAR_MOTOR, TechnicLargeLinearMotor));
describe("Technic XL linear motor", deviceAttach(Consts.DeviceType.TECHNIC_XLARGE_LINEAR_MOTOR, TechnicXLargeLinearMotor));
describe("Technic medium angular motor", deviceAttach(Consts.DeviceType.TECHNIC_MEDIUM_ANGULAR_MOTOR, TechnicMediumAngularMotor));
describe("Technic large angular motor", deviceAttach(Consts.DeviceType.TECHNIC_LARGE_ANGULAR_MOTOR, TechnicLargeAngularMotor));
describe("Remote controller button", deviceAttach(Consts.DeviceType.REMOTE_CONTROL_BUTTON, RemoteControlButton));
describe("Remote controller RSSI - Generic device", deviceAttach(Consts.DeviceType.REMOTE_CONTROL_RSSI, Device));
describe("Technic medium hub accelerometer", deviceAttach(Consts.DeviceType.TECHNIC_MEDIUM_HUB_ACCELEROMETER, TechnicMediumHubAccelerometerSensor));
describe("Technic medium hub gyro sensor", deviceAttach(Consts.DeviceType.TECHNIC_MEDIUM_HUB_GYRO_SENSOR, TechnicMediumHubGyroSensor));
describe("Technic medium hub tilt sensor", deviceAttach(Consts.DeviceType.TECHNIC_MEDIUM_HUB_TILT_SENSOR, TechnicMediumHubTiltSensor));
describe("Technic medium hub temperature sensor - Generic device", deviceAttach(Consts.DeviceType.TECHNIC_MEDIUM_HUB_TEMPERATURE_SENSOR, Device));
describe("Technic color sensor", deviceAttach(Consts.DeviceType.TECHNIC_COLOR_SENSOR, TechnicColorSensor));
describe("Technic distance sensor", deviceAttach(Consts.DeviceType.TECHNIC_DISTANCE_SENSOR, TechnicDistanceSensor));
describe("Technic force sensor", deviceAttach(Consts.DeviceType.TECHNIC_FORCE_SENSOR, TechnicForceSensor));
describe("Technic medium angular motor (grey) - Generic device", deviceAttach(Consts.DeviceType.TECHNIC_MEDIUM_ANGULAR_MOTOR_GREY, Device));
describe("Technic large angular motor (grey) - Generic device", deviceAttach(Consts.DeviceType.TECHNIC_LARGE_ANGULAR_MOTOR_GREY, Device));
});

describe("shutdown", () => {
it("should send shutdown message", async () => {
await hub.shutdown();
includeMessage(bleDevice, "04000201");
});
});
}
26 changes: 26 additions & 0 deletions test/hubs/movehub.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { rejects } from "assert";

import { FakeBLEDevice } from "../utils/fakebledevice";
import {commonsConnectTests } from '../utils/commons';

import { MoveHub } from "../../src/hubs/movehub";

export default function moveHub() {
const state = { connectEvent: false };
const bleDevice = new FakeBLEDevice("fakebledevice", "Boost Move Hub", "2.0.00.0017")
const hub = new MoveHub(bleDevice);
hub.on("connect", () => state.connectEvent = true);

describe("connect", () => {
before(async () => await hub.connect());
it("should reject due to unsupported firmware (<2.0.00.0017)", async () => {
const badHub = new MoveHub(new FakeBLEDevice("fakebledevice", "PoweredUp Hub", "2.0.00.0016"));
await rejects(
async () => await badHub.connect(),
{ name: "Error", message: "Your Move Hub's (PoweredUp Hub) firmware is out of date and unsupported by this library. Please update it via the official Powered Up app." }
)
});
commonsConnectTests(state, hub, bleDevice, "2.0.00.0017");
});

}
15 changes: 15 additions & 0 deletions test/hubs/remotecontrol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FakeBLEDevice } from "../utils/fakebledevice";
import {commonsConnectTests } from '../utils/commons';

import { RemoteControl } from "../../src/hubs/remotecontrol";

export default function remoteControl() {
const state = { connectEvent: false };
const bleDevice = new FakeBLEDevice("fakebledevice", "Remote controller")
const hub = new RemoteControl(bleDevice);
hub.on("connect", () => state.connectEvent = true);
describe("connect", () => {
before(async () => await hub.connect());
commonsConnectTests(state, hub, bleDevice);
});
}
Loading