Skip to content

Commit

Permalink
Merge branch 'refactor-index'
Browse files Browse the repository at this point in the history
  • Loading branch information
schw4rzlicht committed Jun 6, 2020
2 parents 1d4fe34 + 342f847 commit a20e44f
Show file tree
Hide file tree
Showing 14 changed files with 2,921 additions and 271 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ npm install -g twitch2ma

## Configuration

Before you can run `twitch2ma` you need a config file in JSON or YAML format. A sample JSON file is
[located in the root directory](https://github.com/schw4rzlicht/twitch2ma/blob/master/config.json.sample) of the
repository and ships with the npm package.
Before you can run `twitch2ma` you need a config file in JSON or YAML format. A sample files are
located in the root directory ([JSON](config.json.sample) / [YAML](config.yml.sample)])
of the repository and ships with the npm package.

Find a detailed description of every option [here](docs/config.md).

Expand Down
2 changes: 1 addition & 1 deletion __tests__/Config.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Config, MaConfig, TwitchConfig, Command, Parameter} from "../lib/Config";
import {Config, MaConfig, TwitchConfig, Command, Parameter} from "../src/lib/Config";

import Fs = require("fs");

Expand Down
67 changes: 57 additions & 10 deletions __tests__/Twitch2Ma.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {TelnetError, ChannelError} from "../lib/Twitch2Ma";
import Twitch2Ma from "../lib/Twitch2Ma";
import {Config} from "../lib/Config";
import {TelnetError, ChannelError} from "../src/lib/Twitch2Ma";
import Twitch2Ma from "../src/lib/Twitch2Ma";
import {Config} from "../src/lib/Config";
import TwitchPrivateMessage from "twitch-chat-client/lib/StandardCommands/TwitchPrivateMessage";

