Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

hot-files.test.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

hot-files.test.tsBlame78 lines · 1 contributor
74d8c4dClaude1/**
2 * Tests for src/lib/hot-files.ts and src/routes/hot-files.tsx.
3 */
4
5import { describe, test, expect } from "bun:test";
6
7// ─── Pure helper tests ────────────────────────────────────────────────────────
8
9// Risk classification logic — mirrors hot-files.ts without importing the async fn.
10const HIGH_RISK_PATTERNS = ["auth", "security", "schema", "db/", "middleware", "routes/git", "crypto"];
11const MEDIUM_RISK_PATTERNS = ["route", "api", "lib/", ".sql"];
12
13function classifyRisk(filePath: string): "high" | "medium" | "low" {
14 const lower = filePath.toLowerCase();
15 if (HIGH_RISK_PATTERNS.some((p) => lower.includes(p))) return "high";
16 if (MEDIUM_RISK_PATTERNS.some((p) => lower.includes(p))) return "medium";
17 return "low";
18}
19
20describe("hot-files risk classification", () => {
21 test("auth file → high", () => expect(classifyRisk("src/lib/auth.ts")).toBe("high"));
22 test("middleware file → high", () => expect(classifyRisk("src/middleware/rate-limit.ts")).toBe("high"));
23 test("schema file → high", () => expect(classifyRisk("src/db/schema.ts")).toBe("high"));
24 test("route file → medium", () => expect(classifyRisk("src/routes/issues.tsx")).toBe("medium"));
25 test("sql migration → medium", () => expect(classifyRisk("drizzle/0001.sql")).toBe("medium"));
26 test("api lib → medium", () => expect(classifyRisk("src/lib/api-helper.ts")).toBe("medium"));
27 test("test file → low", () => expect(classifyRisk("src/__tests__/orgs.test.ts")).toBe("low"));
28 test("readme → low", () => expect(classifyRisk("README.md")).toBe("low"));
29 test("case-insensitive: AUTH.TS → high", () => expect(classifyRisk("AUTH.TS")).toBe("high"));
30});
31
32// Extension extraction
33function extractExt(p: string): string {
34 const dot = p.lastIndexOf(".");
35 if (dot === -1 || dot === p.length - 1) return "";
36 return p.slice(dot + 1);
37}
38
39describe("hot-files extension extraction", () => {
40 test(".ts extension", () => expect(extractExt("src/lib/foo.ts")).toBe("ts"));
41 test(".tsx extension", () => expect(extractExt("src/routes/bar.tsx")).toBe("tsx"));
42 test("no extension → empty string", () => expect(extractExt("Makefile")).toBe(""));
43 test("trailing dot → empty string", () => expect(extractExt("file.")).toBe(""));
44 test(".sql extension", () => expect(extractExt("drizzle/0001.sql")).toBe("sql"));
45});
46
47// Path truncation
48function truncatePath(path: string, maxChars = 40): string {
49 if (path.length <= maxChars) return path;
50 return "…" + path.slice(path.length - maxChars);
51}
52
53describe("hot-files path truncation", () => {
54 test("short path unchanged", () => expect(truncatePath("src/foo.ts")).toBe("src/foo.ts"));
55 test("long path truncated with ellipsis", () => {
56 const long = "src/routes/very/deeply/nested/path/component/file.tsx";
57 const result = truncatePath(long, 40);
58 expect(result.startsWith("…")).toBe(true);
59 expect(result.length).toBe(41); // 1 for "…" + 40
60 });
61 test("exactly maxChars is unchanged", () => {
62 const exact = "a".repeat(40);
63 expect(truncatePath(exact, 40)).toBe(exact);
64 });
65});
66
67// ─── Route smoke test ─────────────────────────────────────────────────────────
68
69import app from "../app";
70
71const HAS_DB = Boolean(process.env.DATABASE_URL);
72
73describe("GET /:owner/:repo/insights/hotfiles", () => {
74 test.skipIf(!HAS_DB)("non-existent repo returns 404", async () => {
75 const res = await app.request("/__nx_owner__/__nx_repo__/insights/hotfiles");
76 expect(res.status).toBe(404);
77 });
78});