Files
loldle/web/test/classic-mode.test.js
tiennm99 078d80c962 refactor: port lib layer to src/lib
classic-mode.js moves byte-for-byte. champion-data.js swaps the Next.js
env-var fetch prefix for asset() from $app/paths, which resolves to
/champions.json in dev and /loldle/champions.json in the deployed build.
getChampionImageUrl keeps returning an absolute Data Dragon URL, unwrapped.

Drops three exports with no callers: getAllChampions, getChampionByName,
getGuessedNames.

The characterization suite passes unchanged against the new location -- only
import specifiers moved, no assertions touched.
2026-07-25 11:01:40 +07:00

164 lines
5.2 KiB
JavaScript

import { describe, expect, it } from "vitest";
import { CLASSIC_ATTRIBUTES, compareChampions } from "$lib/classic-mode";
import { AATROX, AHRI, AKALI, BELVETH } from "./fixtures/champions";
/** Pull one attribute's comparison out of the 7-entry result array. */
function cell(guess, target, key) {
return compareChampions(guess, target).find((r) => r.key === key);
}
describe("CLASSIC_ATTRIBUTES", () => {
it("exposes 7 attributes with gender first and releaseDate last", () => {
expect(CLASSIC_ATTRIBUTES).toHaveLength(7);
expect(CLASSIC_ATTRIBUTES[0].key).toBe("gender");
expect(CLASSIC_ATTRIBUTES[6].key).toBe("releaseDate");
});
it("keeps the display order the grid header depends on", () => {
expect(CLASSIC_ATTRIBUTES.map((a) => a.key)).toEqual([
"gender",
"genre",
"attackType",
"resource",
"region",
"lane",
"releaseDate",
]);
});
});
describe("compareChampions — result shape", () => {
it("returns one entry per attribute, carrying label and type through", () => {
const results = compareChampions(AHRI, AATROX);
expect(results).toHaveLength(7);
expect(results[0]).toMatchObject({
key: "gender",
label: "Gender",
type: "exact",
});
});
});
describe("compareChampions — exact", () => {
it("marks an identical value correct", () => {
expect(cell(AKALI, AHRI, "gender").result).toBe("correct");
});
it("marks a differing value wrong", () => {
expect(cell(AHRI, AATROX, "gender").result).toBe("wrong");
});
it("compares case-insensitively", () => {
const shouty = { ...AATROX, gender: "MALE" };
expect(cell(shouty, AATROX, "gender").result).toBe("correct");
});
it("treats a missing value as not matching a present one", () => {
expect(cell(BELVETH, AATROX, "resource").result).toBe("wrong");
});
});
describe("compareChampions — multi", () => {
it("marks identical sets correct", () => {
expect(cell(BELVETH, AATROX, "genre").result).toBe("correct");
});
it("marks intersecting sets partial", () => {
// AKALI lane "top,mid" overlaps AATROX lane "top"
expect(cell(AKALI, AATROX, "lane").result).toBe("partial");
});
it("marks disjoint sets wrong", () => {
expect(cell(AHRI, AATROX, "lane").result).toBe("wrong");
});
it("marks two empty sets correct", () => {
const a = { ...AATROX, lane: "" };
const b = { ...AATROX, lane: "" };
expect(cell(a, b, "lane").result).toBe("correct");
});
it("marks one empty set against a populated one wrong", () => {
const empty = { ...AATROX, lane: "" };
expect(cell(empty, AATROX, "lane").result).toBe("wrong");
});
it("ignores order and whitespace when comparing sets", () => {
const spaced = { ...AKALI, lane: " mid , top " };
expect(cell(spaced, AKALI, "lane").result).toBe("correct");
});
});
describe("compareChampions — year", () => {
it("marks the same year correct with no direction hint", () => {
const twin = { ...AHRI, releaseDate: 2013 };
const result = cell(twin, AATROX, "releaseDate");
expect(result.result).toBe("correct");
expect(result.direction).toBeUndefined();
});
it("points up when the guess is older than the target", () => {
expect(cell(AHRI, AATROX, "releaseDate")).toMatchObject({
result: "wrong",
direction: "up",
});
});
it("points down when the guess is newer than the target", () => {
expect(cell(BELVETH, AATROX, "releaseDate")).toMatchObject({
result: "wrong",
direction: "down",
});
});
it("gives no direction when either year is unparseable", () => {
const undated = { ...AHRI, releaseDate: "" };
const result = cell(undated, AATROX, "releaseDate");
expect(result.result).toBe("wrong");
expect(result.direction).toBeUndefined();
});
it("renders a missing year as ?", () => {
const undated = { ...AHRI, releaseDate: "" };
expect(cell(undated, AATROX, "releaseDate").guessValue).toBe("?");
});
it("passes the year through unformatted", () => {
expect(cell(AHRI, AATROX, "releaseDate")).toMatchObject({
guessValue: 2011,
targetValue: 2013,
});
});
});
describe("compareChampions — value formatting", () => {
it("capitalizes gender", () => {
expect(cell(AATROX, AATROX, "gender").guessValue).toBe("Male");
});
it("renders attackType close as Melee and range as Ranged", () => {
expect(cell(AATROX, AATROX, "attackType").guessValue).toBe("Melee");
expect(cell(AHRI, AHRI, "attackType").guessValue).toBe("Ranged");
});
it("splits hyphenated regions into capitalized words", () => {
expect(cell(AKALI, AKALI, "region").guessValue).toBe("Shadow Isles");
});
it("title-cases comma lists and rejoins them with a space", () => {
expect(cell(AHRI, AHRI, "genre").guessValue).toBe("Mage, Assassin");
expect(cell(AKALI, AKALI, "lane").guessValue).toBe("Top, Mid");
});
it("renders an empty value as an em dash", () => {
expect(cell(BELVETH, BELVETH, "resource").guessValue).toBe("—");
});
it("formats the target value the same way as the guess value", () => {
expect(cell(AHRI, AKALI, "region")).toMatchObject({
guessValue: "Ionia",
targetValue: "Shadow Isles",
});
});
});