82 lines
2.6 KiB
TypeScript
82 lines
2.6 KiB
TypeScript
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<string, unknown>;
|
|
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<string, unknown>;
|
|
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<string, unknown>;
|
|
delete missing.calculationMode;
|
|
expect(parseLoadoutDraft(missing)).toBeNull();
|
|
|
|
const invalid = copyDraft() as unknown as Record<string, unknown>;
|
|
invalid.calculationMode = 'legacy';
|
|
expect(parseLoadoutDraft(invalid)).toBeNull();
|
|
});
|
|
|
|
it('rejects a specialization that carries retired unassigned chips', () => {
|
|
const draft = copyDraft() as unknown as {
|
|
specialization: Record<string, unknown>;
|
|
};
|
|
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();
|
|
});
|
|
});
|