import { describe, expect, it } from "vitest"; import { ACTION_CONTROLS, ACTION_LAYERS, actionBindingChordLabel, actionBindingId, actionControlForControllerToken, actionControlForKeyboardCode, actionLayerForModifiers, defaultActionBindings, normalizeActionBindings, resetActionBindingLayer, withActionBinding, } from "./actionBindings"; import { defaultActionBarForClass } from "./abilityCatalog"; describe("controller action bindings", () => { it("creates all twenty-four slots and maps the first four abilities to the face diamond", () => { const bindings = defaultActionBindings(["one", "two", "three", "four"]); expect(Object.keys(bindings)).toHaveLength(ACTION_LAYERS.length * ACTION_CONTROLS.length); expect(bindings["primary:face-bottom"]).toBe("one"); expect(bindings["primary:face-left"]).toBe("two"); expect(bindings["primary:face-top"]).toBe("three"); expect(bindings["primary:face-right"]).toBe("four"); expect(bindings["primary:r1"]).toBeNull(); expect(bindings["secondary:face-bottom"]).toBeNull(); }); it("normalizes partial and corrupt saved data against known class abilities", () => { const bindings = normalizeActionBindings({ "primary:face-bottom": "other-class-spell", "primary:face-left": "known-two", madeUp: "known-one", }, ["known-one", "known-two", "known-three"]); expect(bindings["primary:face-bottom"]).toBeNull(); expect(bindings["primary:face-left"]).toBe("known-two"); expect(bindings["primary:face-top"]).toBe("known-three"); expect(Object.keys(bindings)).toHaveLength(24); }); it("places each primary class taunt in the fifth default R1 slot", () => { for (const [classId, tauntId] of [ ["warrior", "warrior-taunt"], ["paladin", "paladin-hand-of-reckoning"], ["death-knight", "death-knight-dark-command"], ["druid", "druid-growl"], ] as const) { const abilities = defaultActionBarForClass(classId); expect(abilities[4]).toBe(tauntId); expect(defaultActionBindings(abilities)["primary:r1"]).toBe(tauntId); } }); it("updates and restores one layer without disturbing the other layers", () => { const defaults = defaultActionBindings(["one", "two", "three", "four"]); const edited = withActionBinding(defaults, "secondary", "r2", "one"); const reset = resetActionBindingLayer(edited, "primary", ["one", "two", "three", "four"]); expect(reset[actionBindingId("secondary", "r2")]).toBe("one"); expect(reset[actionBindingId("primary", "face-bottom")]).toBe("one"); }); it("resolves physical inputs and modifier precedence", () => { expect(actionControlForControllerToken("Button3")).toBe("face-top"); expect(actionControlForControllerToken("Button7")).toBe("r2"); expect(actionControlForControllerToken("Button14")).toBe("dpad-left"); expect(actionControlForKeyboardCode("Digit8")).toBe("dpad-right"); expect(actionLayerForModifiers(true, false)).toBe("secondary"); expect(actionLayerForModifiers(false, true)).toBe("tertiary"); expect(actionLayerForModifiers(true, true)).toBe("tertiary"); expect(actionBindingChordLabel("secondary", "face-top")).toBe("L1 + Triangle"); expect(actionBindingChordLabel("tertiary", "r1", "keyboard")).toBe("Alt + 5"); }); });