/** * utils.ts 工具函数单元测试 */ import { describe, it, expect, vi } from 'vitest'; import { escapeHtml, debounce, formatTime, uuid, shortUuid } from '../src/utils'; describe('escapeHtml', () => { it('转义 HTML 特殊字符', () => { expect(escapeHtml('')).toBe( '<script>alert("xss")</script>' ); }); it('转义所有五种危险字符', () => { expect(escapeHtml('&<>"\'')).toBe('&<>"''); }); it('不修改安全文本', () => { expect(escapeHtml('Hello World 你好世界')).toBe('Hello World 你好世界'); }); it('空字符串返回空字符串', () => { expect(escapeHtml('')).toBe(''); }); }); describe('uuid', () => { it('生成符合 UUID v4 格式的字符串', () => { const id = uuid(); expect(id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/); }); it('两次生成不同的值', () => { expect(uuid()).not.toBe(uuid()); }); }); describe('shortUuid', () => { it('生成长度为 8 的字符串', () => { expect(shortUuid()).toHaveLength(8); }); }); describe('formatTime', () => { it('格式化为 HH:mm', () => { // 2026-01-15 14:30:00 UTC const ts = new Date(2026, 0, 15, 14, 30, 0).getTime(); expect(formatTime(ts)).toBe('14:30'); }); it('补零处理', () => { const ts = new Date(2026, 0, 1, 9, 5, 0).getTime(); expect(formatTime(ts)).toBe('09:05'); }); }); describe('debounce', () => { it('延迟执行函数', async () => { vi.useFakeTimers(); const fn = vi.fn(); const debounced = debounce(fn, 100); debounced(); expect(fn).not.toHaveBeenCalled(); vi.advanceTimersByTime(100); expect(fn).toHaveBeenCalledTimes(1); vi.useRealTimers(); }); it('连续调用只执行最后一次', async () => { vi.useFakeTimers(); const fn = vi.fn(); const debounced = debounce(fn, 100); debounced(); debounced(); debounced(); vi.advanceTimersByTime(100); expect(fn).toHaveBeenCalledTimes(1); vi.useRealTimers(); }); });