Skip to content

Commit

Permalink
Add error boundary tests for routes
Browse files Browse the repository at this point in the history
  • Loading branch information
Gum-Joe committed Oct 2, 2020
1 parent 3e23567 commit ddb18d8
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 6 deletions.
1 change: 1 addition & 0 deletions packages/@twokeys/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* Requires config to be given
* @packageDocumentation
*/
// TODO: Config validation of everything
import { promises as fs } from "fs";
import YAML from "yaml";
import { MainConfig, DetectorConfig, ClientConfig, ProjectConfig, CombinedConfigs, AddConfigUtils, MakeKeysOptional, ConfigUtils } from "./interfaces";
Expand Down
2 changes: 1 addition & 1 deletion packages/@twokeys/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const server = async (port: number = DEFAULT_PORT, argv: ServerArgs, projectDir:
// Error handler
app.use((err, req, res, next) => {
logger.err(`An error was encountered on router ${req.originalUrl}`);
logger.throw_noexit(err);
logger.printError(err);
next(err);
});

Expand Down
3 changes: 2 additions & 1 deletion packages/@twokeys/server/src/routes/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export default async function getAPI(projectConfig: ProjectConfig, projectDir: s
* }
* ```
*/
router.post("/post/:detector/:keyboard/trigger", getTriggerHotkey(detectors, executors));
router.post("/post/trigger/:detector/:keyboard", getTriggerHotkey(detectors, executors));

/**
* Trigger a hotkey
Expand Down Expand Up @@ -182,6 +182,7 @@ export default async function getAPI(projectConfig: ProjectConfig, projectDir: s
/**
* Handles keyboard path update
*/
// TODO: Update this route to use whatever new method for config updates we decide on
router.post("/post/update-keyboard-path", (req, res, next) => {
const { keyboard, path } = req.body;
logger.info(`Got update for ${keyboard}, path ${path}`);
Expand Down
10 changes: 8 additions & 2 deletions packages/@twokeys/server/src/routes/triggerHotkey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function isMultiHotkey(hotkey: Hotkey): hotkey is HotkeyTypeKeypressValue {
* @param executors Loaded executors
*/
// TODO: Execute on a different thread, because the server hangs and fails any in progress runs if it is still waiting for this
// TODO: Normalise hotkeys so they are all in lowercase, since ^A and ^a are the same key. (might not be needed though, as detectors should read directly from config)
async function executeHotKey(hotkey: HotkeyTypeSingle, hotkeyCode: string, keyboard: Keyboard, executors: ExtractGeneric<ReturnType<typeof loadExecutors>>): Promise<void> {
logger.info(`Executing hotkey ${hotkey}...`);
const executorToCall = hotkey.executor || keyboard.executors.default;
Expand Down Expand Up @@ -70,6 +71,7 @@ async function executeHotKey(hotkey: HotkeyTypeSingle, hotkeyCode: string, keybo
*
* @param detectors Loaded detector configs to use
* @param executor Loaded executors from registry
* @returns Exprss route handler for triggering a hotkey
*/
const getTriggerHotkey = (detectors: Map<string, DetectorConfig>, executors: ExtractGeneric<ReturnType<typeof loadExecutors>>): RequestHandler => {
return function (req, res, next): void {
Expand Down Expand Up @@ -111,7 +113,7 @@ const getTriggerHotkey = (detectors: Map<string, DetectorConfig>, executors: Ext
}
const detector = detectors.get(detectorName) as DetectorConfig;
if (hasOwnProperty(detector.keyboards, keyboardName)) { // Check the keyboard is present
logger.debug(`Keybaord ${keyboardName} found`);
logger.debug(`Keyboard ${keyboardName} found`);
const keyboard = detector.keyboards[keyboardName];

if (!hasOwnProperty(keyboard.hotkeys, hotkey)) { // Check hotkey is present
Expand All @@ -129,7 +131,11 @@ const getTriggerHotkey = (detectors: Map<string, DetectorConfig>, executors: Ext
if (isMultiHotkey(theHotkey)) {
logger.debug("Got a multi type hotkey!");
if (typeof theHotkey[eventType] !== "object") {
return next(new CodedError(`Hotkey event ${eventType} not found!`, ERR_BAD_EVENT_TYPE));
res.statusCode = 422;
res.json({
message: `Hotkey event type ${eventType} not found`
});
return;
} else {
configToGive = theHotkey[eventType] as HotkeyTypeSingle;
}
Expand Down
99 changes: 98 additions & 1 deletion packages/@twokeys/server/test/routes/new-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { expect } from "chai";
import sinon from "sinon";
import { constants } from "@twokeys/core";

let agent;
let agent: request.SuperAgentTest;


describe("New API tests", () => {
Expand Down Expand Up @@ -81,5 +81,102 @@ describe("New API tests", () => {
});
});

describe("/post/trigger/:detector/:keyboard", () => {
it("should return 422 when an invalid post body is sent", (done) => {
agent
.post("/api/post/trigger/someDetector/someKDB")
.expect(422)
.end((err, res) => {
if (err) { done(err); }
expect(res.body).to.deep.equal({
message: "Invalid POST body! Properties were missing!"
});
done();
});
});
it("should return 422 when the hotkey proeprty is missing from the body", (done) => {
agent
.post("/api/post/trigger/someDetector/someKDB")
.send({ event: "down" })
.expect(422)
.end((err, res) => {
if (err) { done(err); }
expect(res.body).to.deep.equal({
message: "Invalid POST body! Properties were missing!"
});
done();
});
});
it("should not accept an invalid event field", (done) => {
agent
.post("/api/post/trigger/someDetector/someKDB")
.send({ hotkey: "^A", event: "NOT AN EVENT" })
.expect(422)
.end((err, res) => {
if (err) { done(err); }
expect(res.body).to.deep.equal({
message: "Bad event field given!"
});
done();
});
});

it("should return 404 when triggering a detector or hotkey that was not found", (done) => {
agent
.post("/api/post/trigger/someDetector/someKDB")
.send({ hotkey: "^A" })
.expect(404)
.end((err, res) => {
if (err) { done(err); }
expect(res.body).to.deep.equal({
message: "Detector Not Found"
});
done();
});
});

it("should return 404 when a keyboard is not found", (done) => {
agent
.post("/api/post/trigger/Test Detector/someKDB")
.send({ hotkey: "^A" })
.expect(404)
.end((err, res) => {
if (err) { done(err); }
expect(res.body).to.deep.equal({
message: "Keyboard Not Found"
});
done();
});
});

it("should return 404 when a hotkey is not found", (done) => {
agent
.post("/api/post/trigger/Test Detector/keyboard_1")
.send({ hotkey: "NotAHotkey" })
.expect(404)
.end((err, res) => {
if (err) { done(err); }
expect(res.body).to.deep.equal({
message: "Hotkey Not Found"
});
done();
});
});

it("should return 422 when a hotkey event type is not found", (done) => {
agent
.post("/api/post/trigger/Test Detector/keyboard_1")
.send({ hotkey: "+C", event: "hold" })
.expect(422)
.end((err, res) => {
if (err) { done(err); }
expect(res.body).to.deep.equal({
message: "Hotkey event type hold not found"
});
done();
});
});
});

after(() => sinon.restore());
});
2 changes: 1 addition & 1 deletion packages/@twokeys/server/test/util/copy-contents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const { expect } = chai;
// Consts
const MOCK_ROOT_COPY = join(MOCK_ROOT, "../non-mocha-copy");

describe("Copy contents of folder function test", () => {
describe.skip("Copy contents of folder function test", () => {

it("should successfully copy contents of a dir to another", async () => {
await copy_contents(MOCK_ROOT, MOCK_ROOT_COPY);
Expand Down
10 changes: 10 additions & 0 deletions packages/@twokeys/server/testing/project/detector-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ detector_config: # Schema specified by detector; this configures the detector
cli-args: --debug # CLI args for detector

keyboards: # Specifies keybaord and hotkeys
malformed_KD:
hotkeys:
^A: ""
keyboard_1:
root: ./Keyboard_1 # Root folder where macro file (e.g. .ahk files) are
executors:
Expand All @@ -27,6 +30,13 @@ keyboards: # Specifies keybaord and hotkeys
^A: # Ultmately the keycodes is up to the detector to decide
executor: "@twokeys/executor-ahk" # If default, don't need to give this
func: CallFunc
+C:
up:
executor: "@twokeys/executor-ahk"
func: CallFunc # AHK function to call
down:
executor: executor-ahk
func: add-ons/packs/essentials-pack/TestIfWorking # Use function TestIfWorking from pack essentials-pack
^B:
up:
executor: "@twokeys/executor-ahk"
Expand Down

0 comments on commit ddb18d8

Please sign in to comment.