import 'reflect-metadata'; import { getMetadataArgsStorage } from 'typeorm'; import { Combat } from '../../combat/entities/combat.entity'; import { CombatEvent } from '../../combat/entities/combat-event.entity'; import { HuntEncounter } from '../../hunting/entities/hunt-encounter.entity'; describe('combat system schema', () => { it('maps Combat and CombatEvent relations with the documented onDelete behavior', () => { const metadata = getMetadataArgsStorage(); const relations = metadata.relations.filter( (relation) => relation.target === Combat || relation.target === CombatEvent, ); expect( relations.map((relation) => ({ onDelete: relation.options.onDelete, propertyName: relation.propertyName, target: relation.target, })), ).toEqual( expect.arrayContaining([ expect.objectContaining({ onDelete: 'RESTRICT', propertyName: 'character', target: Combat }), expect.objectContaining({ onDelete: 'RESTRICT', propertyName: 'huntEncounter', target: Combat }), expect.objectContaining({ onDelete: 'RESTRICT', propertyName: 'monster', target: Combat }), expect.objectContaining({ onDelete: 'CASCADE', propertyName: 'combat', target: CombatEvent }), ]), ); }); it('enforces one combat per hunt encounter via a unique index', () => { const metadata = getMetadataArgsStorage(); const index = metadata.indices.find( (candidate) => candidate.target === Combat && candidate.columns?.includes('huntEncounterId'), ); expect(index).toBeDefined(); const indexMetadata = index as typeof index & { options?: { unique?: boolean }; unique?: boolean }; expect(indexMetadata?.options?.unique ?? indexMetadata?.unique).toBe(true); }); it('enforces ordered, unique event sequencing per combat', () => { const metadata = getMetadataArgsStorage(); const index = metadata.indices.find( (candidate) => candidate.target === CombatEvent && candidate.columns?.includes('combatId') && candidate.columns?.includes('sequence'), ); expect(index).toBeDefined(); const indexMetadata = index as typeof index & { options?: { unique?: boolean }; unique?: boolean }; expect(indexMetadata?.options?.unique ?? indexMetadata?.unique).toBe(true); }); it('adds a nullable consumedAt column to hunt_encounters to prevent reuse', () => { const metadata = getMetadataArgsStorage(); const column = metadata.columns.find( (candidate) => candidate.target === HuntEncounter && candidate.propertyName === 'consumedAt', ); expect(column).toBeDefined(); expect(column?.options.nullable).toBe(true); }); });