31 tests in test/, run in a plain Node env with a tiny localStorage shim (no jsdom — its Node-22.4 transitive-dep breakage isn't worth working around for logic tests): - type-chart: modern effectiveness, dual-type stacking, and the era rules (no Fairy pre-6, Steel resists Ghost/Dark pre-6, the Gen 1 Ghost→Psychic and Bug↔Poison quirks). - damage-calc: nature multipliers, the Gen 3+ stat formula (Garchomp reference values), STAB/effectiveness/immunity, pre/post-Gen-6 crit. - savedex: a synthetic Gen 1 SRAM (bitfields + checksum) round-trips; checksum-mismatch and size guards. - selection: normalizeSelection v2→v3 migration, per-game isolation, global favourite, stats vs statsNational. - pokedex-resolver: prettify, dex resolution against a mini snapshot. `npm test` wired into CI after format:check. Also: docker-compose host port 8080 → 4753 (README updated). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
81 lines
2.4 KiB
JavaScript
81 lines
2.4 KiB
JavaScript
import { describe, it, expect } from 'vitest';
|
||
import {
|
||
prettify,
|
||
dexesForVersionGroup,
|
||
resolvePokedex,
|
||
dexRows,
|
||
} from '../src/data/pokedex-resolver.js';
|
||
|
||
describe('prettify', () => {
|
||
it('title-cases a hyphenated key', () => {
|
||
expect(prettify('heartgold-soulsilver')).toBe('Heartgold Soulsilver');
|
||
expect(prettify('black-2-white-2')).toBe('Black 2 White 2');
|
||
expect(prettify('national')).toBe('National');
|
||
});
|
||
});
|
||
|
||
// A hand-built mini snapshot with the Map indexes loadSnapshot() would add.
|
||
function miniSnap() {
|
||
const pokedexes = [
|
||
{
|
||
key: 'national',
|
||
name: 'National',
|
||
entries: [
|
||
[1, 1],
|
||
[4, 4],
|
||
[999, 7],
|
||
],
|
||
},
|
||
{
|
||
key: 'kanto',
|
||
name: 'Kanto',
|
||
entries: [
|
||
[4, 1],
|
||
[1, 2],
|
||
],
|
||
},
|
||
];
|
||
const versionGroups = [
|
||
{ key: 'red-blue', name: 'Red Blue', generation: 1, pokedexKeys: ['kanto'] },
|
||
{ key: 'x-y', name: 'X Y', generation: 6, pokedexKeys: [] },
|
||
];
|
||
return {
|
||
pokedexByKey: new Map(pokedexes.map((d) => [d.key, d])),
|
||
versionGroupByKey: new Map(versionGroups.map((v) => [v.key, v])),
|
||
speciesById: new Map([
|
||
[1, { id: 1, name: 'bulbasaur' }],
|
||
[4, { id: 4, name: 'charmander' }],
|
||
]),
|
||
};
|
||
}
|
||
|
||
describe('dexesForVersionGroup', () => {
|
||
it('returns the group’s regional dexes', () => {
|
||
expect(dexesForVersionGroup(miniSnap(), 'red-blue').map((d) => d.key)).toEqual(['kanto']);
|
||
});
|
||
it('falls back to National when a group lists no dex', () => {
|
||
expect(dexesForVersionGroup(miniSnap(), 'x-y').map((d) => d.key)).toEqual(['national']);
|
||
});
|
||
});
|
||
|
||
describe('resolvePokedex', () => {
|
||
it('honours settings.pokedex when it belongs to the game', () => {
|
||
const snap = miniSnap();
|
||
// one-dex game: always that dex
|
||
expect(resolvePokedex(snap, { versionGroup: 'red-blue', pokedex: 'kanto' }).key).toBe('kanto');
|
||
// stale pokedex from another game -> that game's first dex
|
||
expect(resolvePokedex(snap, { versionGroup: 'red-blue', pokedex: 'hoenn' }).key).toBe('kanto');
|
||
});
|
||
});
|
||
|
||
describe('dexRows', () => {
|
||
it('expands entries and drops species missing from the snapshot', () => {
|
||
const snap = miniSnap();
|
||
const rows = dexRows(snap, snap.pokedexByKey.get('national'));
|
||
expect(rows).toEqual([
|
||
{ species: { id: 1, name: 'bulbasaur' }, number: 1 },
|
||
{ species: { id: 4, name: 'charmander' }, number: 4 },
|
||
]);
|
||
});
|
||
});
|