diff --git a/tests/unit/first-person-navigation-controller.test.ts b/tests/unit/first-person-navigation-controller.test.ts index 2737111a..4e1f3b75 100644 --- a/tests/unit/first-person-navigation-controller.test.ts +++ b/tests/unit/first-person-navigation-controller.test.ts @@ -162,6 +162,39 @@ describe("FirstPersonNavigationController", () => { expect(exitPointerLockSpy).toHaveBeenCalledTimes(1); }); + it("clears held movement keys when pointer lock is released", () => { + const { context, domElement } = createRuntimeControllerContext(); + const controller = new FirstPersonNavigationController(); + let pointerLockElement: Element | null = domElement; + + Object.defineProperty(document, "pointerLockElement", { + configurable: true, + get: () => pointerLockElement + }); + + controller.activate(context); + + const controllerInternals = controller as unknown as { + pressedKeys: Set; + handleKeyDown(event: KeyboardEvent): void; + handlePointerLockChange(): void; + }; + controllerInternals.handleKeyDown( + new KeyboardEvent("keydown", { code: "KeyW" }) + ); + + expect(controllerInternals.pressedKeys.has("KeyW")).toBe(true); + + pointerLockElement = null; + controllerInternals.handlePointerLockChange(); + + expect(controllerInternals.pressedKeys.size).toBe(0); + + controller.deactivate(context, { + releasePointerLock: false + }); + }); + it("uses authored gamepad bindings instead of the hardcoded stick mapping", () => { const playerStart = createPlayerStartEntity({ id: "entity-player-start-custom-gamepad", diff --git a/tests/unit/third-person-navigation-controller.test.ts b/tests/unit/third-person-navigation-controller.test.ts index 31a5733b..4e4f1f47 100644 --- a/tests/unit/third-person-navigation-controller.test.ts +++ b/tests/unit/third-person-navigation-controller.test.ts @@ -142,6 +142,39 @@ describe("ThirdPersonNavigationController", () => { controller.deactivate(context); }); + it("clears held movement keys when pointer lock is released", () => { + const { context } = createRuntimeControllerContext(); + const controller = new ThirdPersonNavigationController(); + let pointerLockElement: Element | null = context.domElement; + + Object.defineProperty(document, "pointerLockElement", { + configurable: true, + get: () => pointerLockElement + }); + + controller.activate(context); + + const controllerInternals = controller as unknown as { + pressedKeys: Set; + handleKeyDown(event: KeyboardEvent): void; + handlePointerLockChange(): void; + }; + controllerInternals.handleKeyDown( + new KeyboardEvent("keydown", { code: "ArrowUp" }) + ); + + expect(controllerInternals.pressedKeys.has("ArrowUp")).toBe(true); + + pointerLockElement = null; + controllerInternals.handlePointerLockChange(); + + expect(controllerInternals.pressedKeys.size).toBe(0); + + controller.deactivate(context, { + releasePointerLock: false + }); + }); + it("uses the gamepad right stick for third-person camera orbit", () => { const { context } = createRuntimeControllerContext(); const controller = new ThirdPersonNavigationController();