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>
765 lines
14 KiB
Markdown
765 lines
14 KiB
Markdown
# Testing Tools and Setup Guide
|
|
|
|
## Overview
|
|
|
|
This document provides detailed instructions for setting up the testing environment and configuring all testing tools for the HTML chess game project.
|
|
|
|
---
|
|
|
|
## 1. Core Testing Framework
|
|
|
|
### 1.1 Jest
|
|
|
|
**Purpose**: JavaScript testing framework for unit and integration tests
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev jest @types/jest
|
|
```
|
|
|
|
**Configuration** (`jest.config.js`):
|
|
```javascript
|
|
module.exports = {
|
|
// Test environment
|
|
testEnvironment: 'jsdom',
|
|
|
|
// Coverage configuration
|
|
collectCoverageFrom: [
|
|
'src/**/*.{js,jsx,ts,tsx}',
|
|
'!src/**/*.d.ts',
|
|
'!src/**/*.stories.{js,jsx,ts,tsx}',
|
|
'!src/index.{js,jsx,ts,tsx}',
|
|
],
|
|
|
|
// Coverage thresholds
|
|
coverageThresholds: {
|
|
global: {
|
|
statements: 85,
|
|
branches: 80,
|
|
functions: 85,
|
|
lines: 85,
|
|
},
|
|
'./src/chess-engine/': {
|
|
statements: 95,
|
|
branches: 90,
|
|
functions: 95,
|
|
lines: 95,
|
|
},
|
|
},
|
|
|
|
// Test match patterns
|
|
testMatch: [
|
|
'<rootDir>/tests/**/*.test.{js,jsx,ts,tsx}',
|
|
'<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
|
|
],
|
|
|
|
// Module paths
|
|
modulePaths: ['<rootDir>/src'],
|
|
|
|
// Setup files
|
|
setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
|
|
|
|
// Transform files
|
|
transform: {
|
|
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
|
|
},
|
|
|
|
// Module name mapper (for CSS/images)
|
|
moduleNameMapper: {
|
|
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
|
|
'\\.(jpg|jpeg|png|gif|svg)$': '<rootDir>/tests/__mocks__/fileMock.js',
|
|
},
|
|
|
|
// Watch plugins
|
|
watchPlugins: [
|
|
'jest-watch-typeahead/filename',
|
|
'jest-watch-typeahead/testname',
|
|
],
|
|
};
|
|
```
|
|
|
|
**Package.json Scripts**:
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"test": "jest",
|
|
"test:watch": "jest --watch",
|
|
"test:coverage": "jest --coverage",
|
|
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 1.2 Testing Library
|
|
|
|
**Purpose**: DOM testing utilities for user-centric tests
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev @testing-library/dom
|
|
npm install --save-dev @testing-library/user-event
|
|
```
|
|
|
|
**Setup** (`tests/setup.js`):
|
|
```javascript
|
|
import '@testing-library/jest-dom';
|
|
|
|
// Custom matchers
|
|
expect.extend({
|
|
toBeValidChessMove(received, expected) {
|
|
const pass = isValidMove(received);
|
|
return {
|
|
pass,
|
|
message: () => `Expected ${received} to be a valid chess move`,
|
|
};
|
|
},
|
|
});
|
|
|
|
// Global test utilities
|
|
global.createBoard = () => {
|
|
// Board creation helper
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 2. End-to-End Testing
|
|
|
|
### 2.1 Playwright
|
|
|
|
**Purpose**: Cross-browser E2E testing
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev @playwright/test
|
|
npx playwright install
|
|
```
|
|
|
|
**Configuration** (`playwright.config.js`):
|
|
```javascript
|
|
import { defineConfig, devices } from '@playwright/test';
|
|
|
|
export default defineConfig({
|
|
testDir: './tests/e2e',
|
|
|
|
// Timeouts
|
|
timeout: 30000,
|
|
expect: {
|
|
timeout: 5000,
|
|
},
|
|
|
|
// Retry failed tests
|
|
retries: process.env.CI ? 2 : 0,
|
|
|
|
// Parallel execution
|
|
workers: process.env.CI ? 1 : undefined,
|
|
|
|
// Reporter
|
|
reporter: [
|
|
['html', { outputFolder: 'playwright-report' }],
|
|
['junit', { outputFile: 'test-results/junit.xml' }],
|
|
],
|
|
|
|
// Shared settings
|
|
use: {
|
|
baseURL: 'http://localhost:3000',
|
|
trace: 'on-first-retry',
|
|
screenshot: 'only-on-failure',
|
|
video: 'retain-on-failure',
|
|
},
|
|
|
|
// Browser projects
|
|
projects: [
|
|
{
|
|
name: 'chromium',
|
|
use: { ...devices['Desktop Chrome'] },
|
|
},
|
|
{
|
|
name: 'firefox',
|
|
use: { ...devices['Desktop Firefox'] },
|
|
},
|
|
{
|
|
name: 'webkit',
|
|
use: { ...devices['Desktop Safari'] },
|
|
},
|
|
{
|
|
name: 'Mobile Chrome',
|
|
use: { ...devices['Pixel 5'] },
|
|
},
|
|
{
|
|
name: 'Mobile Safari',
|
|
use: { ...devices['iPhone 13'] },
|
|
},
|
|
],
|
|
|
|
// Dev server
|
|
webServer: {
|
|
command: 'npm run start',
|
|
port: 3000,
|
|
reuseExistingServer: !process.env.CI,
|
|
},
|
|
});
|
|
```
|
|
|
|
**Example Test** (`tests/e2e/game-flow.spec.js`):
|
|
```javascript
|
|
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe('Chess Game Flow', () => {
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.goto('/');
|
|
});
|
|
|
|
test('should play a complete game', async ({ page }) => {
|
|
// Move white pawn e2-e4
|
|
await page.dragAndDrop('[data-square="e2"]', '[data-square="e4"]');
|
|
await expect(page.locator('[data-square="e4"]')).toHaveClass(/white-pawn/);
|
|
|
|
// Move black pawn e7-e5
|
|
await page.dragAndDrop('[data-square="e7"]', '[data-square="e5"]');
|
|
|
|
// Verify turn indicator
|
|
await expect(page.locator('[data-testid="turn-indicator"]'))
|
|
.toHaveText('White to move');
|
|
});
|
|
});
|
|
```
|
|
|
|
**Scripts**:
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"test:e2e": "playwright test",
|
|
"test:e2e:headed": "playwright test --headed",
|
|
"test:e2e:debug": "playwright test --debug",
|
|
"test:e2e:report": "playwright show-report"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Visual Regression Testing
|
|
|
|
### 3.1 Percy (Recommended)
|
|
|
|
**Purpose**: Automated visual testing
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev @percy/cli @percy/playwright
|
|
```
|
|
|
|
**Configuration** (`.percy.yml`):
|
|
```yaml
|
|
version: 2
|
|
static:
|
|
include: "public/**/*"
|
|
snapshot:
|
|
widths:
|
|
- 375
|
|
- 768
|
|
- 1280
|
|
min-height: 1024
|
|
percy-css: |
|
|
.animated { animation: none !important; }
|
|
```
|
|
|
|
**Usage in Tests**:
|
|
```javascript
|
|
import { percySnapshot } from '@percy/playwright';
|
|
|
|
test('visual test - initial board', async ({ page }) => {
|
|
await page.goto('/');
|
|
await percySnapshot(page, 'Initial Board State');
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### 3.2 Alternative: Playwright Screenshot Comparison
|
|
|
|
**Built-in screenshot testing**:
|
|
```javascript
|
|
test('visual regression - board', async ({ page }) => {
|
|
await page.goto('/');
|
|
await expect(page).toHaveScreenshot('initial-board.png', {
|
|
maxDiffPixels: 100,
|
|
});
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Performance Testing
|
|
|
|
### 4.1 Lighthouse CI
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev @lhci/cli
|
|
```
|
|
|
|
**Configuration** (`lighthouserc.js`):
|
|
```javascript
|
|
module.exports = {
|
|
ci: {
|
|
collect: {
|
|
startServerCommand: 'npm run start',
|
|
url: ['http://localhost:3000'],
|
|
numberOfRuns: 3,
|
|
},
|
|
assert: {
|
|
assertions: {
|
|
'categories:performance': ['error', { minScore: 0.9 }],
|
|
'categories:accessibility': ['error', { minScore: 0.9 }],
|
|
'categories:best-practices': ['error', { minScore: 0.9 }],
|
|
'categories:seo': ['error', { minScore: 0.9 }],
|
|
'first-contentful-paint': ['error', { maxNumericValue: 1500 }],
|
|
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
|
|
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
|
|
'time-to-interactive': ['error', { maxNumericValue: 3500 }],
|
|
},
|
|
},
|
|
upload: {
|
|
target: 'temporary-public-storage',
|
|
},
|
|
},
|
|
};
|
|
```
|
|
|
|
**Scripts**:
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"test:perf": "lhci autorun",
|
|
"test:perf:collect": "lhci collect",
|
|
"test:perf:assert": "lhci assert"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 4.2 Custom Performance Tests
|
|
|
|
**Using Performance API**:
|
|
```javascript
|
|
// tests/performance/move-calculation.test.js
|
|
describe('Move Calculation Performance', () => {
|
|
test('should generate legal moves in <100ms', () => {
|
|
const board = createComplexPosition();
|
|
|
|
const startTime = performance.now();
|
|
const legalMoves = generateLegalMoves(board);
|
|
const duration = performance.now() - startTime;
|
|
|
|
expect(duration).toBeLessThan(100);
|
|
expect(legalMoves.length).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Accessibility Testing
|
|
|
|
### 5.1 axe-core
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev @axe-core/playwright
|
|
```
|
|
|
|
**Usage in Playwright**:
|
|
```javascript
|
|
import { test, expect } from '@playwright/test';
|
|
import { injectAxe, checkA11y } from '@axe-core/playwright';
|
|
|
|
test('accessibility scan', async ({ page }) => {
|
|
await page.goto('/');
|
|
await injectAxe(page);
|
|
|
|
const violations = await checkA11y(page, null, {
|
|
detailedReport: true,
|
|
detailedReportOptions: {
|
|
html: true,
|
|
},
|
|
});
|
|
|
|
expect(violations).toHaveLength(0);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### 5.2 pa11y
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev pa11y
|
|
```
|
|
|
|
**Configuration** (`pa11y.config.js`):
|
|
```javascript
|
|
module.exports = {
|
|
standard: 'WCAG2AA',
|
|
runners: ['axe', 'htmlcs'],
|
|
level: 'error',
|
|
threshold: 0,
|
|
chromeLaunchConfig: {
|
|
args: ['--no-sandbox'],
|
|
},
|
|
};
|
|
```
|
|
|
|
**Script**:
|
|
```json
|
|
{
|
|
"scripts": {
|
|
"test:a11y": "pa11y http://localhost:3000 --config pa11y.config.js"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Code Quality Tools
|
|
|
|
### 6.1 ESLint
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev eslint eslint-config-airbnb-base
|
|
```
|
|
|
|
**Configuration** (`.eslintrc.json`):
|
|
```json
|
|
{
|
|
"extends": ["airbnb-base"],
|
|
"env": {
|
|
"browser": true,
|
|
"jest": true
|
|
},
|
|
"rules": {
|
|
"no-console": "warn",
|
|
"complexity": ["error", 10],
|
|
"max-lines": ["warn", 500],
|
|
"max-depth": ["error", 4]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 6.2 Prettier
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev prettier eslint-config-prettier
|
|
```
|
|
|
|
**Configuration** (`.prettierrc`):
|
|
```json
|
|
{
|
|
"singleQuote": true,
|
|
"trailingComma": "all",
|
|
"printWidth": 100,
|
|
"tabWidth": 2,
|
|
"semi": true
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 6.3 SonarQube (Optional)
|
|
|
|
**For advanced code quality metrics**:
|
|
```bash
|
|
npm install --save-dev sonarqube-scanner
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Test Data Management
|
|
|
|
### 7.1 FEN Parser
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev chess.js
|
|
```
|
|
|
|
**Usage**:
|
|
```javascript
|
|
import { Chess } from 'chess.js';
|
|
|
|
const loadPosition = (fen) => {
|
|
const chess = new Chess(fen);
|
|
return chess;
|
|
};
|
|
|
|
// In tests
|
|
test('Fool\'s Mate', () => {
|
|
const chess = new Chess();
|
|
chess.move('f3');
|
|
chess.move('e5');
|
|
chess.move('g4');
|
|
chess.move('Qh4');
|
|
|
|
expect(chess.isCheckmate()).toBe(true);
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
### 7.2 Test Data Fixtures
|
|
|
|
**Structure**:
|
|
```
|
|
tests/
|
|
fixtures/
|
|
positions/
|
|
fools-mate.fen
|
|
scholars-mate.fen
|
|
back-rank-mate.fen
|
|
games/
|
|
immortal-game.pgn
|
|
opera-game.pgn
|
|
```
|
|
|
|
**Loading Fixtures**:
|
|
```javascript
|
|
// tests/utils/fixtures.js
|
|
import { readFileSync } from 'fs';
|
|
import { join } from 'path';
|
|
|
|
export const loadFEN = (name) => {
|
|
const path = join(__dirname, '../fixtures/positions', `${name}.fen`);
|
|
return readFileSync(path, 'utf-8').trim();
|
|
};
|
|
|
|
export const loadPGN = (name) => {
|
|
const path = join(__dirname, '../fixtures/games', `${name}.pgn`);
|
|
return readFileSync(path, 'utf-8');
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Continuous Integration
|
|
|
|
### 8.1 GitHub Actions Workflow
|
|
|
|
**File**: `.github/workflows/test.yml`
|
|
```yaml
|
|
name: Test Suite
|
|
|
|
on:
|
|
push:
|
|
branches: [main, develop]
|
|
pull_request:
|
|
branches: [main, develop]
|
|
|
|
jobs:
|
|
test:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v3
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v3
|
|
with:
|
|
node-version: '18'
|
|
cache: 'npm'
|
|
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
|
|
- name: Run linter
|
|
run: npm run lint
|
|
|
|
- name: Run unit tests
|
|
run: npm run test:coverage
|
|
|
|
- name: Upload coverage
|
|
uses: codecov/codecov-action@v3
|
|
with:
|
|
files: ./coverage/lcov.info
|
|
|
|
- name: Run E2E tests
|
|
run: npm run test:e2e
|
|
|
|
- name: Upload Playwright report
|
|
if: always()
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: playwright-report
|
|
path: playwright-report/
|
|
|
|
- name: Run performance tests
|
|
run: npm run test:perf
|
|
|
|
- name: Run accessibility tests
|
|
run: npm run test:a11y
|
|
```
|
|
|
|
---
|
|
|
|
### 8.2 Pre-commit Hooks
|
|
|
|
**Installation**:
|
|
```bash
|
|
npm install --save-dev husky lint-staged
|
|
npx husky install
|
|
```
|
|
|
|
**Configuration** (`.husky/pre-commit`):
|
|
```bash
|
|
#!/bin/sh
|
|
. "$(dirname "$0")/_/husky.sh"
|
|
|
|
npx lint-staged
|
|
```
|
|
|
|
**Lint-staged** (`package.json`):
|
|
```json
|
|
{
|
|
"lint-staged": {
|
|
"*.{js,jsx,ts,tsx}": [
|
|
"eslint --fix",
|
|
"prettier --write",
|
|
"jest --bail --findRelatedTests"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Test Utilities
|
|
|
|
### 9.1 Custom Test Helpers
|
|
|
|
**File**: `tests/utils/helpers.js`
|
|
```javascript
|
|
export const createTestBoard = (fen = null) => {
|
|
// Create board from FEN or default
|
|
};
|
|
|
|
export const makeMove = (board, from, to) => {
|
|
// Helper to make moves in tests
|
|
};
|
|
|
|
export const assertCheckmate = (board) => {
|
|
// Assert checkmate state
|
|
};
|
|
|
|
export const waitForAnimation = async (element) => {
|
|
// Wait for CSS animations to complete
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### 9.2 Mock Data Generators
|
|
|
|
```javascript
|
|
// tests/utils/generators.js
|
|
export const generateRandomPosition = () => {
|
|
// Generate valid random board position
|
|
};
|
|
|
|
export const generateLegalMoves = (position) => {
|
|
// Generate all legal moves for position
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Monitoring and Reporting
|
|
|
|
### 10.1 Coverage Reports
|
|
|
|
**HTML Report**:
|
|
```bash
|
|
npm run test:coverage
|
|
open coverage/index.html
|
|
```
|
|
|
|
**CI Integration**:
|
|
- Codecov: Upload coverage to codecov.io
|
|
- Coveralls: Alternative coverage tracking
|
|
|
|
---
|
|
|
|
### 10.2 Test Dashboards
|
|
|
|
**Allure Report** (Optional):
|
|
```bash
|
|
npm install --save-dev @playwright/test allure-playwright
|
|
```
|
|
|
|
**Configuration**:
|
|
```javascript
|
|
// playwright.config.js
|
|
reporter: [
|
|
['allure-playwright'],
|
|
],
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Recommended VS Code Extensions
|
|
|
|
- **Jest**: orta.vscode-jest
|
|
- **Playwright Test for VSCode**: ms-playwright.playwright
|
|
- **ESLint**: dbaeumer.vscode-eslint
|
|
- **Prettier**: esbenp.prettier-vscode
|
|
- **Code Coverage**: ryanluker.vscode-coverage-gutters
|
|
|
|
---
|
|
|
|
## 12. Quick Start Commands
|
|
|
|
**Setup**:
|
|
```bash
|
|
npm install
|
|
npm run test:setup # Install browsers, etc.
|
|
```
|
|
|
|
**Development**:
|
|
```bash
|
|
npm run test:watch # Unit tests in watch mode
|
|
npm run test:e2e:headed # E2E tests with browser visible
|
|
```
|
|
|
|
**CI/CD**:
|
|
```bash
|
|
npm run lint
|
|
npm run test:coverage
|
|
npm run test:e2e
|
|
npm run test:perf
|
|
npm run test:a11y
|
|
```
|
|
|
|
**Debugging**:
|
|
```bash
|
|
npm run test:debug # Debug Jest tests
|
|
npm run test:e2e:debug # Debug Playwright tests
|
|
```
|
|
|
|
---
|
|
|
|
## Support and Resources
|
|
|
|
- **Jest Documentation**: https://jestjs.io/
|
|
- **Playwright Documentation**: https://playwright.dev/
|
|
- **Testing Library**: https://testing-library.com/
|
|
- **axe-core**: https://github.com/dequelabs/axe-core
|
|
- **Percy**: https://percy.io/
|
|
- **Lighthouse**: https://developers.google.com/web/tools/lighthouse
|