// __tests__/unit/models/User.db.test.js const User = require("../../../src/models/User"); // Adjust path const { pool, clearAllTables } = require("../../setup/testDbUtils"); // Adjust path describe("User Model (PostgreSQL)", () => { beforeEach(async () => { await clearAllTables(); // Ensure clean state for each test }); describe("create", () => { it("should create a new user with hashed password and verification token", async () => { const userData = { email: "test@example.com", password: "Password123!", first_name: "Test", last_name: "User", }; const user = await User.create(userData); expect(user.id).toBeDefined(); expect(user.uuid).toBeDefined(); expect(user.email).toBe(userData.email); expect(user.password_hash).not.toBe(userData.password); // Should be hashed expect(user.verification_token).toBeDefined(); expect(user.is_verified).toBe(0); // Default for SQLite, ensure it's FALSE for PG const dbUser = await pool.query("SELECT * FROM users WHERE id = $1", [ user.id, ]); expect(dbUser.rows[0].email).toBe(userData.email); expect(dbUser.rows[0].password_hash).not.toBe(userData.password); }); it("should throw an error if email already exists", async () => { const userData = { email: "duplicate@example.com", password: "Password123!", }; await User.create(userData); await expect(User.create(userData)).rejects.toThrow( "Email already exists" ); }); }); describe("findByEmail", () => { it("should find an active user by email", async () => { const createdUser = await User.create({ email: "findme@example.com", password: "Password123!", }); const foundUser = await User.findByEmail("findme@example.com"); expect(foundUser).toBeDefined(); expect(foundUser.id).toBe(createdUser.id); }); it("should return null if user not found or inactive", async () => { expect(await User.findByEmail("dontexist@example.com")).toBeNull(); // Add test for inactive user if you implement that logic }); }); describe("findById", () => { it("should find an active user by ID", async () => { const createdUser = await User.create({ email: "findbyid@example.com", password: "Password123!", }); const foundUser = await User.findById(createdUser.id); expect(foundUser).toBeDefined(); expect(foundUser.email).toBe(createdUser.email); }); }); describe("verifyEmail", () => { it("should verify a user and nullify the token", async () => { const user = await User.create({ email: "verify@example.com", password: "Pass!", }); const verificationToken = user.verification_token; const verified = await User.verifyEmail(verificationToken); expect(verified).toBe(true); const dbUser = await User.findById(user.id); expect(dbUser.is_verified).toBe(1); // Or TRUE depending on PG boolean handling expect(dbUser.verification_token).toBeNull(); }); }); describe("setPasswordResetToken and findByPasswordResetToken", () => { it("should set and find a valid password reset token", async () => { const user = await User.create({ email: "reset@example.com", password: "password", }); const { token } = await User.setPasswordResetToken(user.email); expect(token).toBeDefined(); const foundUser = await User.findByPasswordResetToken(token); expect(foundUser).toBeDefined(); expect(foundUser.id).toBe(user.id); }); it("should not find an expired password reset token", async () => { const user = await User.create({ email: "resetexpired@example.com", password: "password", }); const { token } = await User.setPasswordResetToken(user.email); // Manually expire the token in DB for testing await pool.query( "UPDATE users SET password_reset_expires = NOW() - INTERVAL '2 hour' WHERE id = $1", [user.id] ); const foundUser = await User.findByPasswordResetToken(token); expect(foundUser).toBeNull(); }); }); // ... more tests for other User model methods (updatePassword, login attempts, etc.) ... // Example: updatePasswordAndClearChangeFlag describe("updatePasswordAndClearChangeFlag", () => { it("should update password and set must_change_password to false", async () => { const user = await User.create({ email: "changeme@example.com", password: "oldpassword", }); // Manually set must_change_password to true for test await pool.query( "UPDATE users SET must_change_password = TRUE WHERE id = $1", [user.id] ); const newPassword = "NewStrongPassword123!"; const updated = await User.updatePasswordAndClearChangeFlag( user.id, newPassword ); expect(updated).toBe(true); const dbUser = await User.findById(user.id); const isMatch = await require("bcryptjs").compare( newPassword, dbUser.password_hash ); expect(isMatch).toBe(true); expect(dbUser.must_change_password).toBe(0); // Or FALSE }); }); });