chore: add tests for data loading
This commit is contained in:
parent
726856af35
commit
33095d5226
|
|
@ -0,0 +1,10 @@
|
|||
type EffectDesertTable = readonly {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
}[];
|
||||
|
||||
export type EffectDesert = EffectDesertTable[number];
|
||||
|
||||
declare const data: EffectDesertTable;
|
||||
export default data;
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
import type { EnemyDesert } from './enemyDesert.csv';
|
||||
|
||||
type EncounterDesertTable = readonly {
|
||||
readonly type: "minion" | "elite" | "event" | "shop" | "camp" | "curio";
|
||||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly enemies: readonly [EnemyDesert, number];
|
||||
readonly dialogue: string;
|
||||
}[];
|
||||
|
||||
export type EncounterDesert = EncounterDesertTable[number];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
type EnemyDesertTable = readonly {
|
||||
readonly id: string;
|
||||
readonly initHp: number;
|
||||
readonly initBuffs: readonly [string, number];
|
||||
readonly initialIntent: string;
|
||||
}[];
|
||||
|
||||
export type EnemyDesert = EnemyDesertTable[number];
|
||||
|
||||
declare const data: EnemyDesertTable;
|
||||
export default data;
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import type { EnemyDesert } from './enemyDesert.csv';
|
||||
import type { EffectDesert } from './effectDesert.csv';
|
||||
|
||||
type EnemyIntentDesertTable = readonly {
|
||||
readonly enemy: EnemyDesert;
|
||||
readonly intent: string;
|
||||
readonly nextIntents: readonly string[];
|
||||
readonly brokenIntent: readonly string[];
|
||||
readonly effects: readonly ["self" | "opponent", EffectDesert, number];
|
||||
}[];
|
||||
|
||||
export type EnemyIntentDesert = EnemyIntentDesertTable[number];
|
||||
|
||||
declare const data: EnemyIntentDesertTable;
|
||||
export default data;
|
||||
|
|
@ -1,6 +1,16 @@
|
|||
import heroItemFighter1Csv from './heroItemFighter1.csv';
|
||||
import encounterDesertCsv from './encounterDesert.csv';
|
||||
import enemyDesertCsv from './enemyDesert.csv';
|
||||
import enemyIntentDesertCsv from './enemyIntentDesert.csv';
|
||||
import effectDesertCsv from './effectDesert.csv';
|
||||
|
||||
export const heroItemFighter1Data = heroItemFighter1Csv;
|
||||
export const encounterDesertData = encounterDesertCsv;
|
||||
export const enemyDesertData = enemyDesertCsv;
|
||||
export const enemyIntentDesertData = enemyIntentDesertCsv;
|
||||
export const effectDesertData = effectDesertCsv;
|
||||
|
||||
export { default as encounterDesertCsv, type EncounterDesert } from './encounterDesert.csv';
|
||||
export { default as enemyDesertCsv, type EnemyDesert } from './enemyDesert.csv';
|
||||
export { default as enemyIntentDesertCsv, type EnemyIntentDesert } from './enemyIntentDesert.csv';
|
||||
export { default as effectDesertCsv, type EffectDesert } from './effectDesert.csv';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { heroItemFighter1Data } from '@/samples/slay-the-spire-like/data';
|
||||
import {
|
||||
heroItemFighter1Data,
|
||||
encounterDesertData,
|
||||
enemyDesertData,
|
||||
enemyIntentDesertData,
|
||||
effectDesertData,
|
||||
} from '@/samples/slay-the-spire-like/data';
|
||||
|
||||
describe('heroItemFighter1.csv import', () => {
|
||||
it('should import data as an array', () => {
|
||||
|
|
@ -8,7 +14,6 @@ describe('heroItemFighter1.csv import', () => {
|
|||
});
|
||||
|
||||
it('should have expected number of items', () => {
|
||||
// CSV has 24 data rows (excluding header and type rows)
|
||||
expect(heroItemFighter1Data.length).toBe(24);
|
||||
});
|
||||
|
||||
|
|
@ -71,3 +76,162 @@ describe('heroItemFighter1.csv import', () => {
|
|||
expect(typeCounts['tool']).toBe(6);
|
||||
});
|
||||
});
|
||||
|
||||
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<string, number>);
|
||||
|
||||
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 [enemyId, bonusHp] of e.enemies) {
|
||||
expect(typeof enemyId).toBe('string');
|
||||
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(19);
|
||||
});
|
||||
|
||||
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');
|
||||
}
|
||||
});
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
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('intent');
|
||||
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, effectId, value] of intent.effects) {
|
||||
expect(target === 'self' || target === 'opponent').toBe(true);
|
||||
expect(typeof effectId).toBe('string');
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue