
- Updated `.env` and `.env.test` files to include PostgreSQL connection settings and Redis configuration. - Migrated database from SQLite to PostgreSQL, updating relevant queries and connection logic. - Enhanced error handling and logging throughout the application. - Added new test utilities for PostgreSQL integration and updated user model methods. - Introduced new routes for user authentication and form management, ensuring compatibility with the new database structure. - Created login and registration views in EJS for user interaction.
155 lines
4.8 KiB
JavaScript
155 lines
4.8 KiB
JavaScript
// __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
|
|
});
|
|
});
|
|
});
|