Files
memory-infrastructure-palace/code/websites/pokedex.online/tests/unit/auth/jwt-utils.test.js

155 lines
3.9 KiB
JavaScript

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import {
createToken,
verifyToken,
decodeToken,
isTokenExpired,
getTokenExpiresIn
} from '../../server/utils/jwt-utils.js';
describe('JWT Utilities', () => {
const testSecret = 'test-secret-key';
let token;
beforeEach(() => {
// Create a test token
token = createToken(
{
userId: '123',
isAdmin: true,
permissions: ['admin']
},
testSecret,
3600 // 1 hour
);
});
describe('createToken', () => {
it('creates a valid token', () => {
expect(token).toBeDefined();
expect(typeof token).toBe('string');
expect(token.split('.')).toHaveLength(3);
});
it('includes payload data', () => {
const decoded = decodeToken(token);
expect(decoded.userId).toBe('123');
expect(decoded.isAdmin).toBe(true);
expect(decoded.permissions).toContain('admin');
});
it('includes timestamps', () => {
const decoded = decodeToken(token);
expect(decoded.iat).toBeDefined();
expect(decoded.exp).toBeDefined();
expect(decoded.exp).toBeGreaterThan(decoded.iat);
});
it('respects custom expiration time', () => {
const shortToken = createToken(
{ userId: '123' },
testSecret,
60 // 1 minute
);
const longToken = createToken(
{ userId: '123' },
testSecret,
7200 // 2 hours
);
const shortDecoded = decodeToken(shortToken);
const longDecoded = decodeToken(longToken);
expect(longDecoded.exp - longDecoded.iat).toBeGreaterThan(
shortDecoded.exp - shortDecoded.iat
);
});
});
describe('verifyToken', () => {
it('verifies a valid token', () => {
const decoded = verifyToken(token, testSecret);
expect(decoded.userId).toBe('123');
expect(decoded.isAdmin).toBe(true);
});
it('throws on invalid secret', () => {
expect(() => {
verifyToken(token, 'wrong-secret');
}).toThrow();
});
it('throws on malformed token', () => {
expect(() => {
verifyToken('not.a.token', testSecret);
}).toThrow();
});
it('throws on expired token', () => {
// Create an already expired token
const expiredToken = createToken(
{ userId: '123' },
testSecret,
-1 // Already expired
);
expect(() => {
verifyToken(expiredToken, testSecret);
}).toThrow();
});
});
describe('decodeToken', () => {
it('decodes token without verification', () => {
const decoded = decodeToken(token);
expect(decoded.userId).toBe('123');
expect(decoded.isAdmin).toBe(true);
});
it('returns null for invalid token', () => {
const result = decodeToken('invalid');
expect(result).toBeNull();
});
});
describe('isTokenExpired', () => {
it('returns false for valid token', () => {
expect(isTokenExpired(token)).toBe(false);
});
it('returns true for expired token', () => {
const expiredToken = createToken(
{ userId: '123' },
testSecret,
-1
);
expect(isTokenExpired(expiredToken)).toBe(true);
});
it('returns true for invalid token', () => {
expect(isTokenExpired('invalid')).toBe(true);
});
});
describe('getTokenExpiresIn', () => {
it('returns remaining time in milliseconds', () => {
const remaining = getTokenExpiresIn(token);
expect(remaining).toBeGreaterThan(0);
expect(remaining).toBeLessThanOrEqual(3600000); // 1 hour in ms
});
it('returns 0 for expired token', () => {
const expiredToken = createToken(
{ userId: '123' },
testSecret,
-1
);
expect(getTokenExpiresIn(expiredToken)).toBe(0);
});
it('returns 0 for invalid token', () => {
expect(getTokenExpiresIn('invalid')).toBe(0);
});
});
});