import { describe, it, expect, beforeEach } from 'vitest'; import { createGameState } from '../src/core/GameState'; import { PartType } from '../src/core/Part'; import { createPartAction, createMeepleAction, createCardAction, createTileAction, updatePartAction, removePartAction, getPartAction, } from '../src/actions/part.actions'; describe('Part Actions', () => { let gameState: ReturnType; beforeEach(() => { gameState = createGameState({ id: 'test-game', name: 'Test Game' }); }); describe('createPartAction', () => { it('should create a generic part', () => { const part = createPartAction(gameState, { id: 'part-1', type: PartType.Meeple, color: 'red', }); expect(part.id).toBe('part-1'); expect(part.type).toBe(PartType.Meeple); expect(getPartAction(gameState, 'part-1')).toBeDefined(); }); it('should create a part with metadata', () => { const part = createPartAction(gameState, { id: 'part-1', type: PartType.Tile, pattern: 'forest', metadata: { points: 5 }, }); expect(part.metadata).toEqual({ points: 5 }); }); }); describe('createMeepleAction', () => { it('should create a meeple part', () => { const meeple = createMeepleAction(gameState, 'meeple-1', 'blue'); expect(meeple.id).toBe('meeple-1'); expect(meeple.type).toBe(PartType.Meeple); expect(meeple.color).toBe('blue'); }); it('should create a meeple with name', () => { const meeple = createMeepleAction(gameState, 'meeple-1', 'blue', { name: 'Player 1' }); expect(meeple.name).toBe('Player 1'); }); }); describe('createCardAction', () => { it('should create a card part', () => { const card = createCardAction(gameState, 'card-1', { suit: 'hearts', value: 10 }); expect(card.id).toBe('card-1'); expect(card.type).toBe(PartType.Card); expect(card.suit).toBe('hearts'); expect(card.value).toBe(10); }); it('should create a card with string value', () => { const card = createCardAction(gameState, 'card-2', { suit: 'spades', value: 'ace' }); expect(card.value).toBe('ace'); }); }); describe('createTileAction', () => { it('should create a tile part', () => { const tile = createTileAction(gameState, 'tile-1', { pattern: 'road', rotation: 90 }); expect(tile.id).toBe('tile-1'); expect(tile.type).toBe(PartType.Tile); expect(tile.pattern).toBe('road'); expect(tile.rotation).toBe(90); }); it('should create a tile with default rotation', () => { const tile = createTileAction(gameState, 'tile-2', { pattern: 'city' }); expect(tile.rotation).toBeUndefined(); }); }); describe('updatePartAction', () => { it('should update part properties', () => { const meeple = createMeepleAction(gameState, 'meeple-1', 'red'); updatePartAction(gameState, 'meeple-1', { color: 'green' as string, name: 'Updated' }); const updated = getPartAction(gameState, 'meeple-1'); expect(updated?.color).toBe('green'); expect(updated?.name).toBe('Updated'); }); it('should update part metadata', () => { createMeepleAction(gameState, 'meeple-1', 'red', { metadata: { score: 0 } }); updatePartAction(gameState, 'meeple-1', { metadata: { score: 10 } } as any); const updated = getPartAction(gameState, 'meeple-1'); expect(updated?.metadata).toEqual({ score: 10 }); }); }); describe('removePartAction', () => { it('should remove a part', () => { createMeepleAction(gameState, 'meeple-1', 'red'); expect(getPartAction(gameState, 'meeple-1')).toBeDefined(); removePartAction(gameState, 'meeple-1'); expect(getPartAction(gameState, 'meeple-1')).toBeUndefined(); }); it('should remove placements referencing the part', () => { // 这个测试会在 placement 测试中更详细地验证 createMeepleAction(gameState, 'meeple-1', 'red'); removePartAction(gameState, 'meeple-1'); expect(getPartAction(gameState, 'meeple-1')).toBeUndefined(); }); }); describe('getPartAction', () => { it('should return undefined for non-existent part', () => { const part = getPartAction(gameState, 'non-existent'); expect(part).toBeUndefined(); }); it('should return existing part', () => { createMeepleAction(gameState, 'meeple-1', 'red'); const part = getPartAction(gameState, 'meeple-1'); expect(part?.id).toBe('meeple-1'); }); }); });