// Tests for user.ts // These are pure unit tests - no database needed import assert from "node:assert/strict"; import { describe, it } from "node:test"; import { AnonymousUser, AuthenticatedUser, anonymousUser, type Permission, type Role, } from "./user"; describe("User", () => { describe("AuthenticatedUser.create", () => { it("creates a user with default values", () => { const user = AuthenticatedUser.create("test@example.com"); assert.equal(user.email, "test@example.com"); assert.equal(user.status, "active"); assert.equal(user.isAnonymous(), false); assert.deepEqual([...user.roles], []); assert.deepEqual([...user.permissions], []); }); it("creates a user with custom values", () => { const user = AuthenticatedUser.create("test@example.com", { id: "custom-id", displayName: "Test User", status: "pending", roles: ["admin"], permissions: ["posts:create"], }); assert.equal(user.id, "custom-id"); assert.equal(user.displayName, "Test User"); assert.equal(user.status, "pending"); assert.deepEqual([...user.roles], ["admin"]); assert.deepEqual([...user.permissions], ["posts:create"]); }); }); describe("status checks", () => { it("isActive returns true for active users", () => { const user = AuthenticatedUser.create("test@example.com", { status: "active", }); assert.equal(user.isActive(), true); }); it("isActive returns false for suspended users", () => { const user = AuthenticatedUser.create("test@example.com", { status: "suspended", }); assert.equal(user.isActive(), false); }); it("isActive returns false for pending users", () => { const user = AuthenticatedUser.create("test@example.com", { status: "pending", }); assert.equal(user.isActive(), false); }); }); describe("role checks", () => { it("hasRole returns true when user has the role", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["admin", "editor"], }); assert.equal(user.hasRole("admin"), true); assert.equal(user.hasRole("editor"), true); }); it("hasRole returns false when user does not have the role", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["user"], }); assert.equal(user.hasRole("admin"), false); }); it("hasAnyRole returns true when user has at least one role", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["editor"], }); assert.equal(user.hasAnyRole(["admin", "editor"]), true); }); it("hasAnyRole returns false when user has none of the roles", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["user"], }); assert.equal(user.hasAnyRole(["admin", "editor"]), false); }); it("hasAllRoles returns true when user has all roles", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["admin", "editor", "user"], }); assert.equal(user.hasAllRoles(["admin", "editor"]), true); }); it("hasAllRoles returns false when user is missing a role", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["admin"], }); assert.equal(user.hasAllRoles(["admin", "editor"]), false); }); }); describe("permission checks", () => { it("hasPermission returns true for direct permissions", () => { const user = AuthenticatedUser.create("test@example.com", { permissions: ["posts:create" as Permission], }); assert.equal( user.hasPermission("posts:create" as Permission), true, ); }); it("hasPermission returns true for role-derived permissions", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["admin" as Role], }); // admin role has users:read, users:create, users:update, users:delete assert.equal(user.hasPermission("users:read" as Permission), true); assert.equal( user.hasPermission("users:delete" as Permission), true, ); }); it("hasPermission returns false when permission not granted", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["user" as Role], }); // user role only has users:read assert.equal( user.hasPermission("users:delete" as Permission), false, ); }); it("can() is a convenience method for hasPermission", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["admin" as Role], }); assert.equal(user.can("read", "users"), true); assert.equal(user.can("delete", "users"), true); assert.equal(user.can("create", "posts"), false); }); }); describe("effectivePermissions", () => { it("returns combined direct and role-derived permissions", () => { const user = AuthenticatedUser.create("test@example.com", { roles: ["user" as Role], permissions: ["posts:create" as Permission], }); const perms = user.effectivePermissions(); assert.equal(perms.has("posts:create" as Permission), true); assert.equal(perms.has("users:read" as Permission), true); // from user role }); it("returns empty set for user with no roles or permissions", () => { const user = AuthenticatedUser.create("test@example.com"); const perms = user.effectivePermissions(); assert.equal(perms.size, 0); }); }); describe("serialization", () => { it("toJSON returns plain object", () => { const user = AuthenticatedUser.create("test@example.com", { id: "test-id", displayName: "Test", status: "active", roles: ["admin"], permissions: ["posts:create"], }); const json = user.toJSON(); assert.equal(json.id, "test-id"); assert.equal(json.email, "test@example.com"); assert.equal(json.displayName, "Test"); assert.equal(json.status, "active"); assert.deepEqual(json.roles, ["admin"]); assert.deepEqual(json.permissions, ["posts:create"]); }); it("toString returns readable string", () => { const user = AuthenticatedUser.create("test@example.com", { id: "test-id", }); assert.equal(user.toString(), "User(id test-id)"); }); }); describe("AnonymousUser", () => { it("isAnonymous returns true", () => { const user = AnonymousUser.create("anon@example.com"); assert.equal(user.isAnonymous(), true); }); it("anonymousUser singleton is anonymous", () => { assert.equal(anonymousUser.isAnonymous(), true); assert.equal(anonymousUser.id, "-1"); assert.equal(anonymousUser.email, "anonymous@example.com"); }); }); });