diff --git a/src/engine/integration.test.ts b/src/engine/integration.test.ts new file mode 100644 index 0000000..20a6174 --- /dev/null +++ b/src/engine/integration.test.ts @@ -0,0 +1,47 @@ +import { describe, it, expect } from 'vitest'; +import { DuplicateGame } from './game'; +import { playSymmetric } from './test-helpers'; +import { legalSyncedMoves } from './legality'; +import { ghosts } from './ghosts'; +import { evaluateStatus } from './endgame'; +import { serialize, deserialize } from './notation'; + +describe('integration: a scripted game played to checkmate', () => { + it('plays Fool\'s mate, stays consistent throughout, and ends correctly', () => { + const g = new DuplicateGame(); + + // The game is live and ongoing until the mate. + expect(evaluateStatus(g).state).toBe('playing'); + expect(legalSyncedMoves(g).length).toBeGreaterThan(0); + + playSymmetric(g, [ + [{ from: 'f2', to: 'f3' }, { from: 'e7', to: 'e5' }], + [{ from: 'g2', to: 'g4' }, { from: 'd8', to: 'h4' }], + ]); + + // No captures occurred, so there are no ghosts. + expect(ghosts(g)).toEqual([]); + + // North is checkmated. + const status = evaluateStatus(g); + expect(status.state).toBe('checkmate'); + expect(status.result?.N).toBe('loss'); + expect(legalSyncedMoves(g)).toEqual([]); + + // The game round-trips through save/load and reproduces the same outcome. + const restored = new DuplicateGame(deserialize(serialize(g.history))); + expect(evaluateStatus(restored).state).toBe('checkmate'); + expect(restored.history).toEqual(g.history); + }); + + it('undo from the mated position restores a playable game', () => { + const g = new DuplicateGame(); + playSymmetric(g, [ + [{ from: 'f2', to: 'f3' }, { from: 'e7', to: 'e5' }], + [{ from: 'g2', to: 'g4' }, { from: 'd8', to: 'h4' }], + ]); + g.undo(); // take back W's d8h4 + expect(evaluateStatus(g).state).toBe('playing'); + expect(g.currentPlayer).toBe('W'); + }); +});