- Registration form: added 5 new role options to dropdown - Sidebar: new roles get proper nav access via ALL_ROLES/LEADER_ROLES - Dashboard: isLeader check expanded to include new leadership roles - Shared/Pages: role badge colors added for all new roles - Invite modal: expanded role dropdown
128 lines
3.9 KiB
JavaScript
128 lines
3.9 KiB
JavaScript
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import request from 'supertest';
|
|
import { app } from '../index.js';
|
|
import pool from '../db.js';
|
|
import bcrypt from 'bcryptjs';
|
|
|
|
// Mock dependencies
|
|
vi.mock('../db.js', () => ({
|
|
default: {
|
|
query: vi.fn(),
|
|
},
|
|
initDB: vi.fn()
|
|
}));
|
|
|
|
vi.mock('bcryptjs', () => ({
|
|
default: {
|
|
compare: vi.fn(),
|
|
hash: vi.fn()
|
|
}
|
|
}));
|
|
|
|
describe('Auth Routes', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('POST /api/auth/login', () => {
|
|
it('logs in successfully with correct credentials', async () => {
|
|
const mockUser = {
|
|
id: 'u1',
|
|
name: 'Test User',
|
|
email: 'test@test.com',
|
|
password_hash: 'hashed_password',
|
|
role: 'employee',
|
|
dept: 'dev'
|
|
};
|
|
|
|
// Mock DB response
|
|
pool.query.mockResolvedValue([[mockUser]]);
|
|
// Mock bcrypt comparison
|
|
bcrypt.compare.mockResolvedValue(true);
|
|
|
|
const res = await request(app)
|
|
.post('/api/auth/login')
|
|
.send({ email: 'test@test.com', password: 'password' });
|
|
|
|
expect(res.status).toBe(200);
|
|
expect(res.body).toEqual(expect.objectContaining({
|
|
id: 'u1',
|
|
email: 'test@test.com'
|
|
}));
|
|
expect(res.body).not.toHaveProperty('password_hash');
|
|
});
|
|
|
|
it('returns 401 for invalid password', async () => {
|
|
const mockUser = {
|
|
id: 'u1',
|
|
email: 'test@test.com',
|
|
password_hash: 'hashed_password'
|
|
};
|
|
|
|
pool.query.mockResolvedValue([[mockUser]]);
|
|
bcrypt.compare.mockResolvedValue(false);
|
|
|
|
const res = await request(app)
|
|
.post('/api/auth/login')
|
|
.send({ email: 'test@test.com', password: 'wrong' });
|
|
|
|
expect(res.status).toBe(401);
|
|
expect(res.body).toEqual({ error: 'Invalid email or password' });
|
|
});
|
|
|
|
it('returns 401 for user not found', async () => {
|
|
pool.query.mockResolvedValue([[]]); // Empty array
|
|
|
|
const res = await request(app)
|
|
.post('/api/auth/login')
|
|
.send({ email: 'notfound@test.com', password: 'password' });
|
|
|
|
expect(res.status).toBe(401);
|
|
});
|
|
});
|
|
|
|
describe('POST /api/auth/register', () => {
|
|
it('registers a new user successfully', async () => {
|
|
pool.query.mockResolvedValueOnce([[]]); // Check existing email (empty)
|
|
pool.query.mockResolvedValueOnce({}); // Insert success
|
|
|
|
bcrypt.hash.mockResolvedValue('hashed_new_password');
|
|
|
|
const newUser = {
|
|
name: 'New User',
|
|
email: 'new@test.com',
|
|
password: 'password',
|
|
role: 'employee'
|
|
};
|
|
|
|
const res = await request(app)
|
|
.post('/api/auth/register')
|
|
.send(newUser);
|
|
|
|
expect(res.status).toBe(201);
|
|
expect(res.body).toEqual(expect.objectContaining({
|
|
name: 'New User',
|
|
email: 'new@test.com'
|
|
}));
|
|
|
|
// Verify DB insert called
|
|
expect(pool.query).toHaveBeenCalledTimes(2);
|
|
expect(pool.query).toHaveBeenLastCalledWith(
|
|
expect.stringContaining('INSERT INTO users'),
|
|
expect.arrayContaining(['New User', 'employee', 'new@test.com', 'hashed_new_password'])
|
|
);
|
|
});
|
|
|
|
it('returns 409 if email already exists', async () => {
|
|
pool.query.mockResolvedValueOnce([[{ id: 'existing' }]]);
|
|
|
|
const res = await request(app)
|
|
.post('/api/auth/register')
|
|
.send({ name: 'User', email: 'existing@test.com', password: 'pw' });
|
|
|
|
expect(res.status).toBe(409);
|
|
});
|
|
});
|
|
});
|