import { describe, expect, it, vi } from "vitest"; import { BoxGeometry, Group, Mesh, MeshStandardMaterial, Skeleton, SkinnedMesh, Texture, } from "three"; import { disposeObject3DResources } from "./threeResourceDisposal"; describe("Three.js resource disposal", () => { it("disposes shared resources and skeletons exactly once", () => { const root = new Group(); const geometry = new BoxGeometry(); const texture = new Texture(); const material = new MeshStandardMaterial({ map: texture }); const skeleton = new Skeleton(); root.add(new Mesh(geometry, material)); const skinned = new SkinnedMesh(geometry, material); skinned.bind(skeleton); root.add(skinned); const geometryDispose = vi.spyOn(geometry, "dispose"); const materialDispose = vi.spyOn(material, "dispose"); const textureDispose = vi.spyOn(texture, "dispose"); const skeletonDispose = vi.spyOn(skeleton, "dispose"); expect(disposeObject3DResources(root)).toEqual({ geometries: 1, materials: 1, textures: 1, skeletons: 1, }); expect(geometryDispose).toHaveBeenCalledOnce(); expect(materialDispose).toHaveBeenCalledOnce(); expect(textureDispose).toHaveBeenCalledOnce(); expect(skeletonDispose).toHaveBeenCalledOnce(); }); it("can release cloned collision geometry without touching shared materials", () => { const geometry = new BoxGeometry(); const material = new MeshStandardMaterial(); const root = new Mesh(geometry, material); const geometryDispose = vi.spyOn(geometry, "dispose"); const materialDispose = vi.spyOn(material, "dispose"); expect(disposeObject3DResources(root, { materials: false, textures: false, skeletons: false, })).toEqual({ geometries: 1, materials: 0, textures: 0, skeletons: 0 }); expect(geometryDispose).toHaveBeenCalledOnce(); expect(materialDispose).not.toHaveBeenCalled(); }); });