Files
SerpentRace/SerpentRace_Backend/tests/Application/Game/BoardGenerationService.test.ts
Donat 86211923db Backend Complete: Interface Refactoring & Service Container Enhancements
Repository Interface Optimization:
- Created IBaseRepository.ts and IPaginatedRepository.ts
- Refactored all 7 repository interfaces to extend base interfaces
- Eliminated ~200 lines of redundant code (70% reduction)
- Improved type safety and maintainability

 Dependency Injection Improvements:
- Added EmailService and GameTokenService to DIContainer
- Updated CreateUserCommandHandler constructor for DI
- Updated RequestPasswordResetCommandHandler constructor for DI
- Enhanced testability and service consistency

 Environment Configuration:
- Created comprehensive .env.example with 40+ variables
- Organized into 12 logical sections (Database, Security, Email, etc.)
- Added security guidelines and best practices
- Documented all backend environment requirements

 Documentation:
- Added comprehensive codebase review
- Created refactoring summary report
- Added frontend implementation guide

Impact: Improved code quality, reduced maintenance overhead, enhanced developer experience
2025-09-21 03:27:57 +02:00

133 lines
5.5 KiB
TypeScript

import { BoardGenerationService } from '../../../src/Application/Game/BoardGenerationService';
// Mock dependencies
jest.mock('../../../src/Application/Services/LoggingService');
describe('BoardGenerationService', () => {
let boardGenerationService: BoardGenerationService;
beforeEach(() => {
boardGenerationService = new BoardGenerationService();
});
describe('generateBoard', () => {
it('should generate a board with the correct number of special fields', async () => {
const positiveFields = 10;
const negativeFields = 8;
const luckFields = 5;
const result = await boardGenerationService.generateBoard(
positiveFields,
negativeFields,
luckFields
);
expect(result).toBeDefined();
expect(result.fields).toHaveLength(100);
// Count special fields
const actualPositive = result.fields.filter(f => f.type === 'positive').length;
const actualNegative = result.fields.filter(f => f.type === 'negative').length;
const actualLuck = result.fields.filter(f => f.type === 'luck').length;
expect(actualPositive).toBe(positiveFields);
expect(actualNegative).toBe(negativeFields);
expect(actualLuck).toBe(luckFields);
});
it('should ensure positive fields have positive step values', async () => {
const result = await boardGenerationService.generateBoard(5, 5, 2);
const positiveFields = result.fields.filter(f => f.type === 'positive');
positiveFields.forEach(field => {
expect(field.stepValue).toBeGreaterThan(0);
});
});
it('should ensure negative fields have negative step values', async () => {
const result = await boardGenerationService.generateBoard(5, 5, 2);
const negativeFields = result.fields.filter(f => f.type === 'negative');
negativeFields.forEach(field => {
expect(field.stepValue).toBeLessThan(0);
});
});
it('should ensure luck fields do not have step values', async () => {
const result = await boardGenerationService.generateBoard(5, 5, 2);
const luckFields = result.fields.filter(f => f.type === 'luck');
luckFields.forEach(field => {
expect(field.stepValue).toBeUndefined();
});
});
it('should produce validation results without -1 values', async () => {
const result = await boardGenerationService.generateBoard(10, 8, 5);
// Check validation results for invalid moves (-1 values)
let invalidMoves = 0;
let totalMoves = 0;
Object.values(result.validationResults).forEach(diceOutcomes => {
diceOutcomes.forEach(outcome => {
totalMoves++;
if (outcome === -1) {
invalidMoves++;
}
});
});
const errorRate = totalMoves > 0 ? (invalidMoves / totalMoves) * 100 : 0;
// Log the results for analysis
console.log(`Error rate: ${errorRate}%`);
console.log(`Invalid moves: ${invalidMoves}/${totalMoves}`);
// The new algorithm should produce much fewer invalid moves
expect(errorRate).toBeLessThan(50); // Allow some errors but much better than before
});
it('should respect the 20-30 movement rule in validation', async () => {
const result = await boardGenerationService.generateBoard(10, 8, 5);
// Check each validation result to ensure it respects distance rules
Object.entries(result.validationResults).forEach(([fieldPosition, diceOutcomes]) => {
const currentPos = parseInt(fieldPosition);
diceOutcomes.forEach((outcome, diceIndex) => {
if (outcome !== -1) { // Only check valid moves
const distance = Math.abs(outcome - currentPos);
if (currentPos <= 85) {
// Fields 1-85: max 20 in any direction
expect(distance).toBeLessThanOrEqual(20);
} else {
// Fields 86-100: max 30 backward, max 20 forward
if (outcome > currentPos) {
expect(distance).toBeLessThanOrEqual(20); // forward
} else {
expect(distance).toBeLessThanOrEqual(30); // backward
}
}
}
});
});
});
it('should position special fields safely within the safe range', async () => {
const result = await boardGenerationService.generateBoard(10, 8, 5);
const specialFields = result.fields.filter(f => f.type !== 'regular');
// Most special fields should be in the safe range (11-90) for the new algorithm
const safeFields = specialFields.filter(f => f.position >= 11 && f.position <= 90);
const safePercentage = (safeFields.length / specialFields.length) * 100;
console.log(`Safe field percentage: ${safePercentage}%`);
// Expect most fields to be positioned safely
expect(safePercentage).toBeGreaterThan(70);
});
});
});