4 changed files with 162 additions and 1 deletions
@ -0,0 +1,109 @@ |
|||
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> | 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 |
|||
); |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue