test: minimal vitest harness for backend and frontend

Ported from amal66/mike#24 onto current main; lockfiles regenerated against
this tree. Adds vitest as a dev dependency with a `test` script in both
packages, excludes test files from the backend tsc build, and seeds one
suite per package (backend: downloadTokens, 12 tests; frontend: cn() utils,
8 tests). Verified locally: backend 12/12, frontend 8/8 passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
QA Runner 2026-07-20 10:42:28 -07:00
parent dafac6b0a4
commit 4039b94980
7 changed files with 2683 additions and 31 deletions

File diff suppressed because it is too large Load diff

View file

@ -7,6 +7,7 @@
"build": "next build",
"start": "next start",
"lint": "eslint",
"test": "vitest run",
"preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
"deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
"upload": "opennextjs-cloudflare build && opennextjs-cloudflare upload",
@ -73,6 +74,7 @@
"tailwindcss": "^4",
"tw-animate-css": "^1.4.0",
"typescript": "^5",
"vitest": "^4.1.9",
"wrangler": "^4.90.0"
},
"license": "AGPL-3.0-only"

View file

@ -0,0 +1,45 @@
import { describe, expect, it } from "vitest";
import { cn, diceCoefficient, isFuzzyMatch } from "./utils";
describe("cn", () => {
it("joins truthy class names and drops falsy ones", () => {
expect(cn("a", false && "b", undefined, "c")).toBe("a c");
});
it("merges conflicting tailwind classes, keeping the last", () => {
expect(cn("px-2", "px-4")).toBe("px-4");
});
});
describe("diceCoefficient", () => {
it("returns 1 for identical strings (ignoring case and punctuation)", () => {
expect(diceCoefficient("Hello, World!", "hello world")).toBe(1);
});
it("returns 0 when either input is empty", () => {
expect(diceCoefficient("", "anything")).toBe(0);
expect(diceCoefficient("anything", "")).toBe(0);
});
it("returns a partial score for partially overlapping strings", () => {
const score = diceCoefficient("night", "nacht");
expect(score).toBeGreaterThan(0);
expect(score).toBeLessThan(1);
});
});
describe("isFuzzyMatch", () => {
it("matches near-identical strings above the default threshold", () => {
expect(isFuzzyMatch("organization", "organisation")).toBe(true);
});
it("rejects clearly different strings", () => {
expect(isFuzzyMatch("apple", "zebra")).toBe(false);
});
it("respects a custom threshold", () => {
// "night" vs "nacht" scores ~0.25 — passes a low bar, fails a high one.
expect(isFuzzyMatch("night", "nacht", 0.1)).toBe(true);
expect(isFuzzyMatch("night", "nacht", 0.9)).toBe(false);
});
});