import { describe, expect, it } from "vitest"; import { FINGERS, HOME_ROW, KEYBOARD_ROWS, fingerOf, handOf, homeKeyOf, keysInRow, rowOf, shiftHandFor, } from "../fingers"; const ALPHABET = "abcdefghijklmnopqrstuvwxyzäöüß"; describe("fingerOf", () => { it("maps every German letter to exactly one finger", () => { for (const key of ALPHABET) expect(fingerOf(key), key).not.toBeNull(); }); it("is case-insensitive", () => { for (const key of ALPHABET) { // "ß".toUpperCase() is "SS" - two characters, and not a key. `event.key` never // reports that, so the single-character case is the one that has to hold. const upper = key.toUpperCase(); if ([...upper].length !== 1) continue; expect(fingerOf(upper)?.id, upper).toBe(fingerOf(key)?.id); } }); it("returns null for keys that are not on the layout", () => { for (const key of ["Enter", "F1", "€", ""]) expect(fingerOf(key)).toBeNull(); }); it("assigns the home row to the eight home fingers, left to right", () => { const expected = [ "left-pinky", "left-ring", "left-middle", "left-index", "right-index", "right-middle", "right-ring", "right-pinky", ]; HOME_ROW.forEach((key, i) => expect(fingerOf(key)?.id).toBe(expected[i])); }); it("gives each finger the home key it actually rests on", () => { for (const key of HOME_ROW) expect(homeKeyOf(key)).toBe(key); expect(homeKeyOf(" ")).toBe(" "); }); it("sends the two index fingers to their stretch keys", () => { for (const key of "rtfgvb") expect(fingerOf(key)?.id).toBe("left-index"); for (const key of "zuhjnm") expect(fingerOf(key)?.id).toBe("right-index"); }); }); describe("hands", () => { it("splits the letters into two disjoint, non-empty sets", () => { const left = [...ALPHABET].filter((key) => handOf(key) === "left"); const right = [...ALPHABET].filter((key) => handOf(key) === "right"); expect(left.length).toBeGreaterThan(0); expect(right.length).toBeGreaterThan(0); expect(left.length + right.length).toBe(ALPHABET.length); expect(left.some((key) => right.includes(key))).toBe(false); }); it("shifts with the opposite hand", () => { expect(shiftHandFor("a")).toBe("right"); expect(shiftHandFor("l")).toBe("left"); expect(shiftHandFor("Enter")).toBeNull(); }); }); describe("rows", () => { it("places every letter in a row", () => { for (const key of ALPHABET) expect(rowOf(key), key).not.toBeNull(); }); it("has the home row in the home row", () => { for (const key of HOME_ROW) expect(rowOf(key)).toBe("home"); }); it("draws three rows, each with keys", () => { expect(KEYBOARD_ROWS).toHaveLength(3); for (const row of KEYBOARD_ROWS) expect(keysInRow(row).length).toBeGreaterThan(0); }); }); describe("FINGERS", () => { it("gives every finger a distinct hue so the colours can be named", () => { const hues = Object.values(FINGERS).map((finger) => finger.hue); expect(new Set(hues).size).toBe(hues.length); }); it("keeps each finger's id and key consistent", () => { for (const [id, finger] of Object.entries(FINGERS)) expect(finger.id).toBe(id); }); });