feat: update tests for auth
This commit is contained in:
parent
9131a86262
commit
42d2054532
@ -1,80 +1,10 @@
|
||||
import { beforeAll, describe, expect, it } from "bun:test";
|
||||
import { migrate } from "drizzle-orm/bun-sql/migrator";
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import app from ".";
|
||||
import { db } from "./db";
|
||||
import { auth } from "./lib/auth";
|
||||
import { buildHeaders } from "./test/utils";
|
||||
|
||||
beforeAll(async () => {
|
||||
await migrate(db, { migrationsFolder: "./drizzle" });
|
||||
});
|
||||
|
||||
describe("First Test", () => {
|
||||
describe("API Health Check", () => {
|
||||
it("should return 200 Response", async () => {
|
||||
const req = new Request("http://localhost:3000/");
|
||||
const res = await app.fetch(req);
|
||||
expect(res.status).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Auth", () => {
|
||||
const user = {
|
||||
email: "yadunand@yadunut.com",
|
||||
password: "password123",
|
||||
name: "Yadunand Prem",
|
||||
username: "yadunut",
|
||||
};
|
||||
|
||||
let authHeaders: Headers;
|
||||
|
||||
it("creates a new user", async () => {
|
||||
const res = await auth.api.signUpEmail({
|
||||
body: {
|
||||
...user,
|
||||
},
|
||||
});
|
||||
expect(res.user.email).toBe("yadunand@yadunut.com");
|
||||
const foundUser = await db.query.user.findFirst();
|
||||
expect(foundUser).not.toBeNull();
|
||||
expect(foundUser?.email).toBe(user.email);
|
||||
});
|
||||
|
||||
it("logs in user and stores auth headers", async () => {
|
||||
const { headers: signInHeaders, response: signInRes } =
|
||||
await auth.api.signInEmail({
|
||||
body: {
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
},
|
||||
returnHeaders: true,
|
||||
});
|
||||
expect(signInRes.token).not.toBeNull();
|
||||
expect(signInRes.user.name).toBe(user.name);
|
||||
|
||||
// Store the auth headers for subsequent tests
|
||||
authHeaders = buildHeaders(signInHeaders);
|
||||
|
||||
// Verify session works with stored headers
|
||||
const res = await auth.api.getSession({ headers: authHeaders });
|
||||
expect(res?.user.username).toBe(user.username);
|
||||
});
|
||||
|
||||
it("creates auth token using stored headers", async () => {
|
||||
const data = await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: {},
|
||||
});
|
||||
// Add expectations based on what createApiKey should return
|
||||
expect(data).toBeDefined();
|
||||
});
|
||||
|
||||
it("deletes user using stored headers", async () => {
|
||||
const deleteRes = await auth.api.deleteUser({
|
||||
headers: authHeaders,
|
||||
body: {
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
expect(deleteRes.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Hono } from "hono";
|
||||
import { logger } from "hono/logger";
|
||||
import { auth } from "./lib/auth";
|
||||
import { auth } from "@/lib/auth";
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
|
304
api/src/test/auth/apikey.test.ts
Normal file
304
api/src/test/auth/apikey.test.ts
Normal file
@ -0,0 +1,304 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from "bun:test";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { AuthTestHelper, buildHeaders } from "../utils";
|
||||
|
||||
describe("API Key Management", () => {
|
||||
const user = {
|
||||
email: "apikey-test@example.com",
|
||||
password: "password123",
|
||||
name: "API Key Test User",
|
||||
username: "apikeyuser",
|
||||
};
|
||||
|
||||
let authHeaders: Headers;
|
||||
let userId: string;
|
||||
|
||||
let authHelper: AuthTestHelper;
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create user and sign in for each test
|
||||
authHelper = new AuthTestHelper();
|
||||
const authUser = await authHelper.createAuthenticatedUser();
|
||||
authHeaders = authUser.authHeaders;
|
||||
userId = authUser.userId;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Clean up: delete user and associated data
|
||||
authHelper.cleanupUser(authHeaders, user.password);
|
||||
});
|
||||
|
||||
describe("API Key Creation", () => {
|
||||
it("creates an API key successfully", async () => {
|
||||
const res = await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: {
|
||||
name: "Test API Key",
|
||||
},
|
||||
});
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res.id).toBeDefined();
|
||||
expect(res.name).toBe("Test API Key");
|
||||
expect(res.key).toBeDefined();
|
||||
expect(res.userId).toBe(userId);
|
||||
expect(res.enabled).toBe(true);
|
||||
});
|
||||
|
||||
it("creates an API key with custom name", async () => {
|
||||
const res = await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: {
|
||||
name: "Custom API Key",
|
||||
},
|
||||
});
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res.name).toBe("Custom API Key");
|
||||
expect(res.key).toBeDefined();
|
||||
expect(res.userId).toBe(userId);
|
||||
});
|
||||
|
||||
it("rejects API key creation without authentication", async () => {
|
||||
try {
|
||||
await auth.api.createApiKey({
|
||||
headers: new Headers(),
|
||||
body: {
|
||||
name: "Unauthorized Key",
|
||||
},
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("API Key Listing", () => {
|
||||
it("lists user's API keys", async () => {
|
||||
// Create multiple API keys
|
||||
await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: { name: "Key 1" },
|
||||
});
|
||||
await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: { name: "Key 2" },
|
||||
});
|
||||
|
||||
const res = await auth.api.listApiKeys({
|
||||
headers: authHeaders,
|
||||
});
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(Array.isArray(res)).toBe(true);
|
||||
expect(res.length).toBe(2);
|
||||
expect(res.some((key) => key.name === "Key 1")).toBe(true);
|
||||
expect(res.some((key) => key.name === "Key 2")).toBe(true);
|
||||
});
|
||||
|
||||
it("returns empty list for user with no API keys", async () => {
|
||||
const res = await auth.api.listApiKeys({
|
||||
headers: authHeaders,
|
||||
});
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(Array.isArray(res)).toBe(true);
|
||||
expect(res.length).toBe(0);
|
||||
});
|
||||
|
||||
it("rejects listing without authentication", async () => {
|
||||
try {
|
||||
await auth.api.listApiKeys({
|
||||
headers: new Headers(),
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("API Key Deletion", () => {
|
||||
let apiKeyId: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
const res = await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: { name: "Key to Revoke" },
|
||||
});
|
||||
apiKeyId = res.id;
|
||||
});
|
||||
|
||||
it("deletes an API key successfully", async () => {
|
||||
const res = await auth.api.deleteApiKey({
|
||||
headers: authHeaders,
|
||||
body: { keyId: apiKeyId },
|
||||
});
|
||||
|
||||
expect(res.success).toBe(true);
|
||||
|
||||
// Verify the key is no longer in the list
|
||||
const keys = await auth.api.listApiKeys({
|
||||
headers: authHeaders,
|
||||
});
|
||||
expect(keys.find((key) => key.id === apiKeyId)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("rejects deleting non-existent API key", async () => {
|
||||
try {
|
||||
await auth.api.deleteApiKey({
|
||||
headers: authHeaders,
|
||||
body: { keyId: "non-existent-key-id" },
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects deleting API key without authentication", async () => {
|
||||
try {
|
||||
await auth.api.deleteApiKey({
|
||||
headers: new Headers(),
|
||||
body: { keyId: apiKeyId },
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects deleting another user's API key", async () => {
|
||||
// Create another user
|
||||
const otherUser = {
|
||||
email: "other-user@example.com",
|
||||
password: "password123",
|
||||
name: "Other User",
|
||||
username: "otheruser",
|
||||
};
|
||||
|
||||
await auth.api.signUpEmail({
|
||||
body: otherUser,
|
||||
});
|
||||
|
||||
const { headers: otherHeaders } = await auth.api.signInEmail({
|
||||
body: {
|
||||
email: otherUser.email,
|
||||
password: otherUser.password,
|
||||
},
|
||||
returnHeaders: true,
|
||||
});
|
||||
|
||||
try {
|
||||
await auth.api.deleteApiKey({
|
||||
headers: buildHeaders(otherHeaders),
|
||||
body: { keyId: apiKeyId },
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
|
||||
// Clean up other user
|
||||
await auth.api.deleteUser({
|
||||
headers: buildHeaders(otherHeaders),
|
||||
body: { password: otherUser.password },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("API Key Verification", () => {
|
||||
let apiKey: string;
|
||||
let apiKeyId: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
const res = await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: { name: "Test Auth Key" },
|
||||
});
|
||||
apiKey = res.key;
|
||||
apiKeyId = res.id;
|
||||
});
|
||||
|
||||
it("verifies valid API key", async () => {
|
||||
const res = await auth.api.verifyApiKey({
|
||||
body: { key: apiKey },
|
||||
});
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res.valid).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects invalid API key", async () => {
|
||||
const res = await auth.api.verifyApiKey({
|
||||
body: { key: "invalid-key" },
|
||||
});
|
||||
|
||||
expect(res.valid).toBe(false);
|
||||
});
|
||||
|
||||
it("gets API key details", async () => {
|
||||
const res = await auth.api.getApiKey({
|
||||
headers: authHeaders,
|
||||
query: { id: apiKeyId },
|
||||
});
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res.id).toBe(apiKeyId);
|
||||
expect(res.name).toBe("Test Auth Key");
|
||||
expect(res.userId).toBe(userId);
|
||||
});
|
||||
|
||||
it("updates API key", async () => {
|
||||
const res = await auth.api.updateApiKey({
|
||||
headers: authHeaders,
|
||||
body: {
|
||||
keyId: apiKeyId,
|
||||
name: "Updated API Key Name",
|
||||
},
|
||||
});
|
||||
|
||||
expect(res).toBeDefined();
|
||||
expect(res.name).toBe("Updated API Key Name");
|
||||
});
|
||||
});
|
||||
|
||||
describe("API Key Management", () => {
|
||||
it("manages multiple API keys correctly", async () => {
|
||||
// Create multiple keys
|
||||
const key1 = await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: { name: "Key 1" },
|
||||
});
|
||||
|
||||
const key2 = await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: { name: "Key 2" },
|
||||
});
|
||||
|
||||
// List keys
|
||||
const keys = await auth.api.listApiKeys({
|
||||
headers: authHeaders,
|
||||
});
|
||||
|
||||
expect(keys.length).toBeGreaterThanOrEqual(2);
|
||||
expect(keys.find((k) => k.id === key1.id)).toBeDefined();
|
||||
expect(keys.find((k) => k.id === key2.id)).toBeDefined();
|
||||
|
||||
// Delete one key
|
||||
await auth.api.deleteApiKey({
|
||||
headers: authHeaders,
|
||||
body: { keyId: key1.id },
|
||||
});
|
||||
|
||||
// Verify it's removed
|
||||
const updatedKeys = await auth.api.listApiKeys({
|
||||
headers: authHeaders,
|
||||
});
|
||||
|
||||
expect(updatedKeys.find((k) => k.id === key1.id)).toBeUndefined();
|
||||
expect(updatedKeys.find((k) => k.id === key2.id)).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
121
api/src/test/auth/integration.test.ts
Normal file
121
api/src/test/auth/integration.test.ts
Normal file
@ -0,0 +1,121 @@
|
||||
import { beforeEach, describe, expect, it } from "bun:test";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { AuthTestHelper } from "../utils";
|
||||
|
||||
describe("Authentication Integration Flow", () => {
|
||||
let authHelper: AuthTestHelper;
|
||||
|
||||
beforeEach(() => {
|
||||
authHelper = new AuthTestHelper();
|
||||
});
|
||||
|
||||
it("completes full auth flow: signup -> signin -> create API key -> use API key -> cleanup", async () => {
|
||||
// 1. Create and authenticate user
|
||||
const { user, userId, authHeaders } =
|
||||
await authHelper.createAuthenticatedUser({
|
||||
email: `integration-${Date.now()}@example.com`,
|
||||
name: "Integration Test User",
|
||||
username: `integrationuser${Date.now()}`,
|
||||
});
|
||||
|
||||
// 2. Create API key using session auth
|
||||
const apiKeyRes = await authHelper.createApiKey(authHeaders, {
|
||||
name: "Integration Test Key",
|
||||
});
|
||||
|
||||
expect(apiKeyRes.id).toBeDefined();
|
||||
expect(apiKeyRes.key).toBeDefined();
|
||||
expect(apiKeyRes.userId).toBe(userId);
|
||||
expect(apiKeyRes.name).toBe("Integration Test Key");
|
||||
|
||||
// 3. Verify API key with verification endpoint
|
||||
const verifyRes = await auth.api.verifyApiKey({
|
||||
body: { key: apiKeyRes.key },
|
||||
});
|
||||
|
||||
expect(verifyRes.valid).toBe(true);
|
||||
|
||||
// 4. List API keys to verify it appears
|
||||
const keysRes = await auth.api.listApiKeys({
|
||||
headers: authHeaders,
|
||||
});
|
||||
|
||||
expect(keysRes).toBeDefined();
|
||||
expect(Array.isArray(keysRes)).toBe(true);
|
||||
expect(keysRes.length).toBe(1);
|
||||
expect(keysRes?.[0]?.id).toBe(apiKeyRes.id);
|
||||
|
||||
// 5. Delete API key
|
||||
const deleteRes = await auth.api.deleteApiKey({
|
||||
headers: authHeaders,
|
||||
body: { keyId: apiKeyRes.id },
|
||||
});
|
||||
|
||||
expect(deleteRes.success).toBe(true);
|
||||
|
||||
// 6. Verify API key no longer works
|
||||
const invalidVerifyRes = await auth.api.verifyApiKey({
|
||||
body: { key: apiKeyRes.key },
|
||||
});
|
||||
|
||||
expect(invalidVerifyRes.valid).toBe(false);
|
||||
|
||||
// 7. Cleanup user
|
||||
await authHelper.cleanupUser(authHeaders, user.password);
|
||||
});
|
||||
|
||||
it("handles multiple concurrent API keys per user", async () => {
|
||||
const { user, authHeaders } = await authHelper.createAuthenticatedUser();
|
||||
|
||||
// Create multiple API keys
|
||||
const [key1, key2, key3] = await Promise.all([
|
||||
authHelper.createApiKey(authHeaders, { name: "Key 1" }),
|
||||
authHelper.createApiKey(authHeaders, { name: "Key 2" }),
|
||||
authHelper.createApiKey(authHeaders, { name: "Key 3" }),
|
||||
]);
|
||||
|
||||
// Verify all keys work
|
||||
const [verify1, verify2, verify3] = await Promise.all([
|
||||
auth.api.verifyApiKey({ body: { key: key1.key } }),
|
||||
auth.api.verifyApiKey({ body: { key: key2.key } }),
|
||||
auth.api.verifyApiKey({ body: { key: key3.key } }),
|
||||
]);
|
||||
|
||||
expect(verify1.valid).toBe(true);
|
||||
expect(verify2.valid).toBe(true);
|
||||
expect(verify3.valid).toBe(true);
|
||||
|
||||
// List all keys
|
||||
const allKeys = await auth.api.listApiKeys({ headers: authHeaders });
|
||||
expect(allKeys.length).toBe(3);
|
||||
|
||||
// Delete one key
|
||||
await auth.api.deleteApiKey({
|
||||
headers: authHeaders,
|
||||
body: { keyId: key2.id },
|
||||
});
|
||||
|
||||
// Verify only 2 keys remain
|
||||
const remainingKeys = await auth.api.listApiKeys({ headers: authHeaders });
|
||||
expect(remainingKeys.length).toBe(2);
|
||||
expect(remainingKeys.find((k) => k.id === key2.id)).toBeUndefined();
|
||||
|
||||
// Verify deleted key doesn't work
|
||||
const deletedVerify = await auth.api.verifyApiKey({
|
||||
body: { key: key2.key },
|
||||
});
|
||||
expect(deletedVerify.valid).toBe(false);
|
||||
|
||||
// Verify other keys still work
|
||||
const [stillWorking1, stillWorking3] = await Promise.all([
|
||||
auth.api.verifyApiKey({ body: { key: key1.key } }),
|
||||
auth.api.verifyApiKey({ body: { key: key3.key } }),
|
||||
]);
|
||||
|
||||
expect(stillWorking1.valid).toBe(true);
|
||||
expect(stillWorking3.valid).toBe(true);
|
||||
|
||||
// Cleanup
|
||||
await authHelper.cleanupUser(authHeaders, user.password);
|
||||
});
|
||||
});
|
125
api/src/test/auth/user.test.ts
Normal file
125
api/src/test/auth/user.test.ts
Normal file
@ -0,0 +1,125 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { db } from "@/db";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { buildHeaders } from "../utils";
|
||||
|
||||
describe("User Authentication", () => {
|
||||
const user = {
|
||||
email: "test-user@example.com",
|
||||
password: "password123",
|
||||
name: "Test User",
|
||||
username: "testuser",
|
||||
};
|
||||
|
||||
let authHeaders: Headers;
|
||||
|
||||
describe("User Registration", () => {
|
||||
it("creates a new user successfully", async () => {
|
||||
const res = await auth.api.signUpEmail({
|
||||
body: {
|
||||
...user,
|
||||
},
|
||||
});
|
||||
expect(res.user.email).toBe(user.email);
|
||||
expect(res.user.name).toBe(user.name);
|
||||
// Note: Username field may not be returned in the response even if set
|
||||
|
||||
const foundUser = await db.query.user.findFirst({
|
||||
where: (users, { eq }) => eq(users.email, user.email),
|
||||
});
|
||||
expect(foundUser).not.toBeNull();
|
||||
expect(foundUser?.email).toBe(user.email);
|
||||
});
|
||||
|
||||
it("prevents duplicate user registration", async () => {
|
||||
try {
|
||||
await auth.api.signUpEmail({
|
||||
body: {
|
||||
...user,
|
||||
},
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("User Login", () => {
|
||||
it("logs in user with correct credentials", async () => {
|
||||
const { headers: signInHeaders, response: signInRes } =
|
||||
await auth.api.signInEmail({
|
||||
body: {
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
},
|
||||
returnHeaders: true,
|
||||
});
|
||||
|
||||
expect(signInRes.token).not.toBeNull();
|
||||
expect(signInRes.user.name).toBe(user.name);
|
||||
expect(signInRes.user.email).toBe(user.email);
|
||||
|
||||
authHeaders = buildHeaders(signInHeaders);
|
||||
});
|
||||
|
||||
it("rejects login with incorrect password", async () => {
|
||||
try {
|
||||
await auth.api.signInEmail({
|
||||
body: {
|
||||
email: user.email,
|
||||
password: "wrongpassword",
|
||||
},
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
it("rejects login with non-existent email", async () => {
|
||||
try {
|
||||
await auth.api.signInEmail({
|
||||
body: {
|
||||
email: "nonexistent@example.com",
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
expect(true).toBe(false); // Should not reach here
|
||||
} catch (error) {
|
||||
expect(error).toBeDefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Session Management", () => {
|
||||
it("retrieves valid session with auth headers", async () => {
|
||||
const res = await auth.api.getSession({ headers: authHeaders });
|
||||
expect(res?.user.username).toBe(user.username);
|
||||
expect(res?.user.email).toBe(user.email);
|
||||
});
|
||||
|
||||
it("returns null for session without auth headers", async () => {
|
||||
const res = await auth.api.getSession({ headers: new Headers() });
|
||||
expect(res?.user).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("User Deletion", () => {
|
||||
it("deletes user with correct password", async () => {
|
||||
const deleteRes = await auth.api.deleteUser({
|
||||
headers: authHeaders,
|
||||
body: {
|
||||
password: user.password,
|
||||
},
|
||||
});
|
||||
expect(deleteRes.success).toBe(true);
|
||||
|
||||
// Verify user is actually deleted
|
||||
const foundUser = await db.query.user.findFirst({
|
||||
where: (users, { eq }) => eq(users.email, user.email),
|
||||
});
|
||||
expect(foundUser).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
17
api/src/test/setup.ts
Normal file
17
api/src/test/setup.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { afterAll, beforeAll } from "bun:test";
|
||||
import { migrate } from "drizzle-orm/bun-sql/migrator";
|
||||
import { db } from "@/db";
|
||||
|
||||
beforeAll(async () => {
|
||||
await migrate(db, { migrationsFolder: "./drizzle" });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// Clear all test data from database - note: order matters due to foreign keys
|
||||
const { session, apikey, account, user } = await import("@/db/schema/auth");
|
||||
|
||||
await db.delete(session).execute();
|
||||
await db.delete(apikey).execute();
|
||||
await db.delete(account).execute();
|
||||
await db.delete(user).execute();
|
||||
});
|
@ -1,3 +1,6 @@
|
||||
import { db } from "@/db";
|
||||
import { auth } from "@/lib/auth";
|
||||
|
||||
export function buildHeaders(signInHeaders: Headers) {
|
||||
const headers = new Headers();
|
||||
for (const cookie of signInHeaders.getSetCookie() ?? []) {
|
||||
@ -5,3 +8,94 @@ export function buildHeaders(signInHeaders: Headers) {
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
export interface TestUser {
|
||||
email: string;
|
||||
password: string;
|
||||
name: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export class AuthTestHelper {
|
||||
createTestUser(userOverrides: Partial<TestUser> = {}): TestUser {
|
||||
const defaultUser: TestUser = {
|
||||
email: `test-${Date.now()}@example.com`,
|
||||
password: "password123",
|
||||
name: "Test User",
|
||||
username: `testuser${Date.now()}`,
|
||||
};
|
||||
|
||||
return { ...defaultUser, ...userOverrides };
|
||||
}
|
||||
|
||||
async signUpUser(user: TestUser) {
|
||||
return await auth.api.signUpEmail({
|
||||
body: user,
|
||||
});
|
||||
}
|
||||
|
||||
async signInUser(user: Pick<TestUser, "email" | "password">) {
|
||||
return await auth.api.signInEmail({
|
||||
body: {
|
||||
email: user.email,
|
||||
password: user.password,
|
||||
},
|
||||
returnHeaders: true,
|
||||
});
|
||||
}
|
||||
|
||||
async createAuthenticatedUser(userOverrides: Partial<TestUser> = {}) {
|
||||
const user = this.createTestUser(userOverrides);
|
||||
const signUpRes = await this.signUpUser(user);
|
||||
const { headers: signInHeaders } = await this.signInUser(user);
|
||||
const authHeaders = buildHeaders(signInHeaders);
|
||||
|
||||
return {
|
||||
user,
|
||||
userId: signUpRes.user.id,
|
||||
authHeaders,
|
||||
};
|
||||
}
|
||||
|
||||
async cleanupUser(authHeaders: Headers, password: string) {
|
||||
try {
|
||||
await auth.api.deleteUser({
|
||||
headers: authHeaders,
|
||||
body: { password },
|
||||
});
|
||||
} catch (_) {
|
||||
// User might already be deleted, ignore error
|
||||
}
|
||||
}
|
||||
|
||||
async createApiKey(
|
||||
authHeaders: Headers,
|
||||
keyOptions: Partial<
|
||||
Parameters<typeof auth.api.createApiKey>["0"]["body"]
|
||||
> = {},
|
||||
) {
|
||||
return await auth.api.createApiKey({
|
||||
headers: authHeaders,
|
||||
body: {
|
||||
name: `Test API Key ${Date.now()}`,
|
||||
...keyOptions,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
createApiKeyHeaders(apiKey: string) {
|
||||
const headers = new Headers();
|
||||
headers.set("Authorization", `Bearer ${apiKey}`);
|
||||
return headers;
|
||||
}
|
||||
|
||||
async clearDatabase() {
|
||||
// Clear all test data from database - note: order matters due to foreign keys
|
||||
const { session, apikey, account, user } = await import("@/db/schema/auth");
|
||||
|
||||
await db.delete(session).execute();
|
||||
await db.delete(apikey).execute();
|
||||
await db.delete(account).execute();
|
||||
await db.delete(user).execute();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user