2025-06-04 13:12:37 -04:00
|
|
|
import mongoose from 'mongoose';
|
|
|
|
|
import { createUserMethods } from './user';
|
|
|
|
|
import { signPayload } from '~/crypto';
|
|
|
|
|
import type { IUser } from '~/types';
|
|
|
|
|
|
|
|
|
|
jest.mock('~/crypto', () => ({
|
|
|
|
|
signPayload: jest.fn(),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
describe('User Methods', () => {
|
|
|
|
|
const mockSignPayload = signPayload as jest.MockedFunction<typeof signPayload>;
|
|
|
|
|
let userMethods: ReturnType<typeof createUserMethods>;
|
|
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
|
jest.clearAllMocks();
|
|
|
|
|
userMethods = createUserMethods(mongoose);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
describe('generateToken', () => {
|
|
|
|
|
const mockUser = {
|
|
|
|
|
_id: 'user123',
|
|
|
|
|
username: 'testuser',
|
|
|
|
|
provider: 'local',
|
|
|
|
|
email: 'test@example.com',
|
|
|
|
|
name: 'Test User',
|
|
|
|
|
avatar: '',
|
|
|
|
|
role: 'user',
|
|
|
|
|
emailVerified: false,
|
|
|
|
|
createdAt: new Date(),
|
|
|
|
|
updatedAt: new Date(),
|
|
|
|
|
} as IUser;
|
|
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
|
delete process.env.JWT_SECRET;
|
|
|
|
|
});
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
it('should default to 15 minutes when expiresIn is not provided', async () => {
|
2025-06-04 13:12:37 -04:00
|
|
|
process.env.JWT_SECRET = 'test-secret';
|
|
|
|
|
mockSignPayload.mockResolvedValue('mocked-token');
|
|
|
|
|
|
|
|
|
|
await userMethods.generateToken(mockUser);
|
|
|
|
|
|
|
|
|
|
expect(mockSignPayload).toHaveBeenCalledWith({
|
|
|
|
|
payload: {
|
|
|
|
|
id: mockUser._id,
|
|
|
|
|
username: mockUser.username,
|
|
|
|
|
provider: mockUser.provider,
|
|
|
|
|
email: mockUser.email,
|
|
|
|
|
},
|
|
|
|
|
secret: 'test-secret',
|
2025-12-25 12:25:41 -05:00
|
|
|
expirationTime: 900, // 15 minutes in seconds (DEFAULT_SESSION_EXPIRY / 1000)
|
2025-06-04 13:12:37 -04:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
it('should default to 15 minutes when expiresIn is undefined', async () => {
|
2025-06-04 13:12:37 -04:00
|
|
|
process.env.JWT_SECRET = 'test-secret';
|
|
|
|
|
mockSignPayload.mockResolvedValue('mocked-token');
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
await userMethods.generateToken(mockUser, undefined);
|
2025-06-04 13:12:37 -04:00
|
|
|
|
|
|
|
|
expect(mockSignPayload).toHaveBeenCalledWith({
|
|
|
|
|
payload: {
|
|
|
|
|
id: mockUser._id,
|
|
|
|
|
username: mockUser.username,
|
|
|
|
|
provider: mockUser.provider,
|
|
|
|
|
email: mockUser.email,
|
|
|
|
|
},
|
|
|
|
|
secret: 'test-secret',
|
2025-12-25 12:25:41 -05:00
|
|
|
expirationTime: 900, // 15 minutes in seconds (DEFAULT_SESSION_EXPIRY / 1000)
|
2025-06-04 13:12:37 -04:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
it('should use custom expiry when expiresIn is provided', async () => {
|
2025-06-04 13:12:37 -04:00
|
|
|
process.env.JWT_SECRET = 'test-secret';
|
|
|
|
|
mockSignPayload.mockResolvedValue('mocked-token');
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
await userMethods.generateToken(mockUser, 1000 * 60 * 30); // 30 minutes
|
2025-06-04 13:12:37 -04:00
|
|
|
|
|
|
|
|
expect(mockSignPayload).toHaveBeenCalledWith({
|
|
|
|
|
payload: {
|
|
|
|
|
id: mockUser._id,
|
|
|
|
|
username: mockUser.username,
|
|
|
|
|
provider: mockUser.provider,
|
|
|
|
|
email: mockUser.email,
|
|
|
|
|
},
|
|
|
|
|
secret: 'test-secret',
|
|
|
|
|
expirationTime: 1800, // 30 minutes in seconds
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
it('should use 0 when expiresIn is 0', async () => {
|
2025-06-04 13:12:37 -04:00
|
|
|
process.env.JWT_SECRET = 'test-secret';
|
|
|
|
|
mockSignPayload.mockResolvedValue('mocked-token');
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
// When 0 is passed, it should use 0 (caller's responsibility to pass valid value)
|
|
|
|
|
await userMethods.generateToken(mockUser, 0);
|
2025-06-04 13:12:37 -04:00
|
|
|
|
|
|
|
|
expect(mockSignPayload).toHaveBeenCalledWith({
|
|
|
|
|
payload: {
|
|
|
|
|
id: mockUser._id,
|
|
|
|
|
username: mockUser.username,
|
|
|
|
|
provider: mockUser.provider,
|
|
|
|
|
email: mockUser.email,
|
|
|
|
|
},
|
|
|
|
|
secret: 'test-secret',
|
2025-12-25 12:25:41 -05:00
|
|
|
expirationTime: 0, // 0 seconds
|
2025-06-04 13:12:37 -04:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should throw error when no user is provided', async () => {
|
|
|
|
|
process.env.JWT_SECRET = 'test-secret';
|
|
|
|
|
|
|
|
|
|
await expect(userMethods.generateToken(null as unknown as IUser)).rejects.toThrow(
|
|
|
|
|
'No user provided',
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should return the token from signPayload', async () => {
|
|
|
|
|
process.env.JWT_SECRET = 'test-secret';
|
|
|
|
|
const expectedToken = 'generated-jwt-token';
|
|
|
|
|
mockSignPayload.mockResolvedValue(expectedToken);
|
|
|
|
|
|
2025-12-25 12:25:41 -05:00
|
|
|
const token = await userMethods.generateToken(mockUser, 1000 * 60 * 60); // 1 hour
|
2025-06-04 13:12:37 -04:00
|
|
|
|
|
|
|
|
expect(token).toBe(expectedToken);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|