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

live-events.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.

live-events.test.tsBlame82 lines · 1 contributor
8ff60bcClaude1/**
2 * Smoke tests for GET /live-events/:topic — primarily the topic
3 * grammar. The full streaming path needs a live DB (read-gate), so we
4 * focus on:
5 * - 400 on invalid topics (single-letter, missing kind, bad chars)
6 * - non-400 on the valid forms (single-segment `kind:id`, multi-
7 * segment `kind:id:scope1:scope2`).
8 *
9 * The route uses softAuth; no cookie required.
10 */
11
12import { describe, it, expect } from "bun:test";
13import app from "../app";
14
15const NON_400_OK = [200, 301, 302, 303, 307, 401, 403, 404, 503];
16
17describe("GET /live-events/:topic — topic grammar", () => {
18 it("rejects an empty path beyond the prefix", async () => {
19 const res = await app.request("/live-events/", { redirect: "manual" });
20 // 404 for "no param" (Hono path doesn't match) is acceptable.
21 expect([400, 404]).toContain(res.status);
22 });
23
24 it("rejects a kind-only topic (no id)", async () => {
25 const res = await app.request("/live-events/repo");
26 expect([400, 404]).toContain(res.status);
27 });
28
29 it("rejects topics with disallowed characters", async () => {
30 const res = await app.request(
31 "/live-events/" + encodeURIComponent("repo:has spaces")
32 );
33 expect(res.status).toBe(400);
34 });
35
36 it("rejects topics with embedded slash", async () => {
37 const res = await app.request(
38 "/live-events/" + encodeURIComponent("repo:foo/bar")
39 );
40 expect(res.status).toBe(400);
41 });
42
43 it("accepts the canonical single-segment form (repo:<uuid>)", async () => {
44 const uuid = "00000000-0000-0000-0000-000000000000";
45 const res = await app.request(`/live-events/repo:${uuid}`, {
46 redirect: "manual",
47 });
48 // Either 404 (repo not found in DB) or some auth response — but
49 // critically not 400. The grammar must accept this shape.
50 expect(res.status).not.toBe(400);
51 expect(NON_400_OK).toContain(res.status);
52 });
53
54 it("accepts a multi-segment topic (repo:<uuid>:issue:7)", async () => {
55 const uuid = "00000000-0000-0000-0000-000000000000";
56 const res = await app.request(
57 `/live-events/repo:${uuid}:issue:7`,
58 { redirect: "manual" }
59 );
60 expect(res.status).not.toBe(400);
61 expect(NON_400_OK).toContain(res.status);
62 });
63
64 it("accepts a multi-segment PR topic (repo:<uuid>:pr:9)", async () => {
65 const uuid = "00000000-0000-0000-0000-000000000000";
66 const res = await app.request(
67 `/live-events/repo:${uuid}:pr:9`,
68 { redirect: "manual" }
69 );
70 expect(res.status).not.toBe(400);
71 expect(NON_400_OK).toContain(res.status);
72 });
73
74 it("accepts a non-repo kind (passes the read-gate)", async () => {
75 // `user:42` is not a repo so the auth-gate is bypassed; should
76 // open a stream (200 + text/event-stream) or fail later.
77 const res = await app.request(`/live-events/user:42`, {
78 redirect: "manual",
79 });
80 expect(res.status).not.toBe(400);
81 });
82});