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,180 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { processAchievements } from './achievementSystem';
|
||||
import { createTestState } from '../__test-utils__';
|
||||
import type { AchievementDefinition } from '@ai-tycoon/shared';
|
||||
|
||||
function makeDef(overrides: Partial<AchievementDefinition> = {}): AchievementDefinition {
|
||||
return {
|
||||
id: 'ach-1',
|
||||
name: 'First Million',
|
||||
description: 'Earn $1,000',
|
||||
icon: 'money',
|
||||
condition: { field: 'economy.money', operator: 'gte', value: 1000 },
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe('processAchievements', () => {
|
||||
it('returns unchanged state when tickCount is not divisible by 10', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 7 },
|
||||
economy: { money: 999999 },
|
||||
});
|
||||
const defs = [makeDef()];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual([]);
|
||||
expect(result.achievements).toBe(state.achievements);
|
||||
});
|
||||
|
||||
it('checks achievements when tickCount % 10 === 0', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 10 },
|
||||
economy: { money: 5000 },
|
||||
});
|
||||
const defs = [makeDef({ condition: { field: 'economy.money', operator: 'gte', value: 1000 } })];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual(['First Million']);
|
||||
expect(result.achievements.unlocked).toHaveLength(1);
|
||||
expect(result.achievements.unlocked[0]).toMatchObject({ id: 'ach-1', unlockedAtTick: 10 });
|
||||
});
|
||||
|
||||
it('does not unlock when gte condition is not met', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 10 },
|
||||
economy: { money: 500 },
|
||||
});
|
||||
const defs = [makeDef({ condition: { field: 'economy.money', operator: 'gte', value: 1000 } })];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual([]);
|
||||
expect(result.achievements.unlocked).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('handles gt operator as strictly greater than', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 20 },
|
||||
economy: { money: 1000 },
|
||||
});
|
||||
const defs = [makeDef({ condition: { field: 'economy.money', operator: 'gt', value: 1000 } })];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual([]);
|
||||
|
||||
const state2 = createTestState({
|
||||
meta: { tickCount: 20 },
|
||||
economy: { money: 1001 },
|
||||
});
|
||||
|
||||
const result2 = processAchievements(state2, defs);
|
||||
|
||||
expect(result2.newAchievements).toEqual(['First Million']);
|
||||
});
|
||||
|
||||
it('handles eq operator as exact match', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 30 },
|
||||
economy: { money: 1000 },
|
||||
});
|
||||
const defs = [makeDef({ condition: { field: 'economy.money', operator: 'eq', value: 1000 } })];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual(['First Million']);
|
||||
|
||||
const state2 = createTestState({
|
||||
meta: { tickCount: 30 },
|
||||
economy: { money: 1001 },
|
||||
});
|
||||
|
||||
const result2 = processAchievements(state2, defs);
|
||||
|
||||
expect(result2.newAchievements).toEqual([]);
|
||||
});
|
||||
|
||||
it('does not duplicate already-unlocked achievements', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 20 },
|
||||
economy: { money: 5000 },
|
||||
achievements: {
|
||||
unlocked: [{ id: 'ach-1', unlockedAtTick: 10 }],
|
||||
progress: {},
|
||||
},
|
||||
});
|
||||
const defs = [makeDef()];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual([]);
|
||||
expect(result.achievements.unlocked).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('can unlock multiple achievements in one tick', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 10 },
|
||||
economy: { money: 5000 },
|
||||
});
|
||||
const defs = [
|
||||
makeDef({ id: 'ach-1', name: 'First K', condition: { field: 'economy.money', operator: 'gte', value: 1000 } }),
|
||||
makeDef({ id: 'ach-2', name: 'Five K', condition: { field: 'economy.money', operator: 'gte', value: 5000 } }),
|
||||
makeDef({ id: 'ach-3', name: 'Ten K', condition: { field: 'economy.money', operator: 'gte', value: 10000 } }),
|
||||
];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual(['First K', 'Five K']);
|
||||
expect(result.achievements.unlocked).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('resolves meta._eraIndex for era-based achievements', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 10, currentEra: 'bigtech' },
|
||||
});
|
||||
const defs = [
|
||||
makeDef({ id: 'era-ach', name: 'Big Tech Era', condition: { field: 'meta._eraIndex', operator: 'gte', value: 2 } }),
|
||||
];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual(['Big Tech Era']);
|
||||
});
|
||||
|
||||
it('resolves meta._deployedModelCount for deployed model achievements', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 10 },
|
||||
models: {
|
||||
baseModels: [
|
||||
{ isDeployed: true },
|
||||
{ isDeployed: true },
|
||||
{ isDeployed: false },
|
||||
] as any,
|
||||
},
|
||||
});
|
||||
const defs = [
|
||||
makeDef({ id: 'model-ach', name: 'Two Models', condition: { field: 'meta._deployedModelCount', operator: 'eq', value: 2 } }),
|
||||
];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual(['Two Models']);
|
||||
});
|
||||
|
||||
it('resolves nested fields like economy.money', () => {
|
||||
const state = createTestState({
|
||||
meta: { tickCount: 0 },
|
||||
economy: { money: 42 },
|
||||
});
|
||||
const defs = [
|
||||
makeDef({ id: 'exact', name: 'Exact 42', condition: { field: 'economy.money', operator: 'eq', value: 42 } }),
|
||||
];
|
||||
|
||||
const result = processAchievements(state, defs);
|
||||
|
||||
expect(result.newAchievements).toEqual(['Exact 42']);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user