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-review.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-review.test.tsBlame127 lines · 1 contributor
fd87bb9Claude1/**
2 * Tests for src/lib/ai-review.ts.
3 *
4 * The Anthropic-calling path (reviewDiff) and the DB-touching paths
5 * (triggerAiReview's idempotency probe + insert) require external
6 * services we don't stand up in unit tests. We therefore cover the
7 * pure invariants:
8 *
9 * - The marker constant is stable so future searches keep working.
10 * - isAiReviewEnabled is a boolean reflecting config.anthropicApiKey.
11 * - triggerAiReview is a no-op (resolves cleanly) when the API key
12 * is absent — this is the documented graceful-degrade contract.
13 * - triggerAiReview never throws even when called with garbage.
14 * - The internal __test helpers are exported and shaped correctly.
15 */
16
17import { describe, it, expect } from "bun:test";
18import {
19 AI_REVIEW_MARKER,
20 isAiReviewEnabled,
21 triggerAiReview,
22 __test,
23} from "../lib/ai-review";
24
25describe("AI_REVIEW_MARKER", () => {
26 it("is the documented stable string", () => {
27 // Important: any change to this string is a breaking change for
28 // idempotency. New version → write a migration to back-fill old
29 // markers so older AI summaries still suppress duplicates.
30 expect(AI_REVIEW_MARKER).toBe("<!-- gluecron-ai-review:summary -->");
31 });
32
33 it("is an HTML comment so it doesn't render in markdown", () => {
34 expect(AI_REVIEW_MARKER.startsWith("<!--")).toBe(true);
35 expect(AI_REVIEW_MARKER.endsWith("-->")).toBe(true);
36 });
37});
38
39describe("isAiReviewEnabled", () => {
40 it("returns a boolean", () => {
41 const v = isAiReviewEnabled();
42 expect(typeof v).toBe("boolean");
43 });
44});
45
46describe("triggerAiReview — graceful degrade + crash-free", () => {
47 // Note: in the test sandbox ANTHROPIC_API_KEY is unset, so the
48 // function should resolve immediately without touching the DB. We
49 // also pass garbage repo names + nonexistent PR ids to confirm the
50 // overall try/catch holds.
51 it("resolves without throwing when API key is absent", async () => {
52 const before = process.env.ANTHROPIC_API_KEY;
53 delete process.env.ANTHROPIC_API_KEY;
54 try {
55 await triggerAiReview(
56 "alice",
57 "demo",
58 "00000000-0000-0000-0000-000000000000",
59 "Test PR",
60 "Body",
61 "main",
62 "feature"
63 );
64 } finally {
65 if (before) process.env.ANTHROPIC_API_KEY = before;
66 }
67 expect(true).toBe(true);
68 });
69
70 it("never throws even with invalid inputs", async () => {
71 let threw = false;
72 try {
73 await triggerAiReview(
74 "",
75 "",
76 "not-a-uuid",
77 "",
78 "",
79 "",
80 ""
81 );
82 } catch {
83 threw = true;
84 }
85 expect(threw).toBe(false);
86 });
87
88 it("survives an unknown branch combination without throwing", async () => {
89 let threw = false;
90 try {
91 await triggerAiReview(
92 "definitely-not-a-real-owner",
93 "definitely-not-a-real-repo",
94 "00000000-0000-0000-0000-000000000000",
95 "Title",
96 "Body",
97 "definitely-not-a-real-base",
98 "definitely-not-a-real-head"
99 );
100 } catch {
101 threw = true;
102 }
103 expect(threw).toBe(false);
104 });
105});
106
107describe("__test internals", () => {
108 it("exports diffBetweenBranches and alreadyReviewed", () => {
109 expect(typeof __test.diffBetweenBranches).toBe("function");
110 expect(typeof __test.alreadyReviewed).toBe("function");
111 });
112
113 it("diffBetweenBranches returns '' for a nonexistent repo", async () => {
114 const out = await __test.diffBetweenBranches(
115 "definitely-not-a-real-owner",
116 "definitely-not-a-real-repo",
117 "main",
118 "feature"
119 );
120 expect(out).toBe("");
121 });
122
123 it("alreadyReviewed returns false for an unknown PR id (fail-open)", async () => {
124 const out = await __test.alreadyReviewed("00000000-0000-0000-0000-000000000000");
125 expect(out).toBe(false);
126 });
127});