Files
idlegame/src/content/__tests__/schema.test.ts
T

151 lines
4.7 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { buildContent } from '../schema';
const validResources = [{ id: 'gold', name: 'Gold' }];
const validActions = [
{
id: 'forage',
name: 'Forage',
durationMs: 3000,
yields: [{ resourceId: 'gold', amount: 1 }],
},
];
describe('buildContent()', () => {
it('validates definitions and indexes them by id', () => {
const content = buildContent({ resources: validResources, actions: validActions });
expect(content.resourcesById.gold.name).toBe('Gold');
expect(content.actionsById.forage.durationMs).toBe(3000);
});
it('applies the startAmount default of 0', () => {
const content = buildContent({ resources: validResources, actions: validActions });
expect(content.resourcesById.gold.startAmount).toBe(0);
});
it('rejects an action that yields an unknown resource', () => {
const actions = [
{
id: 'forage',
name: 'Forage',
durationMs: 3000,
yields: [{ resourceId: 'ghost', amount: 1 }],
},
];
expect(() => buildContent({ resources: validResources, actions })).toThrow(/unknown resource/i);
});
it('rejects duplicate resource ids', () => {
const resources = [
{ id: 'gold', name: 'Gold' },
{ id: 'gold', name: 'Gold Again' },
];
expect(() => buildContent({ resources, actions: validActions })).toThrow(/duplicate/i);
});
it('rejects a structurally invalid definition', () => {
const actions = [
{
id: 'forage',
name: 'Forage',
durationMs: -1,
yields: [{ resourceId: 'gold', amount: 1 }],
},
];
expect(() => buildContent({ resources: validResources, actions })).toThrow();
});
});
describe('costs and multi-yield', () => {
it('accepts optional costs and multiple yields', () => {
const resources = [
{ id: 'gold', name: 'Gold' },
{ id: 'wood', name: 'Wood' },
];
const actions = [
{
id: 'craft',
name: 'Craft',
durationMs: 1000,
costs: [{ resourceId: 'wood', amount: 2 }],
yields: [
{ resourceId: 'gold', amount: 1 },
{ resourceId: 'wood', amount: 1 },
],
},
];
const content = buildContent({ resources, actions });
expect(content.actionsById.craft.costs).toEqual([{ resourceId: 'wood', amount: 2 }]);
expect(content.actionsById.craft.yields).toHaveLength(2);
});
it('rejects cost referencing unknown resource', () => {
const actions = [
{
id: 'craft',
name: 'Craft',
durationMs: 1000,
costs: [{ resourceId: 'ghost', amount: 1 }],
yields: [{ resourceId: 'gold', amount: 1 }],
},
];
expect(() => buildContent({ resources: validResources, actions })).toThrow(/unknown resource/i);
});
it('defaults costs to empty array', () => {
const content = buildContent({ resources: validResources, actions: validActions });
expect(content.actionsById.forage.costs).toEqual([]);
});
});
describe('unlock conditions', () => {
it('accepts optional minResources and requireStoryFlags', () => {
const actions = [
{
id: 'forage',
name: 'Forage',
durationMs: 3000,
yields: [{ resourceId: 'gold', amount: 1 }],
unlock: {
minResources: { gold: 10 },
requireStoryFlags: ['intro_complete'],
},
},
];
const content = buildContent({ resources: validResources, actions });
expect(content.actionsById.forage.unlock).toEqual({
minResources: { gold: 10 },
requireStoryFlags: ['intro_complete'],
});
});
it('defaults unlock to undefined when omitted', () => {
const content = buildContent({ resources: validResources, actions: validActions });
expect(content.actionsById.forage.unlock).toBeUndefined();
});
});
describe('action narrative fields', () => {
it('accepts optional storyHint and storyTooltip', () => {
const actions = [
{
id: 'forage',
name: 'Forage',
durationMs: 3000,
yields: [{ resourceId: 'gold', amount: 1 }],
storyHint: 'Gather what the forest offers.',
storyTooltip: 'Your first step into the wild.',
},
];
const content = buildContent({ resources: validResources, actions });
expect(content.actionsById.forage.storyHint).toBe('Gather what the forest offers.');
expect(content.actionsById.forage.storyTooltip).toBe('Your first step into the wild.');
});
it('defaults storyHint and storyTooltip to undefined when omitted', () => {
const content = buildContent({ resources: validResources, actions: validActions });
expect(content.actionsById.forage.storyHint).toBeUndefined();
expect(content.actionsById.forage.storyTooltip).toBeUndefined();
});
});