dex/test/fuzzy.test.js
chris 55d26f50ed Who's that Pokémon?: fuzzy guessing + a generation filter
Fuzzy: src/lib/fuzzy.js — editDistance + closeEnough (length-scaled typo
tolerance, 0 for names ≤4 chars). submitGuess() accepts a near-miss, so
"charizrd" counts. Plus inline ghost-text completion: once the typed
prefix matches exactly one Pokémon, the rest of the name shows greyed
after the caret; → (at end), Tab or End accepts it.

Generation filter: a "Pull from" select (All / Gen 1–9, built from the
snapshot's species.generation). Choice persists in pdx.whosThat.gen;
changing it reshuffles the pool (and the completion list) and resets the
streak.

7 new unit tests for fuzzy.js (48 total).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Ve7HLspzeG2xDPtJQ8vmu
2026-09-10 13:19:03 -04:00

33 lines
1.1 KiB
JavaScript

import { describe, it, expect } from 'vitest';
import { editDistance, closeEnough } from '../src/lib/fuzzy.js';
describe('editDistance', () => {
it('counts insert / delete / substitute', () => {
expect(editDistance('', '')).toBe(0);
expect(editDistance('abc', 'abc')).toBe(0);
expect(editDistance('abc', 'ab')).toBe(1);
expect(editDistance('abc', 'abx')).toBe(1);
expect(editDistance('kitten', 'sitting')).toBe(3);
expect(editDistance('charizard', 'charizrd')).toBe(1);
});
});
describe('closeEnough', () => {
it('accepts a small typo on a long name', () => {
expect(closeEnough('charizrd', 'charizard')).toBe(true);
expect(closeEnough('tyraniter', 'tyranitar')).toBe(true);
expect(closeEnough('gardevor', 'gardevoir')).toBe(true);
});
it('is strict on short names', () => {
expect(closeEnough('meh', 'mew')).toBe(false);
expect(closeEnough('mow', 'muk')).toBe(false);
expect(closeEnough('mew', 'mew')).toBe(true);
});
it("won't bridge two genuinely different names", () => {
expect(closeEnough('pikachu', 'raichu')).toBe(false);
expect(closeEnough('bulbasaur', 'ivysaur')).toBe(false);
});
});