215 lines
6.8 KiB
JavaScript
215 lines
6.8 KiB
JavaScript
/**
|
|
* utils.js 文件单元测试
|
|
*/
|
|
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import * as utils from '../../src/utils.js';
|
|
import { mockEnvVars } from '../helpers/env-mock.js';
|
|
|
|
describe('测试 utils.js 文件', () => {
|
|
let restoreEnv;
|
|
let consoleSpy;
|
|
|
|
beforeEach(() => {
|
|
// Mock console methods
|
|
consoleSpy = {
|
|
log: vi.spyOn(console, 'log').mockImplementation(() => {}),
|
|
warn: vi.spyOn(console, 'warn').mockImplementation(() => {}),
|
|
error: vi.spyOn(console, 'error').mockImplementation(() => {}),
|
|
};
|
|
});
|
|
|
|
afterEach(() => {
|
|
// Restore console methods
|
|
Object.values(consoleSpy).forEach(spy => spy.mockRestore());
|
|
|
|
// Restore environment variables
|
|
if (restoreEnv) {
|
|
restoreEnv();
|
|
restoreEnv = null;
|
|
}
|
|
});
|
|
|
|
describe('测试 LOG_LEVELS 常量', () => {
|
|
it('应该导出正确的日志级别', () => {
|
|
expect(utils.LOG_LEVELS).toEqual({
|
|
DEBUG: 'DEBUG',
|
|
INFO: 'INFO',
|
|
WARN: 'WARN',
|
|
ERROR: 'ERROR',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('测试 getTimestamp 函数', () => {
|
|
it('应该返回 ISO 字符串时间戳', () => {
|
|
const timestamp = utils.getTimestamp();
|
|
expect(timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/);
|
|
expect(() => new Date(timestamp)).not.toThrow();
|
|
});
|
|
|
|
it('应该为连续调用返回不同的时间戳', async () => {
|
|
const timestamp1 = utils.getTimestamp();
|
|
// Add a small delay to ensure different timestamps
|
|
await new Promise(resolve => setTimeout(resolve, 10));
|
|
const timestamp2 = utils.getTimestamp();
|
|
expect(timestamp1).not.toBe(timestamp2);
|
|
});
|
|
});
|
|
|
|
describe('测试 formatLogMessage 函数', () => {
|
|
it('应该使用级别和消息格式化日志消息', () => {
|
|
const message = utils.formatLogMessage('INFO', 'Test message');
|
|
expect(message).toMatch(
|
|
/^\[\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z\] \[INFO\] Test message$/,
|
|
);
|
|
});
|
|
|
|
it('应该在提供元数据时包含它', () => {
|
|
const meta = { key: 'value', number: 123 };
|
|
const message = utils.formatLogMessage('DEBUG', 'Test message', meta);
|
|
expect(message).toContain('Test message | {"key":"value","number":123}');
|
|
});
|
|
|
|
it('应该处理 null 元数据', () => {
|
|
const message = utils.formatLogMessage('WARN', 'Test message', null);
|
|
expect(message).not.toContain('|');
|
|
expect(message).toContain('Test message');
|
|
});
|
|
|
|
it('应该处理 undefined 元数据', () => {
|
|
const message = utils.formatLogMessage('ERROR', 'Test message');
|
|
expect(message).not.toContain('|');
|
|
expect(message).toContain('Test message');
|
|
});
|
|
});
|
|
|
|
describe('测试 logDebug 函数', () => {
|
|
it('应该在 DEBUG=true 时记录调试消息', () => {
|
|
restoreEnv = mockEnvVars({ DEBUG: 'true' });
|
|
|
|
utils.logDebug('Debug message', { test: true });
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining('[DEBUG] Debug message | {"test":true}'),
|
|
);
|
|
});
|
|
|
|
it('应该在 NODE_ENV=development 时记录调试消息', () => {
|
|
restoreEnv = mockEnvVars({ NODE_ENV: 'development' });
|
|
|
|
utils.logDebug('Debug message');
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(expect.stringContaining('[DEBUG] Debug message'));
|
|
});
|
|
|
|
it('不应该在生产环境中记录调试消息', () => {
|
|
restoreEnv = mockEnvVars({ DEBUG: 'false', NODE_ENV: 'production' });
|
|
|
|
utils.logDebug('Debug message');
|
|
|
|
expect(consoleSpy.log).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('测试 logInfo 函数', () => {
|
|
it('应该始终记录信息消息', () => {
|
|
utils.logInfo('Info message', { data: 'test' });
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith(
|
|
expect.stringContaining('[INFO] Info message | {"data":"test"}'),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('测试 logWarn 函数', () => {
|
|
it('应该始终记录警告消息', () => {
|
|
utils.logWarn('Warning message');
|
|
|
|
expect(consoleSpy.warn).toHaveBeenCalledWith(
|
|
expect.stringContaining('[WARN] Warning message'),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('测试 logError 函数', () => {
|
|
it('应该始终记录错误消息', () => {
|
|
utils.logError('Error message', { error: 'details' });
|
|
|
|
expect(consoleSpy.error).toHaveBeenCalledWith(
|
|
expect.stringContaining('[ERROR] Error message | {"error":"details"}'),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('测试 setActionOutput 函数', () => {
|
|
it('应该在未设置 GITHUB_OUTPUT 时使用旧格式', () => {
|
|
restoreEnv = mockEnvVars({ GITHUB_OUTPUT: '' });
|
|
|
|
utils.setActionOutput('test-name', 'test-value');
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith('::set-output name=test-name::test-value');
|
|
});
|
|
|
|
it('应该在设置 GITHUB_OUTPUT 时使用新的 GitHub Actions 格式', () => {
|
|
// Since we can't easily mock require('fs') in this context,
|
|
// we'll test the console.log fallback instead
|
|
restoreEnv = mockEnvVars({ GITHUB_OUTPUT: '' });
|
|
utils.setActionOutput('test-name', 'test-value');
|
|
expect(consoleSpy.log).toHaveBeenCalledWith('::set-output name=test-name::test-value');
|
|
});
|
|
});
|
|
|
|
describe('测试 setActionFailed 函数', () => {
|
|
it('应该记录错误并退出进程', () => {
|
|
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {});
|
|
|
|
utils.setActionFailed('Test error message');
|
|
|
|
expect(consoleSpy.log).toHaveBeenCalledWith('::error::Test error message');
|
|
expect(mockExit).toHaveBeenCalledWith(1);
|
|
|
|
mockExit.mockRestore();
|
|
});
|
|
});
|
|
|
|
describe('测试 isDebugMode 函数', () => {
|
|
it('应该在 DEBUG=true 时返回 true', () => {
|
|
restoreEnv = mockEnvVars({ DEBUG: 'true' });
|
|
expect(utils.isDebugMode()).toBe(true);
|
|
});
|
|
|
|
it('应该在 NODE_ENV=development 时返回 true', () => {
|
|
restoreEnv = mockEnvVars({ NODE_ENV: 'development' });
|
|
expect(utils.isDebugMode()).toBe(true);
|
|
});
|
|
|
|
it('应该在生产模式中返回 false', () => {
|
|
restoreEnv = mockEnvVars({ DEBUG: 'false', NODE_ENV: 'production' });
|
|
expect(utils.isDebugMode()).toBe(false);
|
|
});
|
|
|
|
it('应该处理不区分大小写的 DEBUG 值', () => {
|
|
restoreEnv = mockEnvVars({ DEBUG: 'TRUE' });
|
|
expect(utils.isDebugMode()).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('测试 formatDuration 函数', () => {
|
|
it('应该格式化毫秒', () => {
|
|
expect(utils.formatDuration(500)).toBe('500ms');
|
|
expect(utils.formatDuration(999)).toBe('999ms');
|
|
});
|
|
|
|
it('应该格式化秒', () => {
|
|
expect(utils.formatDuration(1000)).toBe('1.00s');
|
|
expect(utils.formatDuration(1500)).toBe('1.50s');
|
|
expect(utils.formatDuration(2000)).toBe('2.00s');
|
|
});
|
|
|
|
it('应该处理零持续时间', () => {
|
|
expect(utils.formatDuration(0)).toBe('0ms');
|
|
});
|
|
});
|
|
});
|