UNPKG

@react-chess-tools/react-chess-puzzle

Version:

A lightweight, customizable React component library for rendering and interacting with chess puzzles.

275 lines (221 loc) 6.98 kB
import { Chess, Move } from "chess.js"; import { reducer, initializePuzzle, State, Action } from "../reducer"; import { Puzzle } from "../../utils"; import { ChessPuzzleContextType } from "../useChessPuzzle"; describe("reducer", () => { // Mock puzzle data const mockPuzzle: Puzzle = { fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", moves: ["e4", "e5", "Nf3", "Nc6", "Bb5"], makeFirstMove: false, }; const mockPuzzleWithFirstMove: Puzzle = { fen: "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", moves: ["e4", "e5", "Nf3", "Nc6", "Bb5"], makeFirstMove: true, }; // Initial state const initialState: State = { puzzle: mockPuzzle, currentMoveIndex: 0, status: "not-started", nextMove: "e4", hint: "none", cpuMove: null, needCpuMove: false, isPlayerTurn: true, onSolveInvoked: false, onFailInvoked: false, }; describe("initializePuzzle", () => { it("should initialize a puzzle correctly", () => { const state = initializePuzzle({ puzzle: mockPuzzle }); expect(state).toEqual({ puzzle: mockPuzzle, currentMoveIndex: 0, status: "not-started", nextMove: "e4", hint: "none", cpuMove: null, needCpuMove: false, isPlayerTurn: true, onSolveInvoked: false, onFailInvoked: false, }); }); it("should set needCpuMove to true if makeFirstMove is true", () => { const state = initializePuzzle({ puzzle: mockPuzzleWithFirstMove }); expect(state.needCpuMove).toBe(true); expect(state.isPlayerTurn).toBe(false); }); }); describe("INITIALIZE action", () => { it("should initialize with a new puzzle", () => { const action: Action = { type: "INITIALIZE", payload: { puzzle: mockPuzzle, }, }; const newState = reducer(initialState, action); expect(newState).toEqual(initialState); }); }); describe("RESET action", () => { it("should reset the puzzle to initial state", () => { const modifiedState: State = { ...initialState, currentMoveIndex: 2, status: "in-progress", hint: "piece", }; const action: Action = { type: "RESET", }; const newState = reducer(modifiedState, action); expect(newState).toEqual(initialState); }); }); describe("TOGGLE_HINT action", () => { it("should change hint from none to piece", () => { const action: Action = { type: "TOGGLE_HINT", }; const newState = reducer(initialState, action); expect(newState.hint).toBe("piece"); }); it("should change hint from piece to move", () => { const stateWithPieceHint: State = { ...initialState, hint: "piece", }; const action: Action = { type: "TOGGLE_HINT", }; const newState = reducer(stateWithPieceHint, action); expect(newState.hint).toBe("move"); }); }); describe("CPU_MOVE action", () => { it("should process CPU move and update state", () => { const state: State = { ...initialState, isPlayerTurn: false, needCpuMove: true, }; const action: Action = { type: "CPU_MOVE", }; const newState = reducer(state, action); expect(newState.currentMoveIndex).toBe(1); expect(newState.cpuMove).toBe("e4"); expect(newState.nextMove).toBe("e5"); expect(newState.needCpuMove).toBe(false); expect(newState.isPlayerTurn).toBe(true); expect(newState.status).toBe("in-progress"); }); it("should not change state if it's player's turn", () => { const action: Action = { type: "CPU_MOVE", }; const newState = reducer(initialState, action); expect(newState).toBe(initialState); }); it("should not change state if puzzle is solved or failed", () => { const solvedState: State = { ...initialState, isPlayerTurn: false, status: "solved", }; const action: Action = { type: "CPU_MOVE", }; const newState = reducer(solvedState, action); expect(newState).toBe(solvedState); }); it("should set nextMove to null when reaching last move", () => { const state: State = { ...initialState, isPlayerTurn: false, needCpuMove: true, currentMoveIndex: 4, // Last move index }; const action: Action = { type: "CPU_MOVE", }; const newState = reducer(state, action); expect(newState.nextMove).toBe(null); }); }); describe("PLAYER_MOVE action", () => { const game = new Chess(mockPuzzle.fen); const mockContext = {} as ChessPuzzleContextType; // Mock puzzle context it("should handle correct player move", () => { const move = { san: "e4", lan: "e2e4" } as Move; const action: Action = { type: "PLAYER_MOVE", payload: { move, puzzleContext: mockContext, game, }, }; const newState = reducer(initialState, action); expect(newState.currentMoveIndex).toBe(1); expect(newState.nextMove).toBe("e5"); expect(newState.hint).toBe("none"); expect(newState.needCpuMove).toBe(true); expect(newState.isPlayerTurn).toBe(false); expect(newState.status).toBe("in-progress"); }); it("should handle incorrect player move", () => { const move = { san: "d4", lan: "d2d4" } as Move; const action: Action = { type: "PLAYER_MOVE", payload: { move, puzzleContext: mockContext, game, }, }; const newState = reducer(initialState, action); expect(newState.status).toBe("failed"); expect(newState.nextMove).toBe(null); expect(newState.hint).toBe("none"); expect(newState.isPlayerTurn).toBe(false); }); it("should handle solving the puzzle", () => { const move = { san: "Bb5", lan: "f1b5" } as Move; const lastMoveState: State = { ...initialState, currentMoveIndex: 4, nextMove: "Bb5", }; const action: Action = { type: "PLAYER_MOVE", payload: { move, puzzleContext: mockContext, game, }, }; const newState = reducer(lastMoveState, action); expect(newState.status).toBe("solved"); expect(newState.nextMove).toBe(null); expect(newState.hint).toBe("none"); expect(newState.isPlayerTurn).toBe(false); }); it("should handle null move", () => { const action: Action = { type: "PLAYER_MOVE", payload: { move: null, puzzleContext: mockContext, game, }, }; const newState = reducer(initialState, action); expect(newState.status).toBe("failed"); }); }); });