mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
Add comprehensive unit tests for: - buildCodexQuotaWindows(): window parsing, clamping, reset time calculation - buildGeminiCliBuckets(): bucket grouping, model series, token types - resolveGeminiCliProjectId(): project ID extraction from account field - sanitizeEmail(): email to filename conversion - isTokenExpired(): token expiry validation Also removes unused 'preferred' field from GEMINI_CLI_GROUPS (YAGNI) 39 new tests covering edge cases: - Percentage clamping (0-100, 0-1) - Missing/null fields - camelCase/snake_case API responses - Empty inputs - Invalid date strings Addresses code review feedback on PR #395
89 lines
2.9 KiB
TypeScript
89 lines
2.9 KiB
TypeScript
/**
|
|
* Auth Utilities Unit Tests
|
|
*
|
|
* Tests for shared authentication utility functions
|
|
*/
|
|
|
|
import { describe, it, expect } from 'bun:test';
|
|
import { sanitizeEmail, isTokenExpired } from '../../../src/cliproxy/auth-utils';
|
|
|
|
describe('Auth Utilities', () => {
|
|
describe('sanitizeEmail', () => {
|
|
it('should replace @ with underscore', () => {
|
|
const result = sanitizeEmail('user@example.com');
|
|
expect(result).not.toContain('@');
|
|
expect(result).toContain('user_example');
|
|
});
|
|
|
|
it('should replace . with underscore', () => {
|
|
const result = sanitizeEmail('user@example.com');
|
|
expect(result).not.toContain('.');
|
|
expect(result).toBe('user_example_com');
|
|
});
|
|
|
|
it('should handle multiple dots', () => {
|
|
const result = sanitizeEmail('user.name@sub.example.com');
|
|
expect(result).toBe('user_name_sub_example_com');
|
|
});
|
|
|
|
it('should handle email without dots in domain', () => {
|
|
const result = sanitizeEmail('user@localhost');
|
|
expect(result).toBe('user_localhost');
|
|
});
|
|
|
|
it('should handle empty string', () => {
|
|
const result = sanitizeEmail('');
|
|
expect(result).toBe('');
|
|
});
|
|
});
|
|
|
|
describe('isTokenExpired', () => {
|
|
it('should return false for undefined input', () => {
|
|
const result = isTokenExpired(undefined);
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('should return false for empty string', () => {
|
|
const result = isTokenExpired('');
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('should return true for past date', () => {
|
|
const pastDate = new Date(Date.now() - 3600000).toISOString(); // 1 hour ago
|
|
const result = isTokenExpired(pastDate);
|
|
expect(result).toBe(true);
|
|
});
|
|
|
|
it('should return false for future date', () => {
|
|
const futureDate = new Date(Date.now() + 3600000).toISOString(); // 1 hour from now
|
|
const result = isTokenExpired(futureDate);
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('should return false for invalid date string', () => {
|
|
// new Date('invalid') returns Invalid Date, getTime() returns NaN
|
|
// NaN < Date.now() is false
|
|
const result = isTokenExpired('not-a-date');
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
it('should handle ISO date strings', () => {
|
|
const pastISO = '2020-01-01T00:00:00.000Z';
|
|
expect(isTokenExpired(pastISO)).toBe(true);
|
|
|
|
const futureISO = '2030-01-01T00:00:00.000Z';
|
|
expect(isTokenExpired(futureISO)).toBe(false);
|
|
});
|
|
|
|
it('should handle Unix timestamp strings', () => {
|
|
// JavaScript Date can parse numeric strings as timestamps
|
|
const pastTimestamp = String(Date.now() - 86400000); // Yesterday
|
|
// Note: Date parsing of pure numbers as strings is inconsistent
|
|
// This test documents the actual behavior
|
|
const result = isTokenExpired(pastTimestamp);
|
|
// The behavior depends on how Date parses the string
|
|
expect(typeof result).toBe('boolean');
|
|
});
|
|
});
|
|
});
|