@react-chess-tools/react-chess-game
Version:
react-chess-game is a React component bridging chess.js with react-chessboard to offer a full-featured, ready-to-integrate chess board experience.
199 lines (161 loc) • 5.94 kB
text/typescript
import { Chess, Color } from "chess.js";
import {
cloneGame,
getGameInfo,
isLegalMove,
requiresPromotion,
getDestinationSquares,
getCurrentFen,
} from "../chess";
describe("Chess Utilities", () => {
describe("cloneGame", () => {
it("should create a clone with the same state", () => {
const game = new Chess();
game.move("e4");
game.move("e5");
const clone = cloneGame(game);
expect(clone.fen()).toEqual(game.fen());
expect(clone.history()).toEqual(game.history());
expect(clone).not.toBe(game); // Different instances
});
});
describe("getGameInfo", () => {
it("should return correct game info for initial position", () => {
const game = new Chess();
const orientation: Color = "w";
const info = getGameInfo(game, orientation);
expect(info.turn).toBe("w");
expect(info.isPlayerTurn).toBe(true);
expect(info.isOpponentTurn).toBe(false);
expect(info.moveNumber).toBe(0);
expect(info.lastMove).toBeUndefined();
expect(info.isCheck).toBe(false);
expect(info.isCheckmate).toBe(false);
expect(info.isDraw).toBe(false);
expect(info.isGameOver).toBe(false);
});
it("should return correct game info after moves", () => {
const game = new Chess();
game.move("e4");
game.move("e5");
const orientation: Color = "w";
const info = getGameInfo(game, orientation);
expect(info.turn).toBe("w");
expect(info.isPlayerTurn).toBe(true);
expect(info.isOpponentTurn).toBe(false);
expect(info.moveNumber).toBe(2);
expect(info.lastMove).toEqual(
expect.objectContaining({
from: "e7",
to: "e5",
piece: "p",
color: "b",
}),
);
});
it("should return correct game info for checkmate position", () => {
const game = new Chess();
// Scholar's mate
game.move("e4");
game.move("e5");
game.move("Qh5");
game.move("Nc6");
game.move("Bc4");
game.move("Nf6");
game.move("Qxf7");
const whiteInfo = getGameInfo(game, "w");
expect(whiteInfo.isCheckmate).toBe(true);
expect(whiteInfo.isGameOver).toBe(true);
expect(whiteInfo.hasPlayerWon).toBe(true);
expect(whiteInfo.hasPlayerLost).toBe(false);
const blackInfo = getGameInfo(game, "b");
expect(blackInfo.hasPlayerWon).toBe(false);
expect(blackInfo.hasPlayerLost).toBe(true);
});
});
describe("isLegalMove", () => {
it("should return true for legal moves", () => {
const game = new Chess();
expect(isLegalMove(game, "e2e4")).toBe(true);
expect(isLegalMove(game, "g1f3")).toBe(true);
});
it("should return false for illegal moves", () => {
const game = new Chess();
expect(isLegalMove(game, "e2e5")).toBe(false);
expect(isLegalMove(game, "e7e5")).toBe(false); // Black's move, but white to move
});
});
describe("requiresPromotion", () => {
it("should return true for moves requiring promotion", () => {
const game = new Chess("8/P7/7k/8/8/8/8/7K w - - 0 1");
expect(requiresPromotion(game, "a7a8")).toBe(true);
});
it("should return false for moves not requiring promotion", () => {
const game = new Chess();
expect(requiresPromotion(game, "e2e4")).toBe(false);
});
it("should return false for illegal moves", () => {
const game = new Chess();
expect(requiresPromotion(game, "e2e5")).toBe(false);
});
it("throws if game is not passed", () => {
expect(() =>
requiresPromotion(null as unknown as Chess, "e2e4"),
).toThrow();
});
});
describe("getDestinationSquares", () => {
it("should return correct destination squares for a piece", () => {
const game = new Chess();
const e2Destinations = getDestinationSquares(game, "e2");
expect(e2Destinations).toContain("e3");
expect(e2Destinations).toContain("e4");
expect(e2Destinations.length).toBe(2);
const g1Destinations = getDestinationSquares(game, "g1");
expect(g1Destinations).toContain("f3");
expect(g1Destinations).toContain("h3");
expect(g1Destinations.length).toBe(2);
});
it("should return empty array for squares with no legal moves", () => {
const game = new Chess();
expect(getDestinationSquares(game, "e3")).toEqual([]);
});
});
describe("getCurrentFen", () => {
it("should return the initial position when moveIndex is -1", () => {
const game = new Chess();
game.move("e4");
const initialFen =
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
expect(getCurrentFen(initialFen, game, -1)).toBe(initialFen);
});
it("should return the FEN after specific moves", () => {
const game = new Chess();
const initialFen = game.fen();
game.move("e4");
game.move("e5");
game.move("Nf3");
// After 1 move (e4)
const fenAfterOneMove = getCurrentFen(initialFen, game, 0);
expect(fenAfterOneMove).toMatch(
/rnbqkbnr\/pppppppp\/8\/8\/4P3\/8\/PPPP1PPP\/RNBQKBNR b KQkq/,
);
// After 2 moves (e4, e5)
const fenAfterTwoMoves = getCurrentFen(initialFen, game, 1);
expect(fenAfterTwoMoves).toMatch(
/rnbqkbnr\/pppp1ppp\/8\/4p3\/4P3\/8\/PPPP1PPP\/RNBQKBNR w KQkq/,
);
// After 3 moves (e4, e5, Nf3)
const fenAfterThreeMoves = getCurrentFen(initialFen, game, 2);
expect(fenAfterThreeMoves).toMatch(
/rnbqkbnr\/pppp1ppp\/8\/4p3\/4P3\/5N2\/PPPP1PPP\/RNBQKB1R b KQkq/,
);
});
it("should use provided FEN as starting position", () => {
const customFen =
"1r2r1k1/pp3pbp/1qp3p1/2B5/2BP2b1/Q1n2N2/P4PPP/3R1K1R b - - 0 17";
const game = new Chess();
expect(getCurrentFen(customFen, game, -1)).toBe(customFen);
});
});
});