import { describe, it, expect, beforeEach } from 'vitest'; import { selection, normalizeSelection, entry, gameEntry, toggle, stats, statsNational, importFlags, } from '../src/store/selection.js'; beforeEach(() => { localStorage.clear(); selection.replace({ version: 3, pokemon: {}, games: {} }); }); describe('normalizeSelection', () => { it('migrates a flat v2 store to per-game', () => { const v2 = { version: 2, pokemon: { 1: { seen: true, caught: true, favorite: true, note: '' }, 4: { seen: true, caught: false }, 150: { seen: true, caught: true, favorite: false, note: 'box 1' }, 25: { favorite: true }, // favourite only, never seen }, }; const out = normalizeSelection(v2); expect(out.version).toBe(3); // favourite / note lift to the global record expect(out.pokemon['1']).toMatchObject({ favorite: true }); expect(out.pokemon['150']).toMatchObject({ note: 'box 1' }); expect(out.pokemon['25']).toMatchObject({ favorite: true }); expect(out.pokemon['4']).toBeUndefined(); // nothing global to keep // seen / caught drop into the 'all' bucket, not a real game expect(out.games.all['1']).toMatchObject({ seen: true, caught: true }); expect(out.games.all['4']).toMatchObject({ seen: true, caught: false }); expect(out.games.all['25']).toBeUndefined(); }); it('passes a v3 store through untouched', () => { const v3 = { version: 3, pokemon: { 7: { favorite: true } }, games: { crystal: {} } }; expect(normalizeSelection(v3)).toEqual(v3); }); it('handles junk input', () => { expect(normalizeSelection(null)).toEqual({ version: 3, pokemon: {}, games: {} }); }); }); describe('per-game seen/caught', () => { it('a catch in one game does not appear in another', () => { toggle(3, 'caught', 'crystal'); expect(entry(3, 'crystal').caught).toBe(true); expect(entry(3, 'red-blue').caught).toBe(false); // catching implies seen expect(gameEntry(3, 'crystal').seen).toBe(true); }); it("'all' reads as the union across games", () => { toggle(1, 'caught', 'crystal'); toggle(4, 'caught', 'red-blue'); expect(gameEntry(1, 'all').caught).toBe(true); expect(gameEntry(4, 'all').caught).toBe(true); expect(gameEntry(7, 'all').caught).toBe(false); }); it('favorite is global, not per game', () => { toggle(25, 'favorite', 'crystal'); expect(entry(25, 'red-blue').favorite).toBe(true); expect(entry(25, 'emerald').favorite).toBe(true); }); it('stats counts one game; statsNational counts the union', () => { importFlags({ seen: [1, 2, 3], caught: [1, 2], game: 'crystal' }); importFlags({ seen: [4], caught: [4], game: 'red-blue' }); const cr = stats([1, 2, 3, 4], 'crystal'); expect(cr).toEqual({ seen: 3, caught: 2, total: 4 }); const rb = stats([1, 2, 3, 4], 'red-blue'); expect(rb).toEqual({ seen: 1, caught: 1, total: 4 }); const nat = statsNational([1, 2, 3, 4]); expect(nat).toEqual({ seen: 4, caught: 3, total: 4 }); }); });