import TwitchChatClient from "twitch-chat-client";
Expand All @@ -24,7 +24,11 @@ test("Connection chain", async () => {
let spyOnInitTwitch = jest.spyOn(twitch2Ma, "initTwitch");
let spyOnOnError = jest.spyOn(twitch2Ma, "onError");

expect.assertions(6);
let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();

twitch2Ma.onTelnetConnected(spyOnOnTelnetConnected);
twitch2Ma.onTwitchConnected(spyOnOnTwitchConnected);

await expect(twitch2Ma.start()).resolves.toBeUndefined();

Expand All @@ -33,33 +37,66 @@ test("Connection chain", async () => {
expect(spyOnInitTwitch).toBeCalled();
expect(twitch2Ma["chatClient"].join).toBeCalled();

expect(spyOnOnTelnetConnected).toBeCalledWith(config.ma.host, config.ma.user);
expect(spyOnOnTwitchConnected).toBeCalledWith(config.twitch.channel);

expect(spyOnOnError).not.toBeCalled();
});

test("Telnet connection failed", () => {
test("Telnet connection failed", async () => {

let twitch2Ma = new Twitch2Ma(config);

jest.spyOn(twitch2Ma["telnet"], "connect").mockRejectedValueOnce("Fooled!");

return expect(twitch2Ma.start()).rejects.toThrow(new TelnetError("Could not connect to desk!"));
let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();

twitch2Ma.onTelnetConnected(spyOnOnTelnetConnected);
twitch2Ma.onTwitchConnected(spyOnOnTwitchConnected);

await expect(twitch2Ma.start()).rejects.toThrow(new TelnetError("Could not connect to desk!"));

expect(spyOnOnTelnetConnected).not.toBeCalled();
expect(spyOnOnTwitchConnected).not.toBeCalled();
});

test("Telnet login fails", () => {
return expect(new Twitch2Ma(config).start()).rejects
test("Telnet login failed", async () => {

let twitch2Ma = new Twitch2Ma(config);

let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();

twitch2Ma.onTelnetConnected(spyOnOnTelnetConnected);
twitch2Ma.onTwitchConnected(spyOnOnTwitchConnected);

await expect(twitch2Ma.start()).rejects
.toThrow(new TelnetError(`Could not log into the desk as user ${config.ma.user}!`));

expect(spyOnOnTelnetConnected).not.toBeCalled();
expect(spyOnOnTwitchConnected).not.toBeCalled();
});

test("Twitch connection failed", () => {
test("Twitch connection failed", async () => {

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();

let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();

twitch2Ma.onTelnetConnected(spyOnOnTelnetConnected);
twitch2Ma.onTwitchConnected(spyOnOnTwitchConnected);

jest.spyOn(TwitchChatClient, "forTwitchClient")
.mockImplementationOnce(() => {
throw Error("Not this time!");
});

return expect(twitch2Ma.start()).rejects.toThrow(new Error("Not this time!"));
await expect(twitch2Ma.start()).rejects.toThrow(new Error("Not this time!"));

expect(spyOnOnTelnetConnected).toBeCalledWith(config.ma.host, config.ma.user);
expect(spyOnOnTwitchConnected).not.toBeCalled();
});

test("Twitch channel join failed", async () => {
Expand All @@ -74,11 +111,21 @@ test("Twitch channel join failed", async () => {
let errorHandler = jest.fn();

let twitch2Ma = getTwitch2MaInstanceAndEnableLogin();

let spyOnOnTelnetConnected = jest.fn();
let spyOnOnTwitchConnected = jest.fn();

twitch2Ma.onTelnetConnected(spyOnOnTelnetConnected);
twitch2Ma.onTwitchConnected(spyOnOnTwitchConnected);

twitch2Ma.onError(errorHandler);
await twitch2Ma.start();

expect(twitch2Ma["chatClient"].join).toBeCalled();
expect(errorHandler).toBeCalledWith(new ChannelError());

expect(spyOnOnTelnetConnected).toBeCalledWith(config.ma.host, config.ma.user);
expect(spyOnOnTwitchConnected).not.toBeCalled();
})

test("Message handler set", async () => {
Expand Down
119 changes: 119 additions & 0 deletions __tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import * as index from "../src/lib/index";
import {Config} from "../src/lib/Config";
import Twitch2Ma from "../src/lib/Twitch2Ma";

import Fs = require("fs");
import _ = require("lodash");

jest.mock("../src/lib/Twitch2Ma");

test("Update notification", () => {

const packageInformation = require("../package.json");
const higherVersion = require("semver/functions/inc")(packageInformation.version, "major");

let consoleSpy = jest.spyOn(console, "log").mockImplementationOnce(() => {});

index.notifyUpdate({version: higherVersion});

expect(consoleSpy).toBeCalledWith(
expect.stringMatching("A new version of \\w+ is available!"));
});

test("Event handlers attached", () => {

let twitch2Ma = new Twitch2Ma(loadConfig());

// For unknown reasons jest.mock() removes these...
twitch2Ma.onTelnetConnected = jest.fn();
twitch2Ma.onTwitchConnected = jest.fn();
twitch2Ma.onCommandExecuted = jest.fn();
twitch2Ma.onHelpExecuted = jest.fn();
twitch2Ma.onError = jest.fn();

index.attachEventHandlers(twitch2Ma);

expect(twitch2Ma.onTelnetConnected).toBeCalled();
expect(twitch2Ma.onTwitchConnected).toBeCalled();
expect(twitch2Ma.onCommandExecuted).toBeCalled();
expect(twitch2Ma.onHelpExecuted).toBeCalled();
expect(twitch2Ma.onError).toBeCalled();
});

test("Load JSON config successful", () => {
return expect(index.loadConfig("config.json.sample")).resolves.toMatchObject(loadConfig());
});

test("Load YAML config successful", () => {
return expect(index.loadConfig("config.yml.sample")).resolves.toMatchObject(loadConfig());
});

test("File does not exist", () => {
return expect(index.loadConfig("doesNotExist.json")).rejects
.toHaveProperty("message", "ENOENT: no such file or directory, open 'doesNotExist.json'");
});

test("Default config.json loaded", async () => {

let configTmp = secureConfigFile();
Fs.copyFileSync("config.json.sample", "config.json");

await expect(index.loadConfig(null)).resolves.toMatchObject(loadConfig());

Fs.unlinkSync("config.json");
restoreConfigFile(configTmp);
});

test("Invalid config file", async () => {

let configTmp = secureConfigFile();
Fs.writeFileSync("config.json", "{ invalid-json: haha ");

await expect(index.loadConfig(null)).rejects.toMatchObject(new Error("Config file config.json is not a valid JSON or YAML file!"));

Fs.unlinkSync("config.json");
restoreConfigFile(configTmp);
});

test("Invalid config", async () => {

let configTmp = secureConfigFile();
Fs.writeFileSync("config.json", "{ everything-missing: true }");

await expect(index.loadConfig(null)).rejects.toBeInstanceOf(Error);

Fs.unlinkSync("config.json");
restoreConfigFile(configTmp);
});

test("Exit with error", () => {

let consoleSpy = jest.spyOn(console, "error").mockImplementationOnce(() => {});

// @ts-ignore
let exitSpy = jest.spyOn(process, "exit").mockImplementationOnce(() => {});

index.exitWithError(new Error("Fuck dat!"));

expect(consoleSpy).toHaveBeenCalledWith(expect.stringMatching("Fuck dat! Exiting..."));
expect(exitSpy).toHaveBeenCalledWith(1);
});

function loadConfig(overrideConfigValues?: any): Config {
return new Config(_.assign({}, JSON.parse(Fs.readFileSync("config.json.sample", {encoding: "utf-8"})), overrideConfigValues));
}

function secureConfigFile() {
let oldFilename = "config.old" + new Date().getTime() + ".json";
if(Fs.existsSync("config.json")) {
Fs.renameSync("config.json", oldFilename);
return oldFilename;
}
return null;
}

function restoreConfigFile(configTmp: string) {
if(_.isString(configTmp)) {
Fs.renameSync(configTmp, "config.json");
}
}
2 changes: 1 addition & 1 deletion cli.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env node

require("./dist/lib/index");
require("./dist/lib/index").main();
39 changes: 39 additions & 0 deletions config.yml.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
timeout: 20
ma:
host: "192.168.0.20"
user: "administrator"
password: "admin"
twitch:
clientId: "yourClientID"
accessToken: "yourAccessToken"
channel: "yourTwitchChannel"
commands:
-
chatCommand: "red"
consoleCommand: "Macro 1"
message: "{user} set the lights to red!"
help: "Sets the lights to red"
-
chatCommand: "blue"
consoleCommand: "Macro 2"
message: "{user} set the lights to blue!"
help: "Sets the lights to blue"
-
chatCommand: "yellow"
consoleCommand: "Macro 3"
-
chatCommand: "textOnly"
message: "Heyyy {user}!"
-
chatCommand: "gobo"
help: "Gobo commands. {parameterList}"
parameters:
-
parameter: "niceGobo"
consoleCommand: "Macro 4"
-
parameter: "evenNicerGobo"
consoleCommand: "Macro 5"
message: "{user} wishes the 'evenNicerGobo'!"

2 changes: 1 addition & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Config details

Find an example `config.json` [here](../config.json.sample).
Find an example `config.json` [here](../config.json.sample) and an example `config.yml` [here](../config.yml.sample).

| Property | Type | Required | Description | Default |
|:-----------------------------------|:-------|:---------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------|
Expand Down
82 changes: 0 additions & 82 deletions lib/index.ts

This file was deleted.

Loading

0 comments on commit a20e44f

Please sign in to comment.