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

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

gists.test.tsBlame98 lines · 1 contributor
1e162a8Claude1/**
2 * Block E4 — Gists smoke tests.
3 *
4 * Full CRUD integration paths require a seeded test DB; we stick to pure
5 * helpers (`generateSlug`, `snapshotOf`) + public route behaviour
6 * (auth redirects, 404s) which exercise middleware + mounting.
7 */
8
9import { describe, it, expect } from "bun:test";
10import app from "../app";
11import { generateSlug, snapshotOf } from "../routes/gists";
12
13describe("gists — generateSlug", () => {
14 it("returns an 8-char lowercase hex string", () => {
15 const s = generateSlug();
16 expect(s).toMatch(/^[0-9a-f]{8}$/);
17 });
18
19 it("returns different values across calls", () => {
20 const a = generateSlug();
21 const b = generateSlug();
22 expect(a).not.toBe(b);
23 });
24});
25
26describe("gists — snapshotOf", () => {
27 it("JSON-encodes filename → content map", () => {
28 const snap = snapshotOf([
29 { filename: "a.ts", content: "export const a = 1;" },
30 { filename: "b.md", content: "# hello" },
31 ]);
32 const parsed = JSON.parse(snap);
33 expect(parsed["a.ts"]).toBe("export const a = 1;");
34 expect(parsed["b.md"]).toBe("# hello");
35 });
36
37 it("handles empty input", () => {
38 expect(snapshotOf([])).toBe("{}");
39 });
40
41 it("last duplicate filename wins", () => {
42 const snap = snapshotOf([
43 { filename: "x", content: "first" },
44 { filename: "x", content: "second" },
45 ]);
46 expect(JSON.parse(snap).x).toBe("second");
47 });
48});
49
50describe("gists — route smoke", () => {
51 it("GET /gists → 200 HTML", async () => {
52 const res = await app.request("/gists");
53 expect(res.status).toBe(200);
54 });
55
56 it("GET /gists/new without auth → 302 /login", async () => {
57 const res = await app.request("/gists/new");
58 expect(res.status).toBe(302);
59 expect(res.headers.get("location") || "").toMatch(/^\/login/);
60 });
61
62 it("POST /gists without auth → 302 /login", async () => {
63 const res = await app.request("/gists", {
64 method: "POST",
65 body: new URLSearchParams({ description: "x" }),
66 headers: { "content-type": "application/x-www-form-urlencoded" },
67 });
68 expect(res.status).toBe(302);
69 expect(res.headers.get("location") || "").toMatch(/^\/login/);
70 });
71
72 it("GET /gists/nonexistent → 404", async () => {
73 const res = await app.request("/gists/ffffffff");
74 expect(res.status).toBe(404);
75 });
76
77 it("GET /gists/xxx/edit without auth → 302 /login", async () => {
78 const res = await app.request("/gists/abc12345/edit");
79 expect(res.status).toBe(302);
80 expect(res.headers.get("location") || "").toMatch(/^\/login/);
81 });
82
83 it("POST /gists/xxx/delete without auth → 302 /login", async () => {
84 const res = await app.request("/gists/abc12345/delete", {
85 method: "POST",
86 });
87 expect(res.status).toBe(302);
88 expect(res.headers.get("location") || "").toMatch(/^\/login/);
89 });
90
91 it("POST /gists/xxx/star without auth → 302 /login", async () => {
92 const res = await app.request("/gists/abc12345/star", {
93 method: "POST",
94 });
95 expect(res.status).toBe(302);
96 expect(res.headers.get("location") || "").toMatch(/^\/login/);
97 });
98});