馃 distributed transcription service
thistle.dunkirk.sh
1import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2import db from "../db/schema";
3import { createSession, createUser } from "./auth";
4
5describe("subscription-protected routes", () => {
6 let testUserId: number;
7 let sessionCookie: string;
8
9 beforeEach(async () => {
10 // Create test user
11 const user = await createUser(
12 `test-${Date.now()}@example.com`,
13 "0".repeat(64),
14 "Test User",
15 );
16 testUserId = user.id;
17 const sessionId = createSession(testUserId, "127.0.0.1", "test");
18 sessionCookie = `session=${sessionId}`;
19 });
20
21 afterEach(() => {
22 // Cleanup
23 db.run("DELETE FROM users WHERE id = ?", [testUserId]);
24 db.run("DELETE FROM subscriptions WHERE user_id = ?", [testUserId]);
25 });
26
27 test("GET /api/transcriptions requires subscription", async () => {
28 const response = await fetch("http://localhost:3000/api/transcriptions", {
29 headers: { Cookie: sessionCookie },
30 });
31
32 expect(response.status).toBe(403);
33 const data = await response.json();
34 expect(data.error).toContain("subscription");
35 });
36
37 test("GET /api/transcriptions succeeds with active subscription", async () => {
38 // Add subscription
39 db.run(
40 "INSERT INTO subscriptions (id, user_id, customer_id, status) VALUES (?, ?, ?, ?)",
41 ["test-sub", testUserId, "test-customer", "active"],
42 );
43
44 const response = await fetch("http://localhost:3000/api/transcriptions", {
45 headers: { Cookie: sessionCookie },
46 });
47
48 expect(response.status).toBe(200);
49 const data = await response.json();
50 expect(data.jobs).toBeDefined();
51 });
52
53 test("GET /api/transcriptions succeeds for admin without subscription", async () => {
54 // Make user admin
55 db.run("UPDATE users SET role = ? WHERE id = ?", ["admin", testUserId]);
56
57 const response = await fetch("http://localhost:3000/api/transcriptions", {
58 headers: { Cookie: sessionCookie },
59 });
60
61 expect(response.status).toBe(200);
62 const data = await response.json();
63 expect(data.jobs).toBeDefined();
64 });
65
66 test("POST /api/transcriptions requires subscription", async () => {
67 const formData = new FormData();
68 const file = new File(["test"], "test.mp3", { type: "audio/mpeg" });
69 formData.append("audio", file);
70
71 const response = await fetch("http://localhost:3000/api/transcriptions", {
72 method: "POST",
73 headers: { Cookie: sessionCookie },
74 body: formData,
75 });
76
77 expect(response.status).toBe(403);
78 const data = await response.json();
79 expect(data.error).toContain("subscription");
80 });
81
82 test("/api/auth/me includes subscription status", async () => {
83 const response = await fetch("http://localhost:3000/api/auth/me", {
84 headers: { Cookie: sessionCookie },
85 });
86
87 expect(response.status).toBe(200);
88 const data = await response.json();
89 expect(data.has_subscription).toBe(false);
90
91 // Add subscription
92 db.run(
93 "INSERT INTO subscriptions (id, user_id, customer_id, status) VALUES (?, ?, ?, ?)",
94 ["test-sub", testUserId, "test-customer", "active"],
95 );
96
97 const response2 = await fetch("http://localhost:3000/api/auth/me", {
98 headers: { Cookie: sessionCookie },
99 });
100
101 expect(response2.status).toBe(200);
102 const data2 = await response2.json();
103 expect(data2.has_subscription).toBe(true);
104 });
105});