Browse Source

test: enforce scene state machine transitions

Made-with: Cursor
master
npmrun 2 weeks ago
parent
commit
775a0721c0
  1. 21
      src/scene/SceneStateMachine.ts
  2. 28
      tests/kernel/scene-state-machine.test.ts

21
src/scene/SceneStateMachine.ts

@ -1,13 +1,30 @@
export type SceneState = "idle" | "loading";
export const SCENE_STATES = {
IDLE: "idle",
LOADING: "loading",
} as const;
export type SceneState = (typeof SCENE_STATES)[keyof typeof SCENE_STATES];
const SCENE_STATE_TRANSITIONS: Readonly<Record<SceneState, readonly SceneState[]>> = {
[SCENE_STATES.IDLE]: [SCENE_STATES.LOADING],
[SCENE_STATES.LOADING]: [SCENE_STATES.IDLE],
};
export class SceneStateMachine {
private state: SceneState = "idle";
private state: SceneState = SCENE_STATES.IDLE;
getState(): SceneState {
return this.state;
}
transitionTo(nextState: SceneState): void {
const allowedNextStates = SCENE_STATE_TRANSITIONS[this.state];
if (!allowedNextStates.includes(nextState)) {
throw new Error(
`Invalid scene transition: "${this.state}" -> "${nextState}"`
);
}
this.state = nextState;
}
}

28
tests/kernel/scene-state-machine.test.ts

@ -2,12 +2,38 @@ import { describe, expect, it } from "vitest";
import { SceneStateMachine } from "@/scene/SceneStateMachine";
describe("SceneStateMachine", () => {
it("starts in idle state and supports transitioning", () => {
it("starts in idle state for every new instance", () => {
const machine = new SceneStateMachine();
const anotherMachine = new SceneStateMachine();
expect(machine.getState()).toBe("idle");
expect(anotherMachine.getState()).toBe("idle");
});
it("allows legal transitions defined by the state machine", () => {
const machine = new SceneStateMachine();
machine.transitionTo("loading");
expect(machine.getState()).toBe("loading");
machine.transitionTo("idle");
expect(machine.getState()).toBe("idle");
});
it("throws on illegal transitions and keeps current state", () => {
const machine = new SceneStateMachine();
expect(() => machine.transitionTo("idle")).toThrowError(
'Invalid scene transition: "idle" -> "idle"'
);
expect(machine.getState()).toBe("idle");
machine.transitionTo("loading");
expect(machine.getState()).toBe("loading");
expect(() => machine.transitionTo("loading")).toThrowError(
'Invalid scene transition: "loading" -> "loading"'
);
expect(machine.getState()).toBe("loading");
});
});

Loading…
Cancel
Save