Add Vitest test suite with 184 tests covering all game engine systems
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||
import { processTick, setAchievementDefinitions } from './tick';
|
||||
import { createTestState, createSeededRNG } from './__test-utils__';
|
||||
import { ACHIEVEMENT_DEFINITIONS } from './data/achievements';
|
||||
import { resetResearchBonusCache } from './systems/researchBonuses';
|
||||
|
||||
const rng = createSeededRNG(42);
|
||||
|
||||
beforeEach(() => {
|
||||
rng.install();
|
||||
resetResearchBonusCache();
|
||||
setAchievementDefinitions(ACHIEVEMENT_DEFINITIONS);
|
||||
});
|
||||
afterEach(() => rng.uninstall());
|
||||
|
||||
describe('processTick', () => {
|
||||
it('returns a valid partial state from initial state', () => {
|
||||
const state = createTestState();
|
||||
const result = processTick(state);
|
||||
|
||||
expect(result.meta).toBeDefined();
|
||||
expect(result.economy).toBeDefined();
|
||||
expect(result.infrastructure).toBeDefined();
|
||||
expect(result.compute).toBeDefined();
|
||||
expect(result.research).toBeDefined();
|
||||
expect(result.models).toBeDefined();
|
||||
expect(result.market).toBeDefined();
|
||||
expect(result.talent).toBeDefined();
|
||||
expect(result.reputation).toBeDefined();
|
||||
expect(result.data).toBeDefined();
|
||||
expect(result.competitors).toBeDefined();
|
||||
expect(result.achievements).toBeDefined();
|
||||
});
|
||||
|
||||
it('increments tickCount by 1', () => {
|
||||
const state = createTestState({ meta: { tickCount: 100 } });
|
||||
const result = processTick(state);
|
||||
expect(result.meta!.tickCount).toBe(101);
|
||||
});
|
||||
|
||||
it('increments totalPlayTime by 1', () => {
|
||||
const state = createTestState({ meta: { totalPlayTime: 500 } });
|
||||
const result = processTick(state);
|
||||
expect(result.meta!.totalPlayTime).toBe(501);
|
||||
});
|
||||
|
||||
it('preserves money when no revenue or expenses', () => {
|
||||
const state = createTestState({ economy: { money: 600_000 } });
|
||||
const result = processTick(state);
|
||||
expect(result.economy!.money).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
|
||||
it('attaches notifications array', () => {
|
||||
const state = createTestState();
|
||||
const result = processTick(state);
|
||||
const notifications = (result as Record<string, unknown>)['_notifications'];
|
||||
expect(Array.isArray(notifications)).toBe(true);
|
||||
});
|
||||
|
||||
it('generates era transition notification when thresholds met', () => {
|
||||
const deployedModel = {
|
||||
id: 'model-1', familyId: 'fam-1', name: 'Test v1',
|
||||
architecture: { type: 'dense' as const, totalParameters: 7e9, activeParameters: 7e9, contextWindow: 8192, vocabularySize: 32000 },
|
||||
rawCapability: 20, capabilities: { reasoning: 20, coding: 20, creative: 20, math: 20, knowledge: 20, multimodal: 0, agents: 10, speed: 50, contextUtilization: 50 },
|
||||
safetyProfile: { overallSafety: 50, refusalRate: 0.05, harmAvoidance: 50, instructionFollowing: 50, honesty: 50 },
|
||||
isDeployed: true, trainedAtTick: 0, trainingCostTotal: 0, trainingStagesCompleted: ['pretraining' as const],
|
||||
sizeTier: 'small' as const, version: 1.0, sftSpecializations: ['general' as const], alignmentMethod: 'rlhf' as const,
|
||||
dataMix: { web: 0.4, code: 0.2, books: 0.15, academic: 0.1, conversational: 0.1, specialized: 0.05 },
|
||||
benchmarkResults: {},
|
||||
};
|
||||
const state = createTestState({
|
||||
meta: { currentEra: 'startup' },
|
||||
economy: { totalRevenue: 10_000 },
|
||||
models: { bestDeployedModelScore: 20, bestDeployedSafetyScore: 50, baseModels: [deployedModel], families: [] },
|
||||
reputation: { score: 50, safetyRecord: 60, publicPerception: 50, employeeSatisfaction: 50, regulatoryStanding: 50 },
|
||||
});
|
||||
const result = processTick(state);
|
||||
expect(result.meta!.currentEra).toBe('scaleup');
|
||||
const notifications = (result as Record<string, unknown>)['_notifications'] as Array<{ title: string }>;
|
||||
expect(notifications.some(n => n.title === 'Era Transition!')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not transition era when thresholds not met', () => {
|
||||
const state = createTestState({
|
||||
meta: { currentEra: 'startup' },
|
||||
economy: { totalRevenue: 100 },
|
||||
models: { bestDeployedModelScore: 5 },
|
||||
reputation: { score: 20 },
|
||||
});
|
||||
const result = processTick(state);
|
||||
expect(result.meta!.currentEra).toBe('startup');
|
||||
});
|
||||
|
||||
it('recomputes valuation each tick', () => {
|
||||
const state = createTestState({
|
||||
economy: { revenuePerTick: 10 },
|
||||
market: { consumerTiers: { totalUsers: 100 } },
|
||||
models: { bestDeployedModelScore: 30 },
|
||||
});
|
||||
const result = processTick(state);
|
||||
expect(result.economy!.funding.valuation).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('research completion generates notification', () => {
|
||||
const state = createTestState({
|
||||
research: {
|
||||
activeResearch: {
|
||||
researchId: 'advanced-cooling',
|
||||
progressTicks: 59,
|
||||
totalTicks: 60,
|
||||
allocatedResearchers: 1,
|
||||
allocatedCompute: 5,
|
||||
},
|
||||
researchQueue: [],
|
||||
completedResearch: [],
|
||||
researchPoints: 0,
|
||||
},
|
||||
talent: {
|
||||
departments: {
|
||||
research: { headcount: 1, effectiveness: 0.5 },
|
||||
},
|
||||
},
|
||||
});
|
||||
const result = processTick(state);
|
||||
const notifications = (result as Record<string, unknown>)['_notifications'] as Array<{ title: string }>;
|
||||
expect(notifications.some(n => n.title === 'Research Complete')).toBe(true);
|
||||
expect(result.research!.completedResearch).toContain('advanced-cooling');
|
||||
});
|
||||
|
||||
it('multiple ticks are stable (no crash on sequential processing)', () => {
|
||||
let state = createTestState();
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const result = processTick(state);
|
||||
state = { ...state, ...result };
|
||||
}
|
||||
expect(state.meta.tickCount).toBe(10);
|
||||
expect(state.economy.money).toBeGreaterThanOrEqual(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user