diff options
| author | Ruben Beltran del Rio <jj@r.bdr.sh> | 2026-01-30 11:31:24 +0100 |
|---|---|---|
| committer | Ruben Beltran del Rio <jj@r.bdr.sh> | 2026-01-30 13:05:48 +0100 |
| commit | 0d4b61993cba37c180ac91e40a0fb362711de8de (patch) | |
| tree | f41dd68420b51766c1ca6fc1ee2c20dc5df830d1 /src/components/ModelControls.test.tsx | |
Initial implementation
Diffstat (limited to 'src/components/ModelControls.test.tsx')
| -rw-r--r-- | src/components/ModelControls.test.tsx | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/components/ModelControls.test.tsx b/src/components/ModelControls.test.tsx new file mode 100644 index 0000000..b38d460 --- /dev/null +++ b/src/components/ModelControls.test.tsx @@ -0,0 +1,204 @@ +import { describe, it, beforeEach, afterEach } from "node:test"; +import assert from "node:assert"; +import "../test-setup.ts"; +import { createRoot, type Root } from "react-dom/client"; +import { act } from "@testing-library/react"; +import { ModelControls } from "./ModelControls.tsx"; +import { useStore } from "../store/store.ts"; + +describe("ModelControls", () => { + let container: HTMLDivElement; + let root: Root; + + beforeEach(() => { + container = document.createElement("div"); + document.body.appendChild(container); + root = createRoot(container); + useStore.setState({ + models: [], + selectedModelId: null, + cameraView: "perspective", + backdropUrl: null, + availableModels: [ + { id: "servbot", name: "Servbot", url: "/models/servbot.gltf" }, + ], + }); + }); + + afterEach(() => { + act(() => { + root.unmount(); + }); + container.remove(); + }); + + it("should not render when no model is selected", async () => { + await act(async () => { + root.render(<ModelControls />); + }); + + const controls = container.querySelector(".model-controls"); + assert.ok( + !controls, + "Should not render controls when no model is selected", + ); + }); + + it("should render when a model is selected", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const controls = container.querySelector(".model-controls"); + assert.ok(controls, "Should render controls when model is selected"); + }); + + it("should have position controls", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const positionXInput = container.querySelector('input[name="position-x"]'); + const positionYInput = container.querySelector('input[name="position-y"]'); + const positionZInput = container.querySelector('input[name="position-z"]'); + + assert.ok(positionXInput, "Should have position X input"); + assert.ok(positionYInput, "Should have position Y input"); + assert.ok(positionZInput, "Should have position Z input"); + }); + + it("should have rotation controls", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const rotationXInput = container.querySelector('input[name="rotation-x"]'); + const rotationYInput = container.querySelector('input[name="rotation-y"]'); + const rotationZInput = container.querySelector('input[name="rotation-z"]'); + + assert.ok(rotationXInput, "Should have rotation X input"); + assert.ok(rotationYInput, "Should have rotation Y input"); + assert.ok(rotationZInput, "Should have rotation Z input"); + }); + + it("should update position when input changes", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const positionXInput = container.querySelector( + 'input[name="position-x"]', + ) as HTMLInputElement; + + await act(async () => { + const nativeInputValueSetter = Object.getOwnPropertyDescriptor( + window.HTMLInputElement.prototype, + "value", + )!.set!; + nativeInputValueSetter.call(positionXInput, "5"); + positionXInput.dispatchEvent(new Event("input", { bubbles: true })); + }); + + const model = useStore.getState().models[0]; + assert.strictEqual(model.position.x, 5); + }); + + it("should have hue shift controls", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const hueRedInput = container.querySelector('input[name="hue-red"]'); + const hueGreenInput = container.querySelector('input[name="hue-green"]'); + const hueBlueInput = container.querySelector('input[name="hue-blue"]'); + + assert.ok(hueRedInput, "Should have red hue shift input"); + assert.ok(hueGreenInput, "Should have green hue shift input"); + assert.ok(hueBlueInput, "Should have blue hue shift input"); + }); + + it("should update hue shift when slider changes", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const hueRedInput = container.querySelector( + 'input[name="hue-red"]', + ) as HTMLInputElement; + + await act(async () => { + const nativeInputValueSetter = Object.getOwnPropertyDescriptor( + window.HTMLInputElement.prototype, + "value", + )!.set!; + nativeInputValueSetter.call(hueRedInput, "0.5"); + hueRedInput.dispatchEvent(new Event("input", { bubbles: true })); + }); + + const model = useStore.getState().models[0]; + assert.strictEqual(model.hueShift.red, 0.5); + }); + + it("should have a delete button", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const deleteButton = container.querySelector("button.delete-model"); + assert.ok(deleteButton, "Should have delete button"); + }); + + it("should remove model when delete button is clicked", async () => { + useStore.getState().addModel("servbot", { x: 0, y: 0, z: 0 }); + const modelId = useStore.getState().models[0].id; + useStore.getState().selectModel(modelId); + + await act(async () => { + root.render(<ModelControls />); + }); + + const deleteButton = container.querySelector( + "button.delete-model", + ) as HTMLButtonElement; + + await act(async () => { + deleteButton.click(); + }); + + const models = useStore.getState().models; + assert.strictEqual(models.length, 0, "Model should be removed"); + assert.strictEqual( + useStore.getState().selectedModelId, + null, + "Selection should be cleared", + ); + }); +}); |