From 811458427593a4172a2cd535cc768db375350dca Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 6 Dec 2025 17:05:21 +0900 Subject: feat(dev): change architecture and directory structure --- pkgs/server/src/routes/auth.test.ts | 428 ------------------------------------ 1 file changed, 428 deletions(-) delete mode 100644 pkgs/server/src/routes/auth.test.ts (limited to 'pkgs/server/src/routes/auth.test.ts') diff --git a/pkgs/server/src/routes/auth.test.ts b/pkgs/server/src/routes/auth.test.ts deleted file mode 100644 index 34eb2b6..0000000 --- a/pkgs/server/src/routes/auth.test.ts +++ /dev/null @@ -1,428 +0,0 @@ -import { Hono } from "hono"; -import { beforeEach, describe, expect, it, vi } from "vitest"; -import { errorHandler } from "../middleware"; -import type { - RefreshTokenRepository, - UserPublic, - UserRepository, -} from "../repositories"; -import { createAuthRouter } from "./auth"; - -vi.mock("argon2", () => ({ - hash: vi.fn((password: string) => Promise.resolve(`hashed_${password}`)), - verify: vi.fn((hash: string, password: string) => - Promise.resolve(hash === `hashed_${password}`), - ), -})); - -function createMockUserRepo(): UserRepository { - return { - findByUsername: vi.fn(), - existsByUsername: vi.fn(), - create: vi.fn(), - findById: vi.fn(), - }; -} - -function createMockRefreshTokenRepo(): RefreshTokenRepository { - return { - findValidToken: vi.fn(), - create: vi.fn(), - deleteById: vi.fn(), - }; -} - -interface RegisterResponse { - user?: { - id: string; - username: string; - createdAt: string; - }; - error?: { - code: string; - message: string; - }; -} - -interface LoginResponse { - accessToken?: string; - refreshToken?: string; - user?: { - id: string; - username: string; - }; - error?: { - code: string; - message: string; - }; -} - -describe("POST /register", () => { - let app: Hono; - let mockUserRepo: ReturnType; - let mockRefreshTokenRepo: ReturnType; - - beforeEach(() => { - vi.clearAllMocks(); - mockUserRepo = createMockUserRepo(); - mockRefreshTokenRepo = createMockRefreshTokenRepo(); - const auth = createAuthRouter({ - userRepo: mockUserRepo, - refreshTokenRepo: mockRefreshTokenRepo, - }); - app = new Hono(); - app.onError(errorHandler); - app.route("/api/auth", auth); - }); - - it("creates a new user with valid credentials", async () => { - vi.mocked(mockUserRepo.existsByUsername).mockResolvedValue(false); - vi.mocked(mockUserRepo.create).mockResolvedValue({ - id: "test-uuid-123", - username: "testuser", - createdAt: new Date("2024-01-01T00:00:00Z"), - } as UserPublic); - - const res = await app.request("/api/auth/register", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "testuser", - password: "securepassword12345", - }), - }); - - expect(res.status).toBe(201); - const body = (await res.json()) as RegisterResponse; - expect(body.user).toEqual({ - id: "test-uuid-123", - username: "testuser", - createdAt: "2024-01-01T00:00:00.000Z", - }); - expect(mockUserRepo.existsByUsername).toHaveBeenCalledWith("testuser"); - expect(mockUserRepo.create).toHaveBeenCalledWith({ - username: "testuser", - passwordHash: "hashed_securepassword12345", - }); - }); - - it("returns 422 for invalid username", async () => { - const res = await app.request("/api/auth/register", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "", - password: "securepassword12345", - }), - }); - - expect(res.status).toBe(422); - const body = (await res.json()) as RegisterResponse; - expect(body.error?.code).toBe("VALIDATION_ERROR"); - }); - - it("returns 422 for password too short", async () => { - const res = await app.request("/api/auth/register", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "testuser", - password: "tooshort123456", - }), - }); - - expect(res.status).toBe(422); - const body = (await res.json()) as RegisterResponse; - expect(body.error?.code).toBe("VALIDATION_ERROR"); - }); - - it("returns 409 for existing username", async () => { - vi.mocked(mockUserRepo.existsByUsername).mockResolvedValue(true); - - const res = await app.request("/api/auth/register", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "existinguser", - password: "securepassword12345", - }), - }); - - expect(res.status).toBe(409); - const body = (await res.json()) as RegisterResponse; - expect(body.error?.code).toBe("USERNAME_EXISTS"); - }); -}); - -describe("POST /login", () => { - let app: Hono; - let mockUserRepo: ReturnType; - let mockRefreshTokenRepo: ReturnType; - - beforeEach(() => { - vi.clearAllMocks(); - mockUserRepo = createMockUserRepo(); - mockRefreshTokenRepo = createMockRefreshTokenRepo(); - const auth = createAuthRouter({ - userRepo: mockUserRepo, - refreshTokenRepo: mockRefreshTokenRepo, - }); - app = new Hono(); - app.onError(errorHandler); - app.route("/api/auth", auth); - }); - - it("returns access token for valid credentials", async () => { - vi.mocked(mockUserRepo.findByUsername).mockResolvedValue({ - id: "user-uuid-123", - username: "testuser", - passwordHash: "hashed_correctpassword", - }); - vi.mocked(mockRefreshTokenRepo.create).mockResolvedValue(undefined); - - const res = await app.request("/api/auth/login", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "testuser", - password: "correctpassword", - }), - }); - - expect(res.status).toBe(200); - const body = (await res.json()) as LoginResponse; - expect(body.accessToken).toBeDefined(); - expect(typeof body.accessToken).toBe("string"); - expect(body.refreshToken).toBeDefined(); - expect(typeof body.refreshToken).toBe("string"); - expect(body.user).toEqual({ - id: "user-uuid-123", - username: "testuser", - }); - expect(mockRefreshTokenRepo.create).toHaveBeenCalledWith({ - userId: "user-uuid-123", - tokenHash: expect.any(String), - expiresAt: expect.any(Date), - }); - }); - - it("returns 401 for non-existent user", async () => { - vi.mocked(mockUserRepo.findByUsername).mockResolvedValue(undefined); - - const res = await app.request("/api/auth/login", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "nonexistent", - password: "anypassword", - }), - }); - - expect(res.status).toBe(401); - const body = (await res.json()) as LoginResponse; - expect(body.error?.code).toBe("INVALID_CREDENTIALS"); - }); - - it("returns 401 for incorrect password", async () => { - vi.mocked(mockUserRepo.findByUsername).mockResolvedValue({ - id: "user-uuid-123", - username: "testuser", - passwordHash: "hashed_correctpassword", - }); - - const res = await app.request("/api/auth/login", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "testuser", - password: "wrongpassword", - }), - }); - - expect(res.status).toBe(401); - const body = (await res.json()) as LoginResponse; - expect(body.error?.code).toBe("INVALID_CREDENTIALS"); - }); - - it("returns 422 for missing username", async () => { - const res = await app.request("/api/auth/login", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "", - password: "somepassword", - }), - }); - - expect(res.status).toBe(422); - const body = (await res.json()) as LoginResponse; - expect(body.error?.code).toBe("VALIDATION_ERROR"); - }); - - it("returns 422 for missing password", async () => { - const res = await app.request("/api/auth/login", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - username: "testuser", - password: "", - }), - }); - - expect(res.status).toBe(422); - const body = (await res.json()) as LoginResponse; - expect(body.error?.code).toBe("VALIDATION_ERROR"); - }); -}); - -interface RefreshResponse { - accessToken?: string; - refreshToken?: string; - user?: { - id: string; - username: string; - }; - error?: { - code: string; - message: string; - }; -} - -describe("POST /refresh", () => { - let app: Hono; - let mockUserRepo: ReturnType; - let mockRefreshTokenRepo: ReturnType; - - beforeEach(() => { - vi.clearAllMocks(); - mockUserRepo = createMockUserRepo(); - mockRefreshTokenRepo = createMockRefreshTokenRepo(); - const auth = createAuthRouter({ - userRepo: mockUserRepo, - refreshTokenRepo: mockRefreshTokenRepo, - }); - app = new Hono(); - app.onError(errorHandler); - app.route("/api/auth", auth); - }); - - it("returns new tokens for valid refresh token", async () => { - vi.mocked(mockRefreshTokenRepo.findValidToken).mockResolvedValue({ - id: "token-id-123", - userId: "user-uuid-123", - expiresAt: new Date(Date.now() + 86400000), - }); - vi.mocked(mockUserRepo.findById).mockResolvedValue({ - id: "user-uuid-123", - username: "testuser", - }); - vi.mocked(mockRefreshTokenRepo.deleteById).mockResolvedValue(undefined); - vi.mocked(mockRefreshTokenRepo.create).mockResolvedValue(undefined); - - const res = await app.request("/api/auth/refresh", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - refreshToken: "valid-refresh-token-hex", - }), - }); - - expect(res.status).toBe(200); - const body = (await res.json()) as RefreshResponse; - expect(body.accessToken).toBeDefined(); - expect(typeof body.accessToken).toBe("string"); - expect(body.refreshToken).toBeDefined(); - expect(typeof body.refreshToken).toBe("string"); - expect(body.user).toEqual({ - id: "user-uuid-123", - username: "testuser", - }); - expect(mockRefreshTokenRepo.deleteById).toHaveBeenCalledWith( - "token-id-123", - ); - expect(mockRefreshTokenRepo.create).toHaveBeenCalledWith({ - userId: "user-uuid-123", - tokenHash: expect.any(String), - expiresAt: expect.any(Date), - }); - }); - - it("returns 401 for invalid refresh token", async () => { - vi.mocked(mockRefreshTokenRepo.findValidToken).mockResolvedValue(undefined); - - const res = await app.request("/api/auth/refresh", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - refreshToken: "invalid-refresh-token", - }), - }); - - expect(res.status).toBe(401); - const body = (await res.json()) as RefreshResponse; - expect(body.error?.code).toBe("INVALID_REFRESH_TOKEN"); - }); - - it("returns 401 for expired refresh token", async () => { - vi.mocked(mockRefreshTokenRepo.findValidToken).mockResolvedValue(undefined); - - const res = await app.request("/api/auth/refresh", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - refreshToken: "expired-refresh-token", - }), - }); - - expect(res.status).toBe(401); - const body = (await res.json()) as RefreshResponse; - expect(body.error?.code).toBe("INVALID_REFRESH_TOKEN"); - }); - - it("returns 401 when user not found", async () => { - vi.mocked(mockRefreshTokenRepo.findValidToken).mockResolvedValue({ - id: "token-id-123", - userId: "deleted-user-id", - expiresAt: new Date(Date.now() + 86400000), - }); - vi.mocked(mockUserRepo.findById).mockResolvedValue(undefined); - - const res = await app.request("/api/auth/refresh", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - refreshToken: "valid-refresh-token", - }), - }); - - expect(res.status).toBe(401); - const body = (await res.json()) as RefreshResponse; - expect(body.error?.code).toBe("USER_NOT_FOUND"); - }); - - it("returns 422 for missing refresh token", async () => { - const res = await app.request("/api/auth/refresh", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({}), - }); - - expect(res.status).toBe(422); - const body = (await res.json()) as RefreshResponse; - expect(body.error?.code).toBe("VALIDATION_ERROR"); - }); - - it("returns 422 for empty refresh token", async () => { - const res = await app.request("/api/auth/refresh", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - refreshToken: "", - }), - }); - - expect(res.status).toBe(422); - const body = (await res.json()) as RefreshResponse; - expect(body.error?.code).toBe("VALIDATION_ERROR"); - }); -}); -- cgit v1.2.3-70-g09d2