Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

ai-explain.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.

ai-explain.test.tsBlame87 lines · 1 contributor
3cbe3d6Claude1/**
2 * Block D6 — AI "Explain this codebase" tests.
3 *
4 * These run without a live database. The lib function is specified never
5 * to throw; the route responds with 404 on unknown repos and gracefully
6 * degrades when the DB proxy is unavailable (503).
7 */
8
9import { describe, it, expect } from "bun:test";
10import {
11 explainCodebase,
12 getCachedExplanation,
13} from "../lib/ai-explain";
14
15describe("lib/ai-explain — module shape", () => {
16 it("exports the expected functions", () => {
17 expect(typeof explainCodebase).toBe("function");
18 expect(typeof getCachedExplanation).toBe("function");
19 });
20});
21
22describe("lib/ai-explain — explainCodebase", () => {
23 it("returns the fallback shape for a bogus owner/repo without throwing", async () => {
24 const result = await explainCodebase({
25 owner: "does-not-exist",
26 repo: "neither-does-this",
27 repositoryId: "00000000-0000-0000-0000-000000000000",
28 commitSha: "0".repeat(40),
29 });
30 expect(result).toBeDefined();
31 expect(typeof result.markdown).toBe("string");
32 expect(typeof result.summary).toBe("string");
33 expect(typeof result.model).toBe("string");
34 expect(result.cached).toBe(false);
35 // When there is no bare git repo, no files can be sampled and the
36 // helper falls through to the canonical "unable to generate" message.
37 expect(result.markdown).toBe("_Unable to generate explanation._");
38 expect(result.model).toBe("fallback");
39 });
40
41 it("never throws even when both the DB and git repo are missing", async () => {
42 await expect(
43 explainCodebase({
44 owner: "alice",
45 repo: "project",
46 repositoryId: "00000000-0000-0000-0000-000000000000",
47 commitSha: "deadbeef".repeat(5),
48 force: true,
49 })
50 ).resolves.toBeDefined();
51 });
52});
53
54describe("lib/ai-explain — getCachedExplanation", () => {
55 it("returns null on cache miss / unavailable DB without throwing", async () => {
56 const result = await getCachedExplanation(
57 "00000000-0000-0000-0000-000000000000",
58 "0".repeat(40)
59 );
60 expect(result).toBeNull();
61 });
62});
63
64describe("routes/ai-explain — guards", () => {
65 it("direct GET /:owner/:repo/explain 404s when repo does not exist", async () => {
66 const { default: aiExplainRoutes } = await import("../routes/ai-explain");
67 const res = await aiExplainRoutes.request("/alice/does-not-exist/explain");
68 // 404 when the DB reports no such repo; 503 when the DB proxy is down.
69 expect([404, 503]).toContain(res.status);
70 });
71
72 it("direct POST /:owner/:repo/explain/regenerate without auth redirects to /login or 404s", async () => {
73 const { default: aiExplainRoutes } = await import("../routes/ai-explain");
74 const res = await aiExplainRoutes.request(
75 "/alice/does-not-exist/explain/regenerate",
76 {
77 method: "POST",
78 redirect: "manual",
79 }
80 );
81 expect([302, 303, 404, 503]).toContain(res.status);
82 if (res.status === 302 || res.status === 303) {
83 const loc = res.headers.get("location") || "";
84 expect(loc).toContain("/login");
85 }
86 });
87});