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

notify-activity-feed.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.

notify-activity-feed.test.tsBlame94 lines · 1 contributor
b7b5f75ccanty labs1/**
2 * logActivity() — the activity_feed writer wired into push/PR/merge paths
3 * on 2026-07-15 (see src/hooks/post-receive.ts, src/routes/pulls.tsx,
4 * src/lib/pr-merge.ts, src/lib/mcp-tools.ts). Before this, activity_feed
5 * was only ever written by fork/use-template/claude-connect/reviewer-suggest,
6 * so dashboards and the repo-page "recent push" indicator were blind to
7 * anything done through git push, the web PR flow, or the MCP write tools.
8 *
9 * Uses the same mock.module("../db", ...) fake-db pattern as push.test.ts —
10 * `logActivity` must never throw (mirrors `audit()`'s contract), and it
11 * must write the exact shape callers rely on (action, targetType, targetId,
12 * metadata as a JSON string).
13 */
14
15import { describe, it, expect, beforeEach, afterAll, mock } from "bun:test";
16
17const _real_db = await import("../db");
18
19const _inserted: Array<{ table: string; values: any }> = [];
20let _shouldThrow = false;
21
22const tableName = (t: any): string => {
23 if (!t || typeof t !== "object") return "?";
24 if ("action" in t && "repositoryId" in t && "targetType" in t) return "activity_feed";
25 return "?";
26};
27
28const _fakeDb = {
29 db: {
30 insert: (t: any) => ({
31 values: (vals: any) => {
32 if (_shouldThrow) return Promise.reject(new Error("db unavailable"));
33 _inserted.push({ table: tableName(t), values: vals });
34 return Promise.resolve();
35 },
36 }),
37 },
38 getDb: () => _fakeDb.db,
39};
40
41mock.module("../db", () => ({ ..._real_db, ..._fakeDb }));
42
43const { logActivity } = await import("../lib/notify");
44
45afterAll(() => {
46 mock.module("../db", () => _real_db);
47});
48
49beforeEach(() => {
50 _inserted.length = 0;
51 _shouldThrow = false;
52});
53
54describe("logActivity", () => {
55 it("writes an activity_feed row with the given action/target/metadata", async () => {
56 await logActivity({
57 repositoryId: "repo-1",
58 userId: "user-1",
59 action: "push",
60 targetType: "commit",
61 targetId: "a".repeat(40),
62 metadata: { branch: "main" },
63 });
64
65 expect(_inserted).toHaveLength(1);
66 expect(_inserted[0]!.table).toBe("activity_feed");
67 expect(_inserted[0]!.values).toMatchObject({
68 repositoryId: "repo-1",
69 userId: "user-1",
70 action: "push",
71 targetType: "commit",
72 targetId: "a".repeat(40),
73 });
74 expect(_inserted[0]!.values.metadata).toBe(JSON.stringify({ branch: "main" }));
75 });
76
77 it("defaults userId to null when omitted", async () => {
78 await logActivity({ repositoryId: "repo-1", action: "pr_open" });
79 expect(_inserted[0]!.values.userId).toBeNull();
80 });
81
82 it("never throws when the DB insert fails — same fail-open contract as audit()", async () => {
83 _shouldThrow = true;
84 await expect(
85 logActivity({ repositoryId: "repo-1", action: "pr_merge" })
86 ).resolves.toBeUndefined();
87 expect(_inserted).toHaveLength(0);
88 });
89
90 it("sets metadata to null when not provided", async () => {
91 await logActivity({ repositoryId: "repo-1", action: "comment", targetType: "pull_request", targetId: "42" });
92 expect(_inserted[0]!.values.metadata).toBeNull();
93 });
94});