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

feat: action tracking #49

Merged
merged 30 commits into from
Sep 25, 2024
Merged
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4c35a7b
feat: add Enumerable class
GeekyEggo Apr 30, 2024
07d2f3e
Merge branch 'main' into action-tracking
GeekyEggo Sep 14, 2024
9dd8a7c
refactor: split Action into KeyAction, DialAction, and KeyInMultiAction
GeekyEggo Sep 14, 2024
683a163
refactor: devices to use store, add initial tracking of actions
GeekyEggo Sep 14, 2024
c062b08
refactor: update Enumerable to be inheritable
GeekyEggo Sep 14, 2024
5041dc3
feat: allow Enumerable to be constructed from another Enumerable
GeekyEggo Sep 14, 2024
23fe625
feat: update action to include device and coordinates
GeekyEggo Sep 14, 2024
62756b8
refactor: update devices to inherit Enumerable
GeekyEggo Sep 14, 2024
7609ea9
style: fix linting
GeekyEggo Sep 14, 2024
b5951f8
feat: track visible actions on devices
GeekyEggo Sep 14, 2024
180bfa0
feat: update events to use Action instance
GeekyEggo Sep 15, 2024
9d4d306
fix: action type
GeekyEggo Sep 15, 2024
e93680a
feat: simplify action store
GeekyEggo Sep 15, 2024
6185074
feat: add type-checking helpers
GeekyEggo Sep 15, 2024
597cd54
test: fix tests
GeekyEggo Sep 15, 2024
20e9210
test: fix tests
GeekyEggo Sep 15, 2024
f5008b4
test: fix tests
GeekyEggo Sep 15, 2024
bf4cd7e
test: fix tests
GeekyEggo Sep 15, 2024
72406b2
style: linting
GeekyEggo Sep 15, 2024
a32e8ba
refactor: update actions to be a service, allowing for it to be itera…
GeekyEggo Sep 15, 2024
995ca5c
feat: add visible actions to SingletonAction
GeekyEggo Sep 18, 2024
0a9fff3
refactor: merge MultiActionKey in KeyAction
GeekyEggo Sep 18, 2024
8a94788
test: mock ActionStore (WIP)
GeekyEggo Sep 22, 2024
d43ed59
refactor: action and device store
GeekyEggo Sep 22, 2024
e3f3ec2
refactor: improve exports
GeekyEggo Sep 22, 2024
625a396
refactor: decouple stores
GeekyEggo Sep 22, 2024
597b89d
chore: fix linting
GeekyEggo Sep 22, 2024
a36d43d
refactor: remove deprecation notice for v1
GeekyEggo Sep 24, 2024
4d0f781
refactor: remove deprecation notice for v1
GeekyEggo Sep 24, 2024
75ec8c2
refactor!: remove deviceId from events, export types over classes
GeekyEggo Sep 24, 2024
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
Prev Previous commit
Next Next commit
test: mock ActionStore (WIP)
GeekyEggo committed Sep 22, 2024
commit 8a94788b1898b163b0812f5485bc471cedd5b259
62 changes: 46 additions & 16 deletions src/plugin/actions/__mocks__/store.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,48 @@
import type { WillAppear, WillDisappear } from "../../../api";
import type { JsonObject } from "../../../common/json";
import { DialAction } from "../dial";
import { KeyAction } from "../key";
import type { ActionContext } from "../store";

const { ActionStore, initializeStore: __initializeStore } = jest.requireActual<typeof import("../store")>("../store");

