Skip to content

Commit e15fbd7

Browse files
committed
fix: use createClerkClient for Clerk SDK v2.13.0 compatibility
1 parent 87d16d9 commit e15fbd7

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

src/__tests__/auth.test.ts

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
/**
2+
* Auth middleware tests
3+
* Tests Clerk integration and user creation flow
4+
*/
5+
6+
import { describe, it, expect, beforeEach, jest } from "@jest/globals";
7+
import { db } from "../db";
8+
import { users } from "../db/schema";
9+
import { eq } from "drizzle-orm";
10+
import { cleanupDatabase, countRows } from "./helpers/testDb";
11+
12+
// Mock Clerk SDK
13+
const mockGetUser = jest.fn();
14+
const mockVerifyToken = jest.fn();
15+
16+
jest.mock("@clerk/backend", () => ({
17+
verifyToken: (...args: unknown[]) => mockVerifyToken(...args),
18+
createClerkClient: () => ({
19+
users: {
20+
getUser: (...args: unknown[]) => mockGetUser(...args),
21+
},
22+
}),
23+
}));
24+
25+
// Import after mocking
26+
import { authMiddleware } from "../middleware/auth";
27+
import { Hono } from "hono";
28+
29+
describe("Auth Middleware", () => {
30+
beforeEach(async () => {
31+
await cleanupDatabase();
32+
jest.clearAllMocks();
33+
});
34+
35+
describe("clerkClient usage", () => {
36+
it("should call clerkClient.users.getUser (not clerkClient().users.getUser) for new users", async () => {
37+
const testUserId = "user_test_clerk_client";
38+
const testEmail = "newuser@example.com";
39+
40+
// Mock successful token verification
41+
mockVerifyToken.mockResolvedValue({
42+
sub: testUserId,
43+
});
44+
45+
// Mock Clerk API response for new user
46+
mockGetUser.mockResolvedValue({
47+
id: testUserId,
48+
emailAddresses: [
49+
{
50+
id: "email_1",
51+
emailAddress: testEmail,
52+
},
53+
],
54+
primaryEmailAddressId: "email_1",
55+
firstName: "New",
56+
lastName: "User",
57+
});
58+
59+
// Create test app with auth middleware
60+
const app = new Hono();
61+
app.use("*", authMiddleware);
62+
app.get("/test", (c) => c.json({ userId: c.get("userId") }));
63+
64+
// Make request (user doesn't exist in DB yet)
65+
const response = await app.request("/test", {
66+
headers: {
67+
Authorization: "Bearer test-token",
68+
},
69+
});
70+
71+
// Should succeed
72+
expect(response.status).toBe(200);
73+
74+
// Verify clerkClient.users.getUser was called (not clerkClient().users.getUser)
75+
expect(mockGetUser).toHaveBeenCalledWith(testUserId);
76+
expect(mockGetUser).toHaveBeenCalledTimes(1);
77+
78+
// Verify user was created in DB
79+
const createdUser = await db.query.users.findFirst({
80+
where: eq(users.id, testUserId),
81+
});
82+
83+
expect(createdUser).toBeDefined();
84+
expect(createdUser?.email).toBe(testEmail);
85+
expect(createdUser?.firstName).toBe("New");
86+
expect(createdUser?.lastName).toBe("User");
87+
});
88+
89+
it("should create default folders for new users", async () => {
90+
const testUserId = "user_test_folders";
91+
92+
mockVerifyToken.mockResolvedValue({ sub: testUserId });
93+
mockGetUser.mockResolvedValue({
94+
id: testUserId,
95+
emailAddresses: [{ id: "email_1", emailAddress: "folders@example.com" }],
96+
primaryEmailAddressId: "email_1",
97+
firstName: "Test",
98+
lastName: "User",
99+
});
100+
101+
const app = new Hono();
102+
app.use("*", authMiddleware);
103+
app.get("/test", (c) => c.json({ ok: true }));
104+
105+
await app.request("/test", {
106+
headers: { Authorization: "Bearer test-token" },
107+
});
108+
109+
// Check default folders were created
110+
const userFolders = await db.query.folders.findMany({
111+
where: eq(users.id, testUserId),
112+
});
113+
114+
// Should have 3 default folders: Personal, Work, Projects
115+
expect(userFolders.length).toBeGreaterThanOrEqual(3);
116+
});
117+
118+
it("should not call clerkClient for existing users", async () => {
119+
const testUserId = "user_existing";
120+
121+
// Create user in DB first
122+
await db.insert(users).values({
123+
id: testUserId,
124+
email: "existing@example.com",
125+
firstName: "Existing",
126+
lastName: "User",
127+
});
128+
129+
mockVerifyToken.mockResolvedValue({ sub: testUserId });
130+
131+
const app = new Hono();
132+
app.use("*", authMiddleware);
133+
app.get("/test", (c) => c.json({ userId: c.get("userId") }));
134+
135+
const response = await app.request("/test", {
136+
headers: { Authorization: "Bearer test-token" },
137+
});
138+
139+
expect(response.status).toBe(200);
140+
141+
// Should NOT call Clerk API for existing users
142+
expect(mockGetUser).not.toHaveBeenCalled();
143+
});
144+
145+
it("should return 401 for invalid token", async () => {
146+
mockVerifyToken.mockRejectedValue(new Error("Invalid token"));
147+
148+
const app = new Hono();
149+
app.use("*", authMiddleware);
150+
app.get("/test", (c) => c.json({ ok: true }));
151+
152+
const response = await app.request("/test", {
153+
headers: { Authorization: "Bearer invalid-token" },
154+
});
155+
156+
expect(response.status).toBe(401);
157+
expect(mockGetUser).not.toHaveBeenCalled();
158+
});
159+
160+
it("should return 401 for missing token", async () => {
161+
const app = new Hono();
162+
app.use("*", authMiddleware);
163+
app.get("/test", (c) => c.json({ ok: true }));
164+
165+
const response = await app.request("/test");
166+
167+
expect(response.status).toBe(401);
168+
expect(mockVerifyToken).not.toHaveBeenCalled();
169+
expect(mockGetUser).not.toHaveBeenCalled();
170+
});
171+
});
172+
});

0 commit comments

Comments
 (0)