You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
2.7 KiB
109 lines
2.7 KiB
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
|
|
);
|
|
});
|
|
});
|
|
|