const key = new KeyAction({
id: "key123",
manifestId: "com.elgato.test.key",
coordinates: {
column: 1,
row: 1
// Mock key.
const key = new KeyAction(
{
id: "key123",
manifestId: "com.elgato.test.key",
device: undefined!,
controller: "Keypad"
},
device: undefined!
});
{
controller: "Keypad",
coordinates: {
column: 1,
row: 1
},
isInMultiAction: false,
settings: {}
}
);

const dial = new DialAction({
id: "dial123",
manifestId: "com.elgato.test.dial",
coordinates: {
column: 1,
row: 1
// Mock dial.
const dial = new DialAction(
{
id: "dial123",
manifestId: "com.elgato.test.dial",
device: undefined!,
controller: "Encoder"
},
device: undefined!
});
{
controller: "Encoder",
coordinates: {
column: 1,
row: 1
},
isInMultiAction: false,
settings: {}
}
);

export const actionStore = {
getActionById: jest.fn().mockImplementation((id) => {
@@ -42,3 +63,12 @@ __initializeStore({

export const initializeStore = jest.fn();
export { ActionStore };

export const createContext = jest.fn().mockImplementation((source: WillAppear<JsonObject> | WillDisappear<JsonObject>) => {
return {
controller: source.payload.controller,
device: undefined!,
id: source.context,
manifestId: source.action
} satisfies ActionContext;
});
164 changes: 44 additions & 120 deletions src/plugin/actions/__tests__/dial.test.ts
Original file line number Diff line number Diff line change
@@ -1,97 +1,70 @@
import { DeviceType, Target, type SetFeedback, type SetFeedbackLayout, type SetImage, type SetTitle, type SetTriggerDescription, type ShowAlert } from "../../../api";
import { type SetFeedback, type SetFeedbackLayout, type SetImage, type SetTriggerDescription, type WillAppear } from "../../../api";
import type { JsonObject } from "../../../common/json";
import { connection } from "../../connection";
import { Device } from "../../devices";
import { Action, type CoordinatedActionContext } from "../action";
import { Action } from "../action";
import { DialAction } from "../dial";
import type { ActionContext } from "../store";

jest.mock("../../logging");
jest.mock("../../manifest");
jest.mock("../../connection");

describe("DialAction", () => {
// Mock device.
const device = new Device(
"dev123",
{
name: "Device One",
size: {
columns: 5,
rows: 3
},
type: DeviceType.StreamDeck
// Mock context.
const context: ActionContext = {
// @ts-expect-error Mocked device.
device: new Device(),
controller: "Keypad",
id: "ABC123",
manifestId: "com.elgato.test.one"
};

// Mock source.
const source: WillAppear<JsonObject>["payload"] = {
controller: "Encoder",
coordinates: {
column: 1,
row: 2
},
false
);
isInMultiAction: false,
settings: {}
};

/**
* Asserts the constructor of {@link DialAction} sets the context.
*/
it("constructor sets context", () => {
// Arrange.
const source: CoordinatedActionContext = {
device,
id: "ABC123",
manifestId: "com.elgato.test.one",
coordinates: {
column: 1,
row: 2
}
};

// Act.
const dialAction = new DialAction(source);

// Assert.
expect(dialAction.coordinates).toBe(source.coordinates);
expect(dialAction.device).toBe(source.device);
expect(dialAction.id).toBe(source.id);
expect(dialAction.manifestId).toBe(source.manifestId);
});

/**
* Asserts the inheritance of {@link DialAction}.
*/
it("inherits shared methods", () => {
// Arrange, act.
const dialAction = new DialAction({
device,
id: "ABC123",
manifestId: "com.elgato.test.one",
coordinates: {
column: 1,
row: 2
}
});
const action = new DialAction(context, source);

// Assert.
expect(dialAction).toBeInstanceOf(Action);
expect(action).toBeInstanceOf(Action);
expect(action.coordinates).not.toBeUndefined();
expect(action.coordinates?.column).toBe(1);
expect(action.coordinates?.row).toBe(2);
expect(action.device).toBe(context.device);
expect(action.id).toBe(context.id);
expect(action.manifestId).toBe(context.manifestId);
});

describe("sending", () => {
const dialAction = new DialAction({
device,
id: "ABC123",
manifestId: "com.elgato.test.one",
coordinates: {
column: 1,
row: 2
}
});
const action = new DialAction(context, source);

/**
* Asserts {@link DialAction.setFeedback} forwards the command to the {@link connection}.
*/
it("setFeedback", async () => {
// Arrange, act.
await dialAction.setFeedback({
await action.setFeedback({
bar: 50,
title: "Hello world"
});

// Assert.
expect(connection.send).toHaveBeenCalledTimes(1);
expect(connection.send).toHaveBeenCalledWith<[SetFeedback]>({
context: dialAction.id,
context: action.id,
event: "setFeedback",
payload: {
bar: 50,
@@ -105,12 +78,12 @@ describe("DialAction", () => {
*/
it("Sends setFeedbackLayout", async () => {
// Arrange, act.
await dialAction.setFeedbackLayout("CustomLayout.json");
await action.setFeedbackLayout("CustomLayout.json");

// Assert.
expect(connection.send).toHaveBeenCalledTimes(1);
expect(connection.send).toHaveBeenCalledWith<[SetFeedbackLayout]>({
context: dialAction.id,
context: action.id,
event: "setFeedbackLayout",
payload: {
layout: "CustomLayout.json"
@@ -123,16 +96,13 @@ describe("DialAction", () => {
*/
it("setImage", async () => {
// Arrange, act
await dialAction.setImage();
await dialAction.setImage("./imgs/test.png", {
state: 1,
target: Target.Hardware
});
await action.setImage();
await action.setImage("./imgs/test.png");

// Assert.
expect(connection.send).toHaveBeenCalledTimes(2);
expect(connection.send).toHaveBeenNthCalledWith<[SetImage]>(1, {
context: dialAction.id,
context: action.id,
event: "setImage",
payload: {
image: undefined,
@@ -142,41 +112,10 @@ describe("DialAction", () => {
});

expect(connection.send).toHaveBeenNthCalledWith<[SetImage]>(2, {
context: dialAction.id,
context: action.id,
event: "setImage",
payload: {
image: "./imgs/test.png",
state: 1,
target: Target.Hardware
}
});
});

/**
* Asserts {@link DialAction.setTitle} forwards the command to the {@link connection}.
*/
it("setTitle", async () => {
// Arrange, act.
await dialAction.setTitle("Hello world");
await dialAction.setTitle("This is a test", { state: 1, target: Target.Software });

// Assert.
expect(connection.send).toHaveBeenCalledTimes(2);
expect(connection.send).toHaveBeenNthCalledWith<[SetTitle]>(1, {
event: "setTitle",
context: "ABC123",
payload: {
title: "Hello world"
}
});

expect(connection.send).toHaveBeenNthCalledWith<[SetTitle]>(2, {
event: "setTitle",
context: "ABC123",
payload: {
state: 1,
target: Target.Software,
title: "This is a test"
image: "./imgs/test.png"
}
});
});
@@ -186,8 +125,8 @@ describe("DialAction", () => {
*/
it("setTriggerDescription", async () => {
// Arrange, act.
await dialAction.setTriggerDescription();
await dialAction.setTriggerDescription({
await action.setTriggerDescription();
await action.setTriggerDescription({
longTouch: "Long-touch",
push: "Push",
rotate: "Rotate",
@@ -198,13 +137,13 @@ describe("DialAction", () => {
expect(connection.send).toHaveBeenCalledTimes(2);
expect(connection.send).toHaveBeenNthCalledWith<[SetTriggerDescription]>(1, {
event: "setTriggerDescription",
context: dialAction.id,
context: action.id,
payload: {}
});

expect(connection.send).toHaveBeenNthCalledWith<[SetTriggerDescription]>(2, {
event: "setTriggerDescription",
context: dialAction.id,
context: action.id,
payload: {
longTouch: "Long-touch",
push: "Push",
@@ -213,20 +152,5 @@ describe("DialAction", () => {
}
});
});

/**
* Asserts {@link DialAction.showAlert} forwards the command to the {@link connection}.
*/
it("showAlert", async () => {
// Arrange, act.
await dialAction.showAlert();

// Assert.
expect(connection.send).toHaveBeenCalledTimes(1);
expect(connection.send).toHaveBeenCalledWith<[ShowAlert]>({
context: dialAction.id,
event: "showAlert"
});
});
});
});
Loading