Files

140 lines
4.2 KiB
TypeScript

import { JWTService, TokenPayload } from '../../../src/Application/Services/JWTService';
import { Request, Response } from 'express';
import { UserState } from '../../../src/Domain/User/UserAggregate';
describe('JWTService - Token Refresh Logic', () => {
let jwtService: JWTService;
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
let dateNowSpy: jest.SpyInstance;
beforeEach(() => {
jwtService = new JWTService();
mockRequest = {
cookies: {}
};
mockResponse = {
cookie: jest.fn()
};
// Create a fresh spy for Date.now in each test
dateNowSpy = jest.spyOn(Date, 'now');
});
afterEach(() => {
// Always restore Date.now after each test
dateNowSpy.mockRestore();
});
describe('shouldRefreshToken', () => {
it('should return true when token is 75% through its lifetime', () => {
// Token issued at time 100, expires at 900 (lifetime: 800)
// 75% of 800 = 600, so at time 700 (100 + 600), it should refresh
const payload: TokenPayload = {
userId: 'test-user',
authLevel: 0 as 0 | 1,
userStatus: UserState.VERIFIED_REGULAR,
orgId: 'test-org',
iat: 100,
exp: 900
};
// Mock current time as 700 (which is 75% through the token lifetime)
dateNowSpy.mockReturnValue(700 * 1000);
const result = jwtService.shouldRefreshToken(payload);
expect(result).toBe(true);
});
it('should return true when token is more than 75% through its lifetime', () => {
const payload: TokenPayload = {
userId: 'test-user',
authLevel: 0 as 0 | 1,
userStatus: UserState.VERIFIED_REGULAR,
orgId: 'test-org',
iat: 100,
exp: 900
};
// Mock current time as 750 (which is 81.25% through the token lifetime)
dateNowSpy.mockReturnValue(750 * 1000);
const result = jwtService.shouldRefreshToken(payload);
expect(result).toBe(true);
});
it('should return false when token is less than 75% through its lifetime', () => {
const payload: TokenPayload = {
userId: 'test-user',
authLevel: 0 as 0 | 1,
userStatus: UserState.VERIFIED_REGULAR,
orgId: 'test-org',
iat: 100,
exp: 900
};
// Mock current time as 600 (which is 62.5% through the token lifetime)
dateNowSpy.mockReturnValue(600 * 1000);
const result = jwtService.shouldRefreshToken(payload);
expect(result).toBe(false);
});
it('should return false when payload does not have required timestamp fields', () => {
const payload: TokenPayload = {
userId: 'test-user',
authLevel: 0 as 0 | 1,
userStatus: UserState.VERIFIED_REGULAR,
orgId: 'test-org'
};
const result = jwtService.shouldRefreshToken(payload);
expect(result).toBe(false);
});
});
describe('refreshIfNeeded', () => {
it('should return new token when refresh is needed', () => {
// Setup a payload that needs refresh (75% through lifetime)
const payload: TokenPayload = {
userId: 'test-user',
authLevel: 0 as 0 | 1,
userStatus: UserState.VERIFIED_REGULAR,
orgId: 'test-org',
iat: 100,
exp: 900
};
// Mock current time as 700 (75% through the token lifetime)
dateNowSpy.mockReturnValue(700 * 1000);
const result = jwtService.refreshIfNeeded(payload, mockResponse as Response);
expect(result).toBe(true);
expect(mockResponse.cookie).toHaveBeenCalled();
});
it('should return false when refresh is not needed', () => {
// Setup a payload that doesn't need refresh (less than 75% through lifetime)
const payload: TokenPayload = {
userId: 'test-user',
authLevel: 0 as 0 | 1,
userStatus: UserState.VERIFIED_REGULAR,
orgId: 'test-org',
iat: 100,
exp: 900
};
// Mock current time as 600 (62.5% through the token lifetime)
dateNowSpy.mockReturnValue(600 * 1000);
const result = jwtService.refreshIfNeeded(payload, mockResponse as Response);
expect(result).toBe(false);
expect(mockResponse.cookie).not.toHaveBeenCalled();
});
});
});