import { beforeEach, describe, expect, it, vi } from "vitest"; import { SceneType } from "@/enums/SceneType"; import type { IBaseScene } from "@/scene/types"; class MockContainer { visible = true; label = ""; _isHolderLast?: boolean; children: MockContainer[] = []; destroyed = false; addChild(child: MockContainer): MockContainer { this.children.push(child); return child; } removeChild(child: MockContainer): MockContainer { this.children = this.children.filter((item) => item !== child); return child; } destroy(): void { this.destroyed = true; } } vi.mock("pixi.js", () => ({ Container: MockContainer, })); vi.mock("@/core/Game", () => { class MockGame { private static instance: MockGame; readonly stage = new MockContainer(); static getInstance(): MockGame { if (!MockGame.instance) { MockGame.instance = new MockGame(); } return MockGame.instance; } } return { default: MockGame, }; }); function createScene( name: string, type: SceneType = SceneType.Normal, onLoad?: () => Promise | void ): IBaseScene { const stage = new MockContainer(); stage.label = name; return { name, type, stage: stage as never, _assetsLoaded: true, _layoutDone: true, changeScene: () => {}, onLoad, onUnLoad: async () => {}, loadBundle: async () => {}, unLoadBundle: async () => {}, layout: async () => {}, }; } describe("SceneManager rollback consistency", () => { beforeEach(async () => { vi.resetModules(); const module = await import("@/scene/SceneManager"); (module.default as unknown as { instance?: unknown }).instance = undefined; }); it("restores previous scene visibility and mount when transition fails", async () => { const module = await import("@/scene/SceneManager"); const SceneManager = module.default; const manager = SceneManager.getInstance(); const previous = createScene("previous"); const target = createScene("target", SceneType.Normal, async () => { throw new Error("target onLoad failed"); }); manager.registerScene(previous); manager.registerScene(target); await manager.initScene("previous"); expect(previous.stage.visible).toBe(true); expect(manager.currentScene).toBe(previous); await expect( manager.changeScene("target", { isHolderLast: true }) ).rejects.toThrowError("target onLoad failed"); expect(manager.currentScene).toBe(previous); expect(previous.stage.visible).toBe(true); expect(manager["game"].stage.children.includes(previous.stage as never)).toBe( true ); expect(manager["game"].stage.children.includes(target.stage as never)).toBe( false ); }); });