Restructured project from nested workspace pattern to flat single-repo layout. This eliminates redundant nesting and consolidates all project files under version control. ## Migration Summary **Before:** ``` alex/ (workspace, not versioned) ├── chess-game/ (git repo) │ ├── js/, css/, tests/ │ └── index.html └── docs/ (planning, not versioned) ``` **After:** ``` alex/ (git repo, everything versioned) ├── js/, css/, tests/ ├── index.html ├── docs/ (project documentation) ├── planning/ (historical planning docs) ├── .gitea/ (CI/CD) └── CLAUDE.md (configuration) ``` ## Changes Made ### Structure Consolidation - Moved all chess-game/ contents to root level - Removed redundant chess-game/ subdirectory - Flattened directory structure (eliminated one nesting level) ### Documentation Organization - Moved chess-game/docs/ → docs/ (project documentation) - Moved alex/docs/ → planning/ (historical planning documents) - Added CLAUDE.md (workspace configuration) - Added IMPLEMENTATION_PROMPT.md (original project prompt) ### Version Control Improvements - All project files now under version control - Planning documents preserved in planning/ folder - Merged .gitignore files (workspace + project) - Added .claude/ agent configurations ### File Updates - Updated .gitignore to include both workspace and project excludes - Moved README.md to root level - All import paths remain functional (relative paths unchanged) ## Benefits ✅ **Simpler Structure** - One level of nesting removed ✅ **Complete Versioning** - All documentation now in git ✅ **Standard Layout** - Matches open-source project conventions ✅ **Easier Navigation** - Direct access to all project files ✅ **CI/CD Compatible** - All workflows still functional ## Technical Validation - ✅ Node.js environment verified - ✅ Dependencies installed successfully - ✅ Dev server starts and responds - ✅ All core files present and accessible - ✅ Git repository functional ## Files Preserved **Implementation Files:** - js/ (3,517 lines of code) - css/ (4 stylesheets) - tests/ (87 test cases) - index.html - package.json **CI/CD Pipeline:** - .gitea/workflows/ci.yml - .gitea/workflows/release.yml **Documentation:** - docs/ (12+ documentation files) - planning/ (historical planning materials) - README.md **Configuration:** - jest.config.js, babel.config.cjs, playwright.config.js - .gitignore (merged) - CLAUDE.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
484 lines
12 KiB
Markdown
484 lines
12 KiB
Markdown
# Test Scenarios (JSON Format)
|
|
|
|
This directory contains structured test scenarios in JSON format for automated testing of specific chess game behaviors.
|
|
|
|
## Scenario Format
|
|
|
|
```json
|
|
{
|
|
"id": "unique-scenario-id",
|
|
"name": "Scenario Name",
|
|
"description": "Detailed description",
|
|
"category": "category-name",
|
|
"priority": "high|medium|low",
|
|
"setup": {
|
|
"fen": "FEN string",
|
|
"description": "Setup description"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "action-type",
|
|
"params": {},
|
|
"expected": {}
|
|
}
|
|
],
|
|
"assertions": [
|
|
{
|
|
"type": "assertion-type",
|
|
"expected": "expected-value"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Available Scenarios
|
|
|
|
### Basic Movement Scenarios
|
|
|
|
#### Pawn Movement
|
|
**File**: `pawn-movement.json`
|
|
```json
|
|
{
|
|
"id": "pawn-001",
|
|
"name": "Pawn Initial Two-Square Move",
|
|
"description": "Verify pawn can move two squares from starting position",
|
|
"category": "piece-movement",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
|
"description": "Initial board position"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "selectPiece",
|
|
"params": { "square": "e2" },
|
|
"expected": { "validMoves": ["e3", "e4"] }
|
|
},
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "e2", "to": "e4" },
|
|
"expected": { "success": true }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "e4", "expected": "white-pawn" },
|
|
{ "type": "pieceAt", "square": "e2", "expected": null },
|
|
{ "type": "turn", "expected": "black" }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### Knight Jump
|
|
**File**: `knight-jump.json`
|
|
```json
|
|
{
|
|
"id": "knight-001",
|
|
"name": "Knight Jumps Over Pieces",
|
|
"description": "Verify knight can jump over blocking pieces",
|
|
"category": "piece-movement",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
|
"description": "Initial position with pawns blocking"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "b1", "to": "c3" },
|
|
"expected": { "success": true }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "c3", "expected": "white-knight" },
|
|
{ "type": "pieceAt", "square": "b1", "expected": null }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Special Moves Scenarios
|
|
|
|
#### En Passant
|
|
**File**: `en-passant.json`
|
|
```json
|
|
{
|
|
"id": "special-001",
|
|
"name": "En Passant Capture",
|
|
"description": "Verify en passant capture works correctly",
|
|
"category": "special-moves",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/ppp1pppp/8/3pP3/8/8/PPPP1PPP/RNBQKBNR w KQkq d6 0 2",
|
|
"description": "White pawn on e5, black just moved d7-d5"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "e5", "to": "d6" },
|
|
"expected": { "success": true, "captureType": "en-passant" }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "d6", "expected": "white-pawn" },
|
|
{ "type": "pieceAt", "square": "d5", "expected": null },
|
|
{ "type": "pieceAt", "square": "e5", "expected": null },
|
|
{ "type": "capturedPieces", "color": "black", "expected": ["pawn"] }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### Castling Kingside
|
|
**File**: `castling-kingside.json`
|
|
```json
|
|
{
|
|
"id": "castling-001",
|
|
"name": "Kingside Castling",
|
|
"description": "Verify kingside castling moves both king and rook",
|
|
"category": "special-moves",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQK2R w KQkq - 0 1",
|
|
"description": "Cleared path for kingside castling"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "e1", "to": "g1" },
|
|
"expected": { "success": true, "moveType": "castling" }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "g1", "expected": "white-king" },
|
|
{ "type": "pieceAt", "square": "f1", "expected": "white-rook" },
|
|
{ "type": "pieceAt", "square": "e1", "expected": null },
|
|
{ "type": "pieceAt", "square": "h1", "expected": null },
|
|
{ "type": "castlingRights", "white": { "kingside": false, "queenside": true } }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### Pawn Promotion
|
|
**File**: `pawn-promotion.json`
|
|
```json
|
|
{
|
|
"id": "promotion-001",
|
|
"name": "Pawn Promotion to Queen",
|
|
"description": "Verify pawn promotes to queen on 8th rank",
|
|
"category": "special-moves",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "4k3/P7/8/8/8/8/8/4K3 w - - 0 1",
|
|
"description": "White pawn on a7 ready to promote"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "a7", "to": "a8", "promotion": "queen" },
|
|
"expected": { "success": true, "moveType": "promotion" }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "a8", "expected": "white-queen" },
|
|
{ "type": "pieceAt", "square": "a7", "expected": null }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Game State Scenarios
|
|
|
|
#### Check Detection
|
|
**File**: `check-detection.json`
|
|
```json
|
|
{
|
|
"id": "gamestate-001",
|
|
"name": "Check Detection",
|
|
"description": "Verify check is detected and displayed",
|
|
"category": "game-state",
|
|
"priority": "critical",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2",
|
|
"description": "Standard position"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "f1", "to": "c4" },
|
|
"expected": { "success": true }
|
|
},
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "d8", "to": "h4" },
|
|
"expected": { "success": true, "check": true }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "inCheck", "color": "white", "expected": true },
|
|
{ "type": "checkIndicator", "visible": true },
|
|
{ "type": "validMoves", "mustEscapeCheck": true }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### Checkmate
|
|
**File**: `checkmate-fools-mate.json`
|
|
```json
|
|
{
|
|
"id": "checkmate-001",
|
|
"name": "Fool's Mate Checkmate",
|
|
"description": "Verify checkmate detection in Fool's Mate",
|
|
"category": "game-state",
|
|
"priority": "critical",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
|
"description": "Initial position"
|
|
},
|
|
"steps": [
|
|
{ "action": "movePiece", "params": { "from": "f2", "to": "f3" } },
|
|
{ "action": "movePiece", "params": { "from": "e7", "to": "e5" } },
|
|
{ "action": "movePiece", "params": { "from": "g2", "to": "g4" } },
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "d8", "to": "h4" },
|
|
"expected": { "success": true, "checkmate": true }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "gameOver", "expected": true },
|
|
{ "type": "result", "expected": "black-wins" },
|
|
{ "type": "reason", "expected": "checkmate" },
|
|
{ "type": "inCheckmate", "color": "white", "expected": true }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### Stalemate
|
|
**File**: `stalemate.json`
|
|
```json
|
|
{
|
|
"id": "gamestate-003",
|
|
"name": "Stalemate Detection",
|
|
"description": "Verify stalemate results in draw",
|
|
"category": "game-state",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "k7/8/1Q6/8/8/8/8/7K b - - 0 1",
|
|
"description": "Black king with no legal moves, not in check"
|
|
},
|
|
"steps": [],
|
|
"assertions": [
|
|
{ "type": "gameOver", "expected": true },
|
|
{ "type": "result", "expected": "draw" },
|
|
{ "type": "reason", "expected": "stalemate" },
|
|
{ "type": "legalMoves", "color": "black", "expected": [] }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### UI Interaction Scenarios
|
|
|
|
#### Drag and Drop
|
|
**File**: `drag-drop-move.json`
|
|
```json
|
|
{
|
|
"id": "ui-001",
|
|
"name": "Drag and Drop Valid Move",
|
|
"description": "Verify drag-drop interaction for valid move",
|
|
"category": "ui-interaction",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
|
"description": "Initial position"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "dragStart",
|
|
"params": { "square": "e2" },
|
|
"expected": { "dragActive": true, "pieceSelected": true }
|
|
},
|
|
{
|
|
"action": "dragOver",
|
|
"params": { "square": "e4" },
|
|
"expected": { "validMoveHighlight": true }
|
|
},
|
|
{
|
|
"action": "drop",
|
|
"params": { "square": "e4" },
|
|
"expected": { "success": true, "pieceAt": "e4" }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "e4", "expected": "white-pawn" },
|
|
{ "type": "dragActive", "expected": false }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### Click to Move
|
|
**File**: `click-to-move.json`
|
|
```json
|
|
{
|
|
"id": "ui-002",
|
|
"name": "Click-Select-Click-Move",
|
|
"description": "Verify click-based move selection",
|
|
"category": "ui-interaction",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
|
"description": "Initial position"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "click",
|
|
"params": { "square": "e2" },
|
|
"expected": { "pieceSelected": true, "validMovesHighlighted": ["e3", "e4"] }
|
|
},
|
|
{
|
|
"action": "click",
|
|
"params": { "square": "e4" },
|
|
"expected": { "success": true }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "e4", "expected": "white-pawn" },
|
|
{ "type": "selectedSquare", "expected": null }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Error Handling Scenarios
|
|
|
|
#### Invalid Move
|
|
**File**: `invalid-move.json`
|
|
```json
|
|
{
|
|
"id": "error-001",
|
|
"name": "Invalid Move Rejection",
|
|
"description": "Verify invalid moves are rejected with feedback",
|
|
"category": "error-handling",
|
|
"priority": "high",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
|
"description": "Initial position"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "e2", "to": "e5" },
|
|
"expected": { "success": false, "error": "Invalid move" }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "e2", "expected": "white-pawn" },
|
|
{ "type": "pieceAt", "square": "e5", "expected": null },
|
|
{ "type": "errorMessage", "visible": true }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### Move Opponent's Piece
|
|
**File**: `wrong-color-move.json`
|
|
```json
|
|
{
|
|
"id": "error-002",
|
|
"name": "Cannot Move Opponent's Piece",
|
|
"description": "Verify player cannot move opponent's pieces",
|
|
"category": "error-handling",
|
|
"priority": "critical",
|
|
"setup": {
|
|
"fen": "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",
|
|
"description": "White to move"
|
|
},
|
|
"steps": [
|
|
{
|
|
"action": "movePiece",
|
|
"params": { "from": "e7", "to": "e5" },
|
|
"expected": { "success": false, "error": "Wrong turn" }
|
|
}
|
|
],
|
|
"assertions": [
|
|
{ "type": "pieceAt", "square": "e7", "expected": "black-pawn" },
|
|
{ "type": "turn", "expected": "white" }
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Usage in Tests
|
|
|
|
```javascript
|
|
import scenario from './test-data/scenarios/pawn-movement.json';
|
|
|
|
describe(scenario.name, () => {
|
|
test(scenario.description, async () => {
|
|
// Setup
|
|
const chess = new Chess(scenario.setup.fen);
|
|
|
|
// Execute steps
|
|
for (const step of scenario.steps) {
|
|
const result = executeAction(step.action, step.params);
|
|
expect(result).toMatchObject(step.expected);
|
|
}
|
|
|
|
// Verify assertions
|
|
for (const assertion of scenario.assertions) {
|
|
verifyAssertion(chess, assertion);
|
|
}
|
|
});
|
|
});
|
|
```
|
|
|
|
## Scenario Categories
|
|
|
|
- **piece-movement**: Basic piece movements
|
|
- **special-moves**: Castling, en passant, promotion
|
|
- **game-state**: Check, checkmate, stalemate
|
|
- **ui-interaction**: Drag-drop, click-to-move
|
|
- **error-handling**: Invalid moves, wrong turn
|
|
- **performance**: Load testing, stress testing
|
|
|
|
## Adding New Scenarios
|
|
|
|
1. Create JSON file with proper structure
|
|
2. Validate JSON syntax
|
|
3. Test scenario manually
|
|
4. Add to appropriate category
|
|
5. Update this README
|
|
|
|
## Validation
|
|
|
|
```javascript
|
|
const validateScenario = (scenario) => {
|
|
return (
|
|
scenario.id &&
|
|
scenario.name &&
|
|
scenario.category &&
|
|
scenario.priority &&
|
|
scenario.setup &&
|
|
scenario.steps &&
|
|
Array.isArray(scenario.assertions)
|
|
);
|
|
};
|
|
```
|