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.
129 lines
3.8 KiB
129 lines
3.8 KiB
import { describe, expect, it, vi } from "vitest";
|
|
import { RuntimeEvents } from "@/kernel/RuntimeEvents";
|
|
import { AppRuntime } from "@/kernel/AppRuntime";
|
|
import type { RuntimePlugin } from "@/kernel/RuntimePlugin";
|
|
|
|
vi.mock("@/core/Game", () => {
|
|
class MockGame {
|
|
private static instance: MockGame;
|
|
|
|
static getInstance(): MockGame {
|
|
if (!MockGame.instance) {
|
|
MockGame.instance = new MockGame();
|
|
}
|
|
return MockGame.instance;
|
|
}
|
|
}
|
|
|
|
return { default: MockGame };
|
|
});
|
|
|
|
vi.mock("@/scene/SceneManager", () => {
|
|
class MockSceneManager {
|
|
private static instance: MockSceneManager;
|
|
|
|
static getInstance(): MockSceneManager {
|
|
if (!MockSceneManager.instance) {
|
|
MockSceneManager.instance = new MockSceneManager();
|
|
}
|
|
return MockSceneManager.instance;
|
|
}
|
|
}
|
|
|
|
return { default: MockSceneManager };
|
|
});
|
|
|
|
describe("RuntimeEvents", () => {
|
|
it("supports on/off/emit with variadic args", () => {
|
|
const events = new RuntimeEvents();
|
|
const handler = vi.fn();
|
|
|
|
events.on("runtime:ready", handler);
|
|
events.emit("runtime:ready", { startedAt: 1 }, "extra", 42);
|
|
events.off("runtime:ready", handler);
|
|
events.emit("runtime:ready", { startedAt: 2 });
|
|
|
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
expect(handler).toHaveBeenCalledWith({ startedAt: 1 }, "extra", 42);
|
|
});
|
|
|
|
it("supports once subscriptions", () => {
|
|
const events = new RuntimeEvents();
|
|
const handler = vi.fn();
|
|
|
|
events.once("scene:changed", handler);
|
|
events.emit("scene:changed", { current: "a", previous: undefined });
|
|
events.emit("scene:changed", { current: "b", previous: "a" });
|
|
|
|
expect(handler).toHaveBeenCalledTimes(1);
|
|
expect(handler).toHaveBeenCalledWith({ current: "a", previous: undefined });
|
|
});
|
|
|
|
it("keeps dispatching when one listener throws", () => {
|
|
const events = new RuntimeEvents();
|
|
const bad = vi.fn(() => {
|
|
throw new Error("boom");
|
|
});
|
|
const good = vi.fn();
|
|
|
|
events.on("scene:changed", bad);
|
|
events.on("scene:changed", good);
|
|
events.emit("scene:changed", { current: "x" });
|
|
|
|
expect(bad).toHaveBeenCalledTimes(1);
|
|
expect(good).toHaveBeenCalledTimes(1);
|
|
expect(good).toHaveBeenCalledWith({ current: "x" });
|
|
});
|
|
|
|
it("unsubscribes once listener even when callback throws", () => {
|
|
const events = new RuntimeEvents();
|
|
const throwing = vi.fn(() => {
|
|
throw new Error("once failed");
|
|
});
|
|
const after = vi.fn();
|
|
|
|
events.once("runtime:ready", throwing);
|
|
events.on("runtime:ready", after);
|
|
|
|
events.emit("runtime:ready", { startedAt: 1 });
|
|
events.emit("runtime:ready", { startedAt: 2 });
|
|
|
|
expect(throwing).toHaveBeenCalledTimes(1);
|
|
expect(after).toHaveBeenCalledTimes(2);
|
|
});
|
|
|
|
it("supports onAny tap without affecting event listeners", () => {
|
|
const events = new RuntimeEvents();
|
|
const tap = vi.fn();
|
|
const handler = vi.fn();
|
|
const offTap = events.onAny(tap);
|
|
|
|
events.on("scene:changed", handler);
|
|
events.emit("scene:changed", { current: "a", previous: undefined });
|
|
offTap();
|
|
events.emit("scene:changed", { current: "b", previous: "a" });
|
|
|
|
expect(tap).toHaveBeenCalledTimes(1);
|
|
expect(tap).toHaveBeenCalledWith("scene:changed", { current: "a", previous: undefined });
|
|
expect(handler).toHaveBeenCalledTimes(2);
|
|
});
|
|
});
|
|
|
|
describe("AppRuntime plugin lifecycle", () => {
|
|
it("installs plugin and keeps compatibility exports", () => {
|
|
const runtime = new AppRuntime();
|
|
const setup = vi.fn();
|
|
const plugin: RuntimePlugin = {
|
|
name: "test-plugin",
|
|
setup,
|
|
};
|
|
|
|
runtime.use(plugin);
|
|
runtime.use(plugin);
|
|
|
|
expect(setup).toHaveBeenCalledTimes(1);
|
|
expect(runtime.game).toBeDefined();
|
|
expect(runtime.sceneManager).toBeDefined();
|
|
expect(runtime.events).toBeDefined();
|
|
});
|
|
});
|
|
|