import { describe, expect, it } from 'vitest'; import { createDraft, parseLoadoutDraft } from './loadout.js'; const copyDraft = () => structuredClone(createDraft()); describe('parseLoadoutDraft', () => { it('accepts a current draft and returns an independent clone', () => { const draft = createDraft(); const parsed = parseLoadoutDraft(draft); expect(parsed).toEqual(draft); expect(parsed?.calculationMode).toBe('maximum'); expect(parsed).not.toBe(draft); parsed!.gear.Holster.level = 1; expect(draft.gear.Holster.level).toBe(50); }); it('rejects the retired version 1 three-chip shape', () => { const retired = copyDraft() as unknown as Record; retired.version = 1; retired.chips = (retired.chips as unknown[]).slice(0, 3); expect(parseLoadoutDraft(retired)).toBeNull(); }); it('rejects a version 4 draft that does not contain exactly nine chips', () => { const draft = copyDraft(); draft.chips.pop(); expect(parseLoadoutDraft(draft)).toBeNull(); }); it('rejects a draft missing the unified combat profile', () => { const draft = copyDraft() as unknown as Record; delete draft.combatProfile; expect(parseLoadoutDraft(draft)).toBeNull(); }); it('accepts a custom scenario and preserves its assumptions', () => { const draft = copyDraft(); draft.calculationMode = 'custom'; draft.combatProfile.hitRate = 63; draft.combatProfile.targetDistanceMeters = 28; draft.conditionalEffects.relentless = { mode: 'encounter', inputs: { alliesWithinRange: 3, targetHasDebuff: true, }, }; expect(parseLoadoutDraft(draft)).toEqual(draft); }); it('rejects drafts without the required calculation model', () => { const missing = copyDraft() as unknown as Record; delete missing.calculationMode; expect(parseLoadoutDraft(missing)).toBeNull(); const invalid = copyDraft() as unknown as Record; invalid.calculationMode = 'legacy'; expect(parseLoadoutDraft(invalid)).toBeNull(); }); it('rejects a specialization that carries retired unassigned chips', () => { const draft = copyDraft() as unknown as { specialization: Record; }; draft.specialization.unassignedChips = []; expect(parseLoadoutDraft(draft)).toBeNull(); }); it('rejects malformed nested equipment selections', () => { const draft = copyDraft(); draft.weapons[0].rolls[1] = { statId: 'weapon-damage', value: Number.NaN }; expect(parseLoadoutDraft(draft)).toBeNull(); }); });