Backend Tests Added: - Unit tests for helpers.js (tokens, validation, pagination) - Unit tests for middleware (auth, errorHandler, validate) - Integration tests for auth endpoints - Integration tests for game endpoints - Integration tests for admin endpoints - Integration tests for employee endpoints - Integration tests for draw endpoints - Integration tests for newsletter/contact endpoints Also added: - cross-env for Windows compatibility - Test scripts update 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
214 lines
6.3 KiB
JavaScript
214 lines
6.3 KiB
JavaScript
/**
|
|
* Tests unitaires pour src/utils/helpers.js
|
|
*/
|
|
import {
|
|
generateToken,
|
|
generateJWT,
|
|
verifyJWT,
|
|
generateTicketCode,
|
|
isValidEmail,
|
|
isValidPhone,
|
|
cleanPhone,
|
|
formatDate,
|
|
maskEmail,
|
|
getTokenExpiry,
|
|
isExpired,
|
|
generateRandomPassword,
|
|
getPagination,
|
|
formatPaginatedResponse,
|
|
} from '../../src/utils/helpers.js';
|
|
|
|
describe('Helpers - Token Generation', () => {
|
|
describe('generateToken', () => {
|
|
it('should generate a token of default length 32', () => {
|
|
const token = generateToken();
|
|
expect(token).toHaveLength(64); // hex string is 2x the byte length
|
|
});
|
|
|
|
it('should generate a token of specified length', () => {
|
|
const token = generateToken(16);
|
|
expect(token).toHaveLength(32);
|
|
});
|
|
|
|
it('should generate unique tokens', () => {
|
|
const token1 = generateToken();
|
|
const token2 = generateToken();
|
|
expect(token1).not.toBe(token2);
|
|
});
|
|
});
|
|
|
|
describe('generateJWT', () => {
|
|
it('should generate a valid JWT token', () => {
|
|
const token = generateJWT(1, 'test@example.com', 'CLIENT');
|
|
expect(token).toBeDefined();
|
|
expect(typeof token).toBe('string');
|
|
expect(token.split('.')).toHaveLength(3);
|
|
});
|
|
});
|
|
|
|
describe('verifyJWT', () => {
|
|
it('should verify a valid JWT token', () => {
|
|
const token = generateJWT(1, 'test@example.com', 'CLIENT');
|
|
const decoded = verifyJWT(token);
|
|
expect(decoded).toBeDefined();
|
|
expect(decoded.userId).toBe(1);
|
|
expect(decoded.email).toBe('test@example.com');
|
|
expect(decoded.role).toBe('CLIENT');
|
|
});
|
|
|
|
it('should return null for invalid token', () => {
|
|
const decoded = verifyJWT('invalid-token');
|
|
expect(decoded).toBeNull();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Helpers - Ticket Code Generation', () => {
|
|
describe('generateTicketCode', () => {
|
|
it('should generate a ticket code starting with TTP', () => {
|
|
const code = generateTicketCode();
|
|
expect(code).toMatch(/^TTP/);
|
|
});
|
|
|
|
it('should generate a 10-character code', () => {
|
|
const code = generateTicketCode();
|
|
expect(code).toHaveLength(10);
|
|
});
|
|
|
|
it('should include current year', () => {
|
|
const code = generateTicketCode();
|
|
const year = new Date().getFullYear().toString();
|
|
expect(code).toContain(year);
|
|
});
|
|
|
|
it('should generate unique codes', () => {
|
|
const codes = new Set();
|
|
for (let i = 0; i < 100; i++) {
|
|
codes.add(generateTicketCode());
|
|
}
|
|
expect(codes.size).toBe(100);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Helpers - Validation', () => {
|
|
describe('isValidEmail', () => {
|
|
it('should return true for valid emails', () => {
|
|
expect(isValidEmail('test@example.com')).toBe(true);
|
|
expect(isValidEmail('user.name@domain.fr')).toBe(true);
|
|
expect(isValidEmail('user+tag@example.org')).toBe(true);
|
|
});
|
|
|
|
it('should return false for invalid emails', () => {
|
|
expect(isValidEmail('invalid')).toBe(false);
|
|
expect(isValidEmail('invalid@')).toBe(false);
|
|
expect(isValidEmail('@domain.com')).toBe(false);
|
|
expect(isValidEmail('')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('isValidPhone', () => {
|
|
it('should return true for valid French phone numbers', () => {
|
|
expect(isValidPhone('0612345678')).toBe(true);
|
|
expect(isValidPhone('06 12 34 56 78')).toBe(true);
|
|
expect(isValidPhone('+33612345678')).toBe(true);
|
|
});
|
|
|
|
it('should return false for invalid phone numbers', () => {
|
|
expect(isValidPhone('123')).toBe(false);
|
|
expect(isValidPhone('')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('cleanPhone', () => {
|
|
it('should remove spaces from phone number', () => {
|
|
expect(cleanPhone('06 12 34 56 78')).toBe('0612345678');
|
|
});
|
|
|
|
it('should handle already clean numbers', () => {
|
|
expect(cleanPhone('0612345678')).toBe('0612345678');
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Helpers - Date Functions', () => {
|
|
describe('formatDate', () => {
|
|
it('should format date to French locale', () => {
|
|
const date = new Date('2025-01-15');
|
|
const formatted = formatDate(date);
|
|
expect(formatted).toContain('2025');
|
|
});
|
|
});
|
|
|
|
describe('getTokenExpiry', () => {
|
|
it('should return a future date', () => {
|
|
const expiry = getTokenExpiry(24);
|
|
expect(new Date(expiry).getTime()).toBeGreaterThan(Date.now());
|
|
});
|
|
});
|
|
|
|
describe('isExpired', () => {
|
|
it('should return true for past dates', () => {
|
|
const pastDate = new Date('2020-01-01');
|
|
expect(isExpired(pastDate)).toBe(true);
|
|
});
|
|
|
|
it('should return false for future dates', () => {
|
|
const futureDate = new Date('2030-01-01');
|
|
expect(isExpired(futureDate)).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Helpers - Security', () => {
|
|
describe('maskEmail', () => {
|
|
it('should mask the middle of email', () => {
|
|
const masked = maskEmail('john.doe@example.com');
|
|
expect(masked).toContain('***');
|
|
expect(masked).not.toBe('john.doe@example.com');
|
|
});
|
|
});
|
|
|
|
describe('generateRandomPassword', () => {
|
|
it('should generate password of specified length', () => {
|
|
const password = generateRandomPassword(12);
|
|
expect(password).toHaveLength(12);
|
|
});
|
|
|
|
it('should generate unique passwords', () => {
|
|
const p1 = generateRandomPassword(16);
|
|
const p2 = generateRandomPassword(16);
|
|
expect(p1).not.toBe(p2);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Helpers - Pagination', () => {
|
|
describe('getPagination', () => {
|
|
it('should calculate correct offset', () => {
|
|
expect(getPagination(1, 10)).toEqual({ offset: 0, limit: 10 });
|
|
expect(getPagination(2, 10)).toEqual({ offset: 10, limit: 10 });
|
|
expect(getPagination(3, 20)).toEqual({ offset: 40, limit: 20 });
|
|
});
|
|
|
|
it('should handle default values', () => {
|
|
const result = getPagination();
|
|
expect(result.offset).toBeDefined();
|
|
expect(result.limit).toBeDefined();
|
|
});
|
|
});
|
|
|
|
describe('formatPaginatedResponse', () => {
|
|
it('should format paginated response correctly', () => {
|
|
const data = [{ id: 1 }, { id: 2 }];
|
|
const response = formatPaginatedResponse(data, 100, 1, 10);
|
|
|
|
expect(response.data).toEqual(data);
|
|
expect(response.pagination.total).toBe(100);
|
|
expect(response.pagination.page).toBe(1);
|
|
expect(response.pagination.limit).toBe(10);
|
|
expect(response.pagination.totalPages).toBe(10);
|
|
});
|
|
});
|
|
});
|