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

follows.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.

follows.test.tsBlame64 lines · 1 contributor
7aa8b99Claude1/**
2 * Block J4 — User following route-auth smokes + pure-helper tests.
3 *
4 * Graph mutations (followUser, etc.) are DB-bound so they're only exercised
5 * via integration. Here we cover the describeAction verb table and
6 * verify route guards redirect anonymous users.
7 */
8
9import { describe, it, expect } from "bun:test";
10import app from "../app";
11import { describeAction } from "../lib/follows";
12
13describe("follows — describeAction", () => {
14 it("maps known actions", () => {
15 expect(describeAction("push")).toBe("pushed to");
16 expect(describeAction("issue_open")).toBe("opened an issue in");
17 expect(describeAction("issue_close")).toBe("closed an issue in");
18 expect(describeAction("pr_open")).toBe("opened a pull request in");
19 expect(describeAction("pr_merge")).toBe("merged a pull request in");
20 expect(describeAction("pr_close")).toBe("closed a pull request in");
21 expect(describeAction("star")).toBe("starred");
22 expect(describeAction("comment")).toBe("commented in");
23 });
24
25 it("falls back to underscore-stripped action for unknown tokens", () => {
26 expect(describeAction("release_publish")).toBe("release publish");
27 expect(describeAction("custom")).toBe("custom");
28 });
29});
30
31describe("follows — route auth", () => {
32 it("POST /:user/follow without auth → 302 /login", async () => {
33 const res = await app.request("/alice/follow", { method: "POST" });
34 expect(res.status).toBe(302);
35 expect(res.headers.get("location") || "").toContain("/login");
36 });
37
38 it("POST /:user/unfollow without auth → 302 /login", async () => {
39 const res = await app.request("/alice/unfollow", { method: "POST" });
40 expect(res.status).toBe(302);
41 expect(res.headers.get("location") || "").toContain("/login");
42 });
43
44 it("GET /feed without auth → 302 /login", async () => {
45 const res = await app.request("/feed");
46 expect(res.status).toBe(302);
47 expect(res.headers.get("location") || "").toContain("/login");
48 });
49
50 it("GET /:user/followers is public (404 or 500 for unknown user)", async () => {
51 const res = await app.request("/nobody-x/followers");
52 expect([404, 500]).toContain(res.status);
53 });
54
55 it("GET /:user/following is public (404 or 500 for unknown user)", async () => {
56 const res = await app.request("/nobody-x/following");
57 expect([404, 500]).toContain(res.status);
58 });
59
60 it("reserved name /login/followers is not a profile route", async () => {
61 const res = await app.request("/login/followers");
62 expect([404, 405, 200, 302]).toContain(res.status);
63 });
64});