// tests/presets/storage.test.ts
import { beforeEach, describe, expect, it, vi } from 'vitest';
import type { Preset } from '~/engine/types';
import { deleteCustomPreset, loadCustomPresets, saveCustomPreset } from '~/presets/storage';
const species = {
color: [0.5, 0.5, 0.5] as const,
populationShare: 0.33,
sensorAngle: 0.5,
sensorDistance: 24,
turnSpeed: 0.4,
moveSpeed: 1,
depositAmount: 20,
};
const samplePreset: Preset = {
id: 'custom-1',
name: 'My Custom',
builtIn: false,
tags: ['test'],
tagSignal: 'pearl',
params: {
agentCount: 1000,
spawnPattern: 'random',
species: [species, species, species],
interactionMatrix: [
[1, -0.6, -0.6],
[-0.6, 1, -0.6],
[-0.6, -0.6, 1],
],
decayRate: 0.97,
diffusionFreq: 3,
fadeStrength: 0.1,
trailSaturation: 255,
chaosInterval: 0,
chaosStrength: 0,
rhythmAmplitude: 0.05,
simSpeed: 1,
blendMode: 'additive',
backgroundColor: [0, 0, 0],
headIntensity: 0,
kaleidoscope: 0,
exposure: 2.5,
feedbackAmount: 0.2,
bloomThreshold: 0.25,
bloomIntensity: 0.9,
vignette: 0.3,
saturation: 1.1,
contrast: 1.05,
audioReactive: { enabled: false, gain: 1, autoGain: false, routes: [] },
},
};
beforeEach(() => {
const store = new Map<string, string>();
vi.stubGlobal('localStorage', {
getItem: (k: string) => store.get(k) ?? null,
setItem: (k: string, v: string) => store.set(k, v),
removeItem: (k: string) => store.delete(k),
clear: () => store.clear(),
key: () => null,
length: 0,
});
});
describe('storage', () => {
it('save then load roundtrips', () => {
saveCustomPreset(samplePreset);
const loaded = loadCustomPresets();
expect(loaded).toHaveLength(1);
expect(loaded[0]?.id).toBe('custom-1');
});
it('delete removes', () => {
saveCustomPreset(samplePreset);
deleteCustomPreset('custom-1');
expect(loadCustomPresets()).toHaveLength(0);
});
it('loadCustomPresets returns [] when storage empty', () => {
expect(loadCustomPresets()).toEqual([]);
});
it('loadCustomPresets ignores invalid entries', () => {
localStorage.setItem('physarum:presets:custom', '[{"invalid":true}]');
expect(loadCustomPresets()).toEqual([]);
});
it('migrates a legacy single-species preset on load', () => {
const legacy = {
id: 'custom-old',
name: 'Old One',
builtIn: false,
tags: ['x'],
tagSignal: 'pearl',
params: {
agentCount: 5000,
sensorAngle: 0.5,
sensorDistance: 10,
turnSpeed: 0.4,
moveSpeed: 1,
evaporationRate: 0.05,
diffusionRate: 0.5,
depositAmount: 0.5,
trailColor: [0.5, 0.5, 0.5],
backgroundColor: [0, 0, 0],
exposure: 2.5,
audioReactive: { enabled: false, gain: 1, autoGain: false, routes: [] },
},
};
localStorage.setItem('physarum:presets:custom', JSON.stringify([legacy]));
const loaded = loadCustomPresets();
expect(loaded).toHaveLength(1);
const p = loaded[0];
expect(p?.params.species[0]?.populationShare).toBe(1);
expect(p?.params.species[1]?.populationShare).toBe(0);
expect(p?.params.spawnPattern).toBe('random');
});
});