From e2bb0e5f1451b512fe8d3c08ae24e662c5012905 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Mon, 27 Apr 2026 00:15:36 +0200 Subject: [PATCH] feat(test): Add unit tests for model instance rendering --- tests/unit/model-instance-rendering.test.ts | 79 +++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/unit/model-instance-rendering.test.ts diff --git a/tests/unit/model-instance-rendering.test.ts b/tests/unit/model-instance-rendering.test.ts new file mode 100644 index 00000000..6a7212d8 --- /dev/null +++ b/tests/unit/model-instance-rendering.test.ts @@ -0,0 +1,79 @@ +import { BoxGeometry, Mesh, MeshBasicMaterial } from "three"; +import { describe, expect, it } from "vitest"; + +import { + createModelInstanceRenderGroup, + disposeModelInstance, + syncModelInstanceSelectionShell +} from "../../src/assets/model-instance-rendering"; +import { createModelInstance } from "../../src/assets/model-instances"; +import type { ModelAssetRecord } from "../../src/assets/project-assets"; + +const modelAsset: ModelAssetRecord = { + id: "asset-model", + kind: "model", + sourceName: "Model.glb", + mimeType: "model/gltf-binary", + storageKey: "project-asset:asset-model", + byteLength: 1024, + metadata: { + kind: "model", + format: "glb", + sceneName: null, + nodeCount: 1, + meshCount: 1, + materialNames: [], + textureNames: [], + animationNames: [], + boundingBox: { + min: { x: -1, y: 0, z: -0.5 }, + max: { x: 1, y: 2, z: 0.5 }, + size: { x: 2, y: 2, z: 1 } + }, + warnings: [] + } +}; + +function getSelectionShells(group: ReturnType) { + return group.children.filter( + (child): child is Mesh => + child instanceof Mesh && + child.userData.modelInstanceSelectionShell === true + ); +} + +describe("model instance rendering", () => { + it("toggles one selection shell without replacing unrelated children", () => { + const modelInstance = createModelInstance({ + id: "model-instance", + assetId: modelAsset.id + }); + const renderGroup = createModelInstanceRenderGroup( + modelInstance, + modelAsset, + undefined, + false + ); + const debugMesh = new Mesh( + new BoxGeometry(0.25, 0.25, 0.25), + new MeshBasicMaterial() + ); + debugMesh.userData.nonPickable = true; + renderGroup.add(debugMesh); + + expect(getSelectionShells(renderGroup)).toHaveLength(0); + + syncModelInstanceSelectionShell(renderGroup, modelAsset, true); + syncModelInstanceSelectionShell(renderGroup, modelAsset, true); + + expect(getSelectionShells(renderGroup)).toHaveLength(1); + expect(renderGroup.children).toContain(debugMesh); + + syncModelInstanceSelectionShell(renderGroup, modelAsset, false); + + expect(getSelectionShells(renderGroup)).toHaveLength(0); + expect(renderGroup.children).toContain(debugMesh); + + disposeModelInstance(renderGroup); + }); +});