Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesPull RequestsActionsSecurityInsightsSettings
✨ AI
More
Blame · Line-by-line history

web-routes.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.

web-routes.test.tsBlame164 lines · 3 contributors
06d5ffeClaude1import { describe, it, expect, beforeAll, afterAll } from "bun:test";
2import { join } from "path";
3import { rm, mkdir } from "fs/promises";
4import app from "../app";
5import { initBareRepo, getRepoPath } from "../git/repository";
6
7const TEST_REPOS = join(import.meta.dir, "../../.test-repos-web-" + Date.now());
8
9beforeAll(async () => {
10 await rm(TEST_REPOS, { recursive: true, force: true });
11 await mkdir(TEST_REPOS, { recursive: true });
12 process.env.GIT_REPOS_PATH = TEST_REPOS;
13
14 // Create a test repo with content
15 await initBareRepo("testuser", "myrepo");
16 const cloneDir = join(TEST_REPOS, "_clone");
17 await mkdir(cloneDir, { recursive: true });
18 const repoPath = getRepoPath("testuser", "myrepo");
19 const workDir = join(cloneDir, "work");
20
779c681ccantynz-alt21 // Must throw on failure — see the note in week3.test.ts. A silently failed
22 // clone leaves `cwd` inside the real repository and the subsequent git
23 // config/add/commit calls then mutate it.
06d5ffeClaude24 const run = async (cmd: string[], cwd: string) => {
25 const proc = Bun.spawn(cmd, { cwd, stdout: "pipe", stderr: "pipe" });
779c681ccantynz-alt26 const [exitCode, stderr] = await Promise.all([
27 proc.exited,
28 new Response(proc.stderr).text(),
29 ]);
30 if (exitCode !== 0) {
31 throw new Error(
32 `[web-routes fixture] ${cmd.join(" ")} failed in ${cwd} (exit ${exitCode}): ${stderr}`
33 );
34 }
06d5ffeClaude35 };
36
37 await run(["git", "clone", repoPath, workDir], TEST_REPOS);
38 await run(["git", "config", "user.email", "test@test.com"], workDir);
39 await run(["git", "config", "user.name", "Test"], workDir);
40
41 await mkdir(join(workDir, "src"), { recursive: true });
42 await Bun.write(join(workDir, "README.md"), "# My Repo\nHello");
43 await Bun.write(
44 join(workDir, "src/index.ts"),
45 'const x: number = 42;\nconsole.log(x);'
46 );
47
48 await run(["git", "add", "-A"], workDir);
49 await run(["git", "commit", "-m", "Initial commit"], workDir);
50 await run(["git", "branch", "-M", "main"], workDir);
51 await run(["git", "push", "-u", "origin", "main"], workDir);
52
53 // Create a second branch
54 await run(["git", "checkout", "-b", "feature"], workDir);
55 await Bun.write(join(workDir, "src/feature.ts"), "export const y = 1;");
56 await run(["git", "add", "-A"], workDir);
57 await run(["git", "commit", "-m", "Add feature"], workDir);
58 await run(["git", "push", "-u", "origin", "feature"], workDir);
59
60 await rm(cloneDir, { recursive: true, force: true });
61});
62
63afterAll(async () => {
64 await rm(TEST_REPOS, { recursive: true, force: true });
65});
66
67describe("web routes", () => {
68 it("GET / returns landing page", async () => {
69 const res = await app.request("/");
70 expect(res.status).toBe(200);
71 const html = await res.text();
72 expect(html).toContain("gluecron");
73 });
74
75 it("GET /login returns login form", async () => {
76 const res = await app.request("/login");
77 expect(res.status).toBe(200);
78 const html = await res.text();
79 expect(html).toContain("Sign in");
cf21786ccanty labs80 expect(html).toContain("Continue with GitHub");
81 expect(html).toContain("Email me a link");
06d5ffeClaude82 });
83
84 it("GET /register returns registration form", async () => {
85 const res = await app.request("/register");
86 expect(res.status).toBe(200);
87 const html = await res.text();
88 expect(html).toContain("Create account");
89 expect(html).toContain('name="username"');
90 expect(html).toContain('name="email"');
91 });
92
93 it("GET /new redirects to login without auth", async () => {
94 const res = await app.request("/new", { redirect: "manual" });
95 expect(res.status).toBe(302);
96 expect(res.headers.get("location")).toContain("/login");
97 });
98
99 it("GET /settings redirects to login without auth", async () => {
100 const res = await app.request("/settings", { redirect: "manual" });
101 expect(res.status).toBe(302);
102 expect(res.headers.get("location")).toContain("/login");
103 });
104
105 it("GET /:owner/:repo shows repo page", async () => {
106 const res = await app.request("/testuser/myrepo");
107 expect(res.status).toBe(200);
108 const html = await res.text();
109 expect(html).toContain("testuser");
110 expect(html).toContain("myrepo");
111 expect(html).toContain("README.md");
112 expect(html).toContain("src");
113 });
114
115 it("GET /:owner/:repo returns 404 for missing repo", async () => {
116 const res = await app.request("/nobody/nope");
117 expect(res.status).toBe(404);
118 });
119
120 it("GET /:owner/:repo/tree/:ref shows tree", async () => {
121 const res = await app.request("/testuser/myrepo/tree/main/src");
122 expect(res.status).toBe(200);
123 const html = await res.text();
124 expect(html).toContain("index.ts");
125 });
126
127 it("GET /:owner/:repo/blob/:ref/:path shows file with syntax highlighting", async () => {
128 const res = await app.request("/testuser/myrepo/blob/main/src/index.ts");
129 expect(res.status).toBe(200);
130 const html = await res.text();
131 // Should contain highlighted code
132 expect(html).toContain("hljs-");
133 expect(html).toContain("42");
134 });
135
136 it("GET /:owner/:repo/commits shows commits", async () => {
137 const res = await app.request("/testuser/myrepo/commits");
138 expect(res.status).toBe(200);
139 const html = await res.text();
140 expect(html).toContain("Initial commit");
141 });
142
143 it("supports branch switching — feature branch", async () => {
144 const res = await app.request("/testuser/myrepo/tree/feature");
145 expect(res.status).toBe(200);
146 const html = await res.text();
147 expect(html).toContain("feature");
148 });
149
150 it("feature branch has feature.ts", async () => {
151 const res = await app.request("/testuser/myrepo/tree/feature/src");
152 expect(res.status).toBe(200);
153 const html = await res.text();
154 expect(html).toContain("feature.ts");
155 });
156
157 it("shows branch dropdown when multiple branches", async () => {
158 const res = await app.request("/testuser/myrepo");
159 const html = await res.text();
160 expect(html).toContain("branch-dropdown");
161 expect(html).toContain("main");
162 expect(html).toContain("feature");
163 });
164});