// Tests for auth/types.ts // Pure unit tests - no database needed import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { z } from "zod"; import { AuthenticatedUser, anonymousUser } from "../user"; import { authMethodParser, forgotPasswordInputParser, loginInputParser, registerInputParser, resetPasswordInputParser, Session, sessionDataParser, tokenLifetimes, tokenTypeParser, } from "./types"; describe("auth/types", () => { describe("tokenTypeParser", () => { it("accepts valid token types", () => { assert.equal(tokenTypeParser.parse("session"), "session"); assert.equal( tokenTypeParser.parse("password_reset"), "password_reset", ); assert.equal(tokenTypeParser.parse("email_verify"), "email_verify"); }); it("rejects invalid token types", () => { assert.throws(() => tokenTypeParser.parse("invalid")); }); }); describe("authMethodParser", () => { it("accepts valid auth methods", () => { assert.equal(authMethodParser.parse("cookie"), "cookie"); assert.equal(authMethodParser.parse("bearer"), "bearer"); }); it("rejects invalid auth methods", () => { assert.throws(() => authMethodParser.parse("basic")); }); }); describe("sessionDataParser", () => { it("accepts valid session data", () => { const data = { tokenId: "abc123", userId: "user-1", tokenType: "session", authMethod: "cookie", createdAt: new Date(), expiresAt: new Date(), }; const result = sessionDataParser.parse(data); assert.equal(result.tokenId, "abc123"); assert.equal(result.userId, "user-1"); }); it("coerces date strings to dates", () => { const data = { tokenId: "abc123", userId: "user-1", tokenType: "session", authMethod: "cookie", createdAt: "2025-01-01T00:00:00Z", expiresAt: "2025-01-02T00:00:00Z", }; const result = sessionDataParser.parse(data); assert.ok(result.createdAt instanceof Date); assert.ok(result.expiresAt instanceof Date); }); it("accepts optional fields", () => { const data = { tokenId: "abc123", userId: "user-1", tokenType: "session", authMethod: "cookie", createdAt: new Date(), expiresAt: new Date(), lastUsedAt: new Date(), userAgent: "Mozilla/5.0", ipAddress: "127.0.0.1", isUsed: true, }; const result = sessionDataParser.parse(data); assert.equal(result.userAgent, "Mozilla/5.0"); assert.equal(result.ipAddress, "127.0.0.1"); assert.equal(result.isUsed, true); }); }); describe("loginInputParser", () => { it("accepts valid login input", () => { const result = loginInputParser.parse({ email: "test@example.com", password: "secret", }); assert.equal(result.email, "test@example.com"); assert.equal(result.password, "secret"); }); it("rejects invalid email", () => { assert.throws(() => loginInputParser.parse({ email: "not-an-email", password: "secret", }), ); }); it("rejects empty password", () => { assert.throws(() => loginInputParser.parse({ email: "test@example.com", password: "", }), ); }); }); describe("registerInputParser", () => { it("accepts valid registration input", () => { const result = registerInputParser.parse({ email: "test@example.com", password: "password123", displayName: "Test User", }); assert.equal(result.email, "test@example.com"); assert.equal(result.password, "password123"); assert.equal(result.displayName, "Test User"); }); it("accepts registration without displayName", () => { const result = registerInputParser.parse({ email: "test@example.com", password: "password123", }); assert.equal(result.displayName, undefined); }); it("rejects password shorter than 8 characters", () => { assert.throws(() => registerInputParser.parse({ email: "test@example.com", password: "short", }), ); }); }); describe("forgotPasswordInputParser", () => { it("accepts valid email", () => { const result = forgotPasswordInputParser.parse({ email: "test@example.com", }); assert.equal(result.email, "test@example.com"); }); it("rejects invalid email", () => { assert.throws(() => forgotPasswordInputParser.parse({ email: "invalid", }), ); }); }); describe("resetPasswordInputParser", () => { it("accepts valid reset input", () => { const result = resetPasswordInputParser.parse({ token: "abc123", password: "newpassword", }); assert.equal(result.token, "abc123"); assert.equal(result.password, "newpassword"); }); it("rejects empty token", () => { assert.throws(() => resetPasswordInputParser.parse({ token: "", password: "newpassword", }), ); }); it("rejects password shorter than 8 characters", () => { assert.throws(() => resetPasswordInputParser.parse({ token: "abc123", password: "short", }), ); }); }); describe("tokenLifetimes", () => { it("defines session lifetime", () => { assert.ok(tokenLifetimes.session > 0); // 30 days in ms assert.equal(tokenLifetimes.session, 30 * 24 * 60 * 60 * 1000); }); it("defines password_reset lifetime", () => { assert.ok(tokenLifetimes.password_reset > 0); // 1 hour in ms assert.equal(tokenLifetimes.password_reset, 1 * 60 * 60 * 1000); }); it("defines email_verify lifetime", () => { assert.ok(tokenLifetimes.email_verify > 0); // 24 hours in ms assert.equal(tokenLifetimes.email_verify, 24 * 60 * 60 * 1000); }); }); describe("Session", () => { it("wraps authenticated session", () => { const user = AuthenticatedUser.create("test@example.com", { id: "user-1", }); const sessionData = { tokenId: "token-1", userId: "user-1", tokenType: "session" as const, authMethod: "cookie" as const, createdAt: new Date(), expiresAt: new Date(), }; const session = new Session(sessionData, user); assert.equal(session.isAuthenticated(), true); assert.equal(session.getUser(), user); assert.equal(session.getData(), sessionData); assert.equal(session.tokenId, "token-1"); assert.equal(session.userId, "user-1"); }); it("wraps anonymous session", () => { const session = new Session(null, anonymousUser); assert.equal(session.isAuthenticated(), false); assert.equal(session.getUser(), anonymousUser); assert.equal(session.getData(), null); assert.equal(session.tokenId, undefined); assert.equal(session.userId, undefined); }); }); });