import { describe, it, expect } from 'vitest'; import { heroItemFighter1Data, encounterDesertData, enemyDesertData, enemyIntentDesertData, effectDesertData, statusCardDesertData, } from '@/samples/slay-the-spire-like/data'; describe('heroItemFighter1.csv import', () => { it('should import data as an array', () => { expect(Array.isArray(heroItemFighter1Data)).toBe(true); expect(heroItemFighter1Data.length).toBeGreaterThan(0); }); it('should have expected number of items', () => { expect(heroItemFighter1Data.length).toBe(24); }); it('should have correct fields for each item', () => { for (const item of heroItemFighter1Data) { expect(item).toHaveProperty('type'); expect(item).toHaveProperty('name'); expect(item).toHaveProperty('shape'); expect(item).toHaveProperty('costType'); expect(item).toHaveProperty('costCount'); expect(item).toHaveProperty('targetType'); expect(item).toHaveProperty('desc'); expect(item).toHaveProperty('effects'); } }); it('should parse costCount as number', () => { for (const item of heroItemFighter1Data) { expect(typeof item.costCount).toBe('number'); } }); it('should contain expected items by name', () => { const names = heroItemFighter1Data.map(item => item.name); expect(names).toContain('剑'); expect(names).toContain('盾'); expect(names).toContain('绷带'); expect(names).toContain('火把'); }); it('should have valid type values', () => { const validTypes = ['weapon', 'armor', 'consumable', 'tool']; for (const item of heroItemFighter1Data) { expect(validTypes).toContain(item.type); } }); it('should have valid costType values', () => { const validCostTypes = ['energy', 'uses']; for (const item of heroItemFighter1Data) { expect(validCostTypes).toContain(item.costType); } }); it('should have valid targetType values', () => { const validTargetTypes = ['single', 'none']; for (const item of heroItemFighter1Data) { expect(validTargetTypes).toContain(item.targetType); } }); it('should have correct item counts by type', () => { const typeCounts = heroItemFighter1Data.reduce((acc, item) => { acc[item.type] = (acc[item.type] || 0) + 1; return acc; }, {} as Record); expect(typeCounts['weapon']).toBe(6); expect(typeCounts['armor']).toBe(6); expect(typeCounts['consumable']).toBe(6); expect(typeCounts['tool']).toBe(6); }); it('should have effects with target, effect ref, and value', () => { for (const item of heroItemFighter1Data) { expect(Array.isArray(item.effects)).toBe(true); for (const [target, effect, value] of item.effects) { expect(target === 'self' || target === 'target' || target === 'all' || target === 'random').toBe(true); expect(typeof effect === 'string' || typeof effect === 'object').toBe(true); expect(typeof value).toBe('number'); } } }); }); describe('encounterDesert.csv import', () => { it('should import data as an array', () => { expect(Array.isArray(encounterDesertData)).toBe(true); expect(encounterDesertData.length).toBeGreaterThan(0); }); it('should have correct encounter type counts', () => { const typeCounts = encounterDesertData.reduce((acc, e) => { acc[e.type] = (acc[e.type] || 0) + 1; return acc; }, {} as Record); expect(typeCounts['minion']).toBe(10); expect(typeCounts['elite']).toBe(4); expect(typeCounts['shop']).toBe(2); expect(typeCounts['camp']).toBe(2); expect(typeCounts['curio']).toBe(8); expect(typeCounts['event']).toBe(1); }); it('should have enemies for combat encounters', () => { for (const e of encounterDesertData) { if (e.type === 'minion' || e.type === 'elite') { expect(Array.isArray(e.enemies)).toBe(true); expect(e.enemies.length).toBeGreaterThan(0); for (const [enemy, bonusHp] of e.enemies) { expect(typeof enemy === 'string' || typeof enemy === 'object').toBe(true); expect(typeof bonusHp).toBe('number'); } } } }); it('should have empty enemies for non-combat encounters', () => { for (const e of encounterDesertData) { if (e.type === 'shop' || e.type === 'camp') { expect(e.enemies.length).toBe(0); } } }); it('should have dialogue for curio and event encounters', () => { for (const e of encounterDesertData) { if (e.type === 'curio' || e.type === 'event') { expect(e.dialogue).toBeTruthy(); expect(e.dialogue.startsWith('desert_')).toBe(true); } } }); }); describe('effectDesert.csv import', () => { it('should import data as an array', () => { expect(Array.isArray(effectDesertData)).toBe(true); expect(effectDesertData.length).toBeGreaterThan(0); }); it('should have expected number of effects', () => { expect(effectDesertData.length).toBe(35); }); it('should have correct fields for each effect', () => { for (const effect of effectDesertData) { expect(effect).toHaveProperty('id'); expect(effect).toHaveProperty('name'); expect(effect).toHaveProperty('description'); expect(effect).toHaveProperty('timing'); } }); it('should have valid timing values', () => { const validTimings = ['instant', 'temporary', 'lingering', 'permanent', 'posture', 'card', 'cardDraw', 'cardHand', 'item', 'itemUntilPlayed']; for (const effect of effectDesertData) { expect(validTimings).toContain(effect.timing); } }); it('should contain core effect types', () => { const ids = effectDesertData.map(e => e.id); expect(ids).toContain('attack'); expect(ids).toContain('defend'); expect(ids).toContain('spike'); expect(ids).toContain('venom'); expect(ids).toContain('draw'); expect(ids).toContain('removeWound'); expect(ids).toContain('gainEnergy'); }); }); describe('enemyDesert.csv import', () => { it('should import data as an array', () => { expect(Array.isArray(enemyDesertData)).toBe(true); expect(enemyDesertData.length).toBeGreaterThan(0); }); it('should have expected number of enemies', () => { expect(enemyDesertData.length).toBe(14); }); it('should have correct fields for each enemy', () => { for (const enemy of enemyDesertData) { expect(enemy).toHaveProperty('id'); expect(enemy).toHaveProperty('initHp'); expect(enemy).toHaveProperty('initBuffs'); expect(enemy).toHaveProperty('initialIntent'); expect(typeof enemy.initHp).toBe('number'); expect(typeof enemy.initialIntent).toBe('string'); } }); it('should have valid HP ranges', () => { for (const enemy of enemyDesertData) { expect(enemy.initHp).toBeGreaterThan(0); } }); it('should have minions with lower HP than elites', () => { const minionIds = ['仙人掌怪', '蛇', '木乃伊', '枪手', '风卷草', '秃鹫', '沙蝎', '幼沙虫', '蜥蜴', '沙匪']; const eliteIds = ['风暴之灵', '骑马枪手', '沙虫王', '沙漠守卫']; const byId = Object.fromEntries(enemyDesertData.map(e => [e.id, e])); for (const id of minionIds) { expect(byId[id].initHp).toBeLessThan(40); } for (const id of eliteIds) { expect(byId[id].initHp).toBeGreaterThanOrEqual(40); } }); }); describe('enemyIntentDesert.csv import', () => { it('should import data as an array', () => { expect(Array.isArray(enemyIntentDesertData)).toBe(true); expect(enemyIntentDesertData.length).toBeGreaterThan(0); }); it('should have expected number of intent rows', () => { expect(enemyIntentDesertData.length).toBe(41); }); it('should have correct fields for each intent', () => { for (const intent of enemyIntentDesertData) { expect(intent).toHaveProperty('enemy'); expect(intent).toHaveProperty('id'); expect(intent).toHaveProperty('nextIntents'); expect(intent).toHaveProperty('brokenIntent'); expect(intent).toHaveProperty('effects'); expect(intent.enemy).toHaveProperty('id'); expect(Array.isArray(intent.nextIntents)).toBe(true); expect(Array.isArray(intent.brokenIntent)).toBe(true); expect(Array.isArray(intent.effects)).toBe(true); } }); it('should have effects with target, effect ref, and value', () => { for (const intent of enemyIntentDesertData) { for (const [target, effect, value] of intent.effects) { expect(target === 'self' || target === 'player' || target === 'team').toBe(true); expect(typeof effect === 'string' || typeof effect === 'object').toBe(true); expect(typeof value).toBe('number'); } } }); it('should cover all 14 enemies', () => { const enemyIds = new Set(enemyIntentDesertData.map(i => typeof i.enemy === 'string' ? i.enemy : i.enemy.id)); expect(enemyIds.size).toBe(14); }); }); describe('statusCardDesert.csv import', () => { it('should import data as an array', () => { expect(Array.isArray(statusCardDesertData)).toBe(true); expect(statusCardDesertData.length).toBeGreaterThan(0); }); it('should have expected number of status cards', () => { expect(statusCardDesertData.length).toBe(6); }); it('should have correct fields for each status card', () => { for (const card of statusCardDesertData) { expect(card).toHaveProperty('id'); expect(card).toHaveProperty('name'); expect(card).toHaveProperty('desc'); expect(card).toHaveProperty('unplayable'); expect(card).toHaveProperty('effects'); expect(typeof card.id).toBe('string'); expect(typeof card.name).toBe('string'); expect(typeof card.desc).toBe('string'); expect(typeof card.unplayable).toBe('boolean'); } }); it('should have all cards unplayable', () => { for (const card of statusCardDesertData) { expect(card.unplayable).toBe(true); } }); it('should have effects with target, effect ref, and value', () => { for (const card of statusCardDesertData) { expect(Array.isArray(card.effects)).toBe(true); for (const [target, effect, value] of card.effects) { expect(target).toBe('self'); expect(typeof effect === 'string' || typeof effect === 'object').toBe(true); expect(typeof value).toBe('number'); } } }); it('should contain expected status cards by id', () => { const ids = statusCardDesertData.map(c => c.id); expect(ids).toContain('wound'); expect(ids).toContain('venom'); expect(ids).toContain('curse'); expect(ids).toContain('static'); }); });