diff --git a/src/__tests__/useUnicornScene.test.ts b/src/__tests__/useUnicornScene.test.ts index 4a4137b..e2e3e5b 100644 --- a/src/__tests__/useUnicornScene.test.ts +++ b/src/__tests__/useUnicornScene.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; import { renderHook, act } from "@testing-library/react"; +import { StrictMode } from "react"; import { useUnicornScene } from "../shared/hooks"; import type { UnicornStudioScene } from "../shared/types"; import { MockResizeObserver } from "./setup"; @@ -85,6 +86,20 @@ describe("useUnicornScene", () => { expect(result.current.error).toBeNull(); }); + it("initializes once in Strict Mode", async () => { + const scene = createMockScene(); + addSceneMock.mockResolvedValue(scene); + + renderHook(() => useUnicornScene(defaultProps(elementRef)), { + wrapper: StrictMode, + }); + + await act(async () => {}); + + expect(addSceneMock).toHaveBeenCalledTimes(1); + expect(scene.destroy).not.toHaveBeenCalled(); + }); + it("does not initialize when isScriptLoaded is false", async () => { const { result } = renderHook(() => useUnicornScene({ ...defaultProps(elementRef), isScriptLoaded: false }), @@ -487,6 +502,8 @@ describe("useUnicornScene", () => { }, }); + await act(async () => {}); + // Props change while addScene() is still in flight, so the scene config was // already built with the previous values. rerender({ diff --git a/src/shared/hooks.ts b/src/shared/hooks.ts index ae2e702..6e2f037 100644 --- a/src/shared/hooks.ts +++ b/src/shared/hooks.ts @@ -409,6 +409,10 @@ export function useUnicornScene({ async function initializeScene() { if (!elementRef.current || !isScriptLoaded || validationError) return; + // Let Strict Mode clean up its discarded effect before starting the SDK. + await Promise.resolve(); + if (ignore) return; + // Prevent multiple concurrent initializations if (isInitializingRef.current) return;