Spaces:
Running
Running
| import { describe, it, expect } from "vitest"; | |
| import { gameReducer, createInitialState } from "./engine"; | |
| import type { ShuffledQuestion } from "./types"; | |
| const mockQuestion = (id: string, difficulty: "easy" | "medium" | "hard" = "medium"): ShuffledQuestion => ({ | |
| id, category: "General", difficulty, questionText: `Question ${id}?`, | |
| correctAnswer: "Correct", incorrectAnswers: ["Wrong1", "Wrong2", "Wrong3"], | |
| allAnswers: ["Correct", "Wrong1", "Wrong2", "Wrong3"], | |
| }); | |
| describe("createInitialState", () => { | |
| it("creates idle state for quick-fire", () => { | |
| const state = createInitialState("quick-fire", [mockQuestion("1")]); | |
| expect(state.phase).toBe("idle"); | |
| expect(state.mode).toBe("quick-fire"); | |
| expect(state.score).toBe(0); | |
| expect(state.currentQuestionIndex).toBe(0); | |
| }); | |
| }); | |
| describe("gameReducer", () => { | |
| it("START transitions from idle to playing", () => { | |
| const state = createInitialState("quick-fire", [mockQuestion("1")]); | |
| const next = gameReducer(state, { type: "START" }); | |
| expect(next.phase).toBe("playing"); | |
| expect(next.startedAt).not.toBeNull(); | |
| }); | |
| it("ANSWER_CORRECT increments score and streak", () => { | |
| let state = createInitialState("quick-fire", [mockQuestion("1"), mockQuestion("2")]); | |
| state = gameReducer(state, { type: "START" }); | |
| state = gameReducer(state, { type: "ANSWER_CORRECT", points: 200 }); | |
| expect(state.score).toBe(200); | |
| expect(state.streak).toBe(1); | |
| expect(state.questionsCorrect).toBe(1); | |
| expect(state.currentQuestionIndex).toBe(1); | |
| }); | |
| it("ANSWER_WRONG resets streak to 0", () => { | |
| let state = createInitialState("quick-fire", [mockQuestion("1"), mockQuestion("2")]); | |
| state = gameReducer(state, { type: "START" }); | |
| state = gameReducer(state, { type: "ANSWER_CORRECT", points: 100 }); | |
| state = gameReducer(state, { type: "ANSWER_WRONG" }); | |
| expect(state.streak).toBe(0); | |
| expect(state.questionsCorrect).toBe(1); | |
| expect(state.currentQuestionIndex).toBe(2); | |
| }); | |
| it("ANSWER_WRONG in streak mode ends the game", () => { | |
| let state = createInitialState("streak", [mockQuestion("1"), mockQuestion("2")]); | |
| state = gameReducer(state, { type: "START" }); | |
| state = gameReducer(state, { type: "ANSWER_WRONG" }); | |
| expect(state.phase).toBe("finished"); | |
| }); | |
| it("answering last question finishes the game", () => { | |
| let state = createInitialState("quick-fire", [mockQuestion("1")]); | |
| state = gameReducer(state, { type: "START" }); | |
| state = gameReducer(state, { type: "ANSWER_CORRECT", points: 100 }); | |
| expect(state.phase).toBe("finished"); | |
| }); | |
| it("TIME_UP finishes the game", () => { | |
| let state = createInitialState("quick-fire", [mockQuestion("1")]); | |
| state = gameReducer(state, { type: "START" }); | |
| state = gameReducer(state, { type: "TIME_UP" }); | |
| expect(state.phase).toBe("finished"); | |
| }); | |
| it("tracks streakMax across the game", () => { | |
| let state = createInitialState("quick-fire", [ | |
| mockQuestion("1"), mockQuestion("2"), mockQuestion("3"), mockQuestion("4"), | |
| ]); | |
| state = gameReducer(state, { type: "START" }); | |
| state = gameReducer(state, { type: "ANSWER_CORRECT", points: 100 }); | |
| state = gameReducer(state, { type: "ANSWER_CORRECT", points: 100 }); | |
| state = gameReducer(state, { type: "ANSWER_WRONG" }); | |
| state = gameReducer(state, { type: "ANSWER_CORRECT", points: 100 }); | |
| expect(state.streakMax).toBe(2); | |
| expect(state.streak).toBe(1); | |
| }); | |
| it("NEXT_PHASE transitions challenge-me phases", () => { | |
| let state = createInitialState("challenge-me", [mockQuestion("1")]); | |
| state = gameReducer(state, { type: "START" }); | |
| expect(state.challengePhase).toBe("easy"); | |
| state = gameReducer(state, { type: "NEXT_PHASE" }); | |
| expect(state.challengePhase).toBe("medium"); | |
| state = gameReducer(state, { type: "NEXT_PHASE" }); | |
| expect(state.challengePhase).toBe("hard"); | |
| state = gameReducer(state, { type: "NEXT_PHASE" }); | |
| expect(state.phase).toBe("finished"); | |
| }); | |
| }); | |