116 lines
3.6 KiB
TypeScript
116 lines
3.6 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import {
|
|
shouldAutoSwapBaseUrl,
|
|
formatDateTime,
|
|
sourceLabel,
|
|
sourceColor,
|
|
PROVIDER_DEFAULTS,
|
|
extractErrorMessage,
|
|
} from './helpers';
|
|
|
|
describe('AiConfig helpers', () => {
|
|
describe('shouldAutoSwapBaseUrl', () => {
|
|
it('swaps to default on first provider selection', () => {
|
|
const result = shouldAutoSwapBaseUrl('DEEPSEEK', '', null);
|
|
expect(result.shouldSwap).toBe(true);
|
|
expect(result.baseUrl).toBe(PROVIDER_DEFAULTS.DEEPSEEK);
|
|
});
|
|
|
|
it('swaps when current baseUrl matches previous provider default', () => {
|
|
const result = shouldAutoSwapBaseUrl(
|
|
'DEEPSEEK',
|
|
'https://api.openai.com/v1',
|
|
'OPENAI',
|
|
);
|
|
expect(result.shouldSwap).toBe(true);
|
|
expect(result.baseUrl).toBe(PROVIDER_DEFAULTS.DEEPSEEK);
|
|
});
|
|
|
|
it('swaps when current baseUrl is empty', () => {
|
|
const result = shouldAutoSwapBaseUrl('DEEPSEEK', '', 'OPENAI');
|
|
expect(result.shouldSwap).toBe(true);
|
|
});
|
|
|
|
it('keeps custom baseUrl unchanged', () => {
|
|
const result = shouldAutoSwapBaseUrl(
|
|
'OPENAI',
|
|
'https://custom.api.com/v1',
|
|
'DEEPSEEK',
|
|
);
|
|
expect(result.shouldSwap).toBe(false);
|
|
expect(result.baseUrl).toBe('https://custom.api.com/v1');
|
|
});
|
|
});
|
|
|
|
describe('formatDateTime', () => {
|
|
it('returns hyphen for null', () => {
|
|
expect(formatDateTime(null)).toBe('-');
|
|
});
|
|
|
|
it('returns Chinese locale string for ISO date', () => {
|
|
expect(formatDateTime('2024-01-15T10:30:00Z')).toContain('2024');
|
|
});
|
|
});
|
|
|
|
describe('sourceLabel', () => {
|
|
it('returns Chinese labels', () => {
|
|
expect(sourceLabel('database')).toBe('数据库');
|
|
expect(sourceLabel('environment')).toBe('环境变量');
|
|
expect(sourceLabel('none')).toBe('未配置');
|
|
});
|
|
});
|
|
|
|
describe('sourceColor', () => {
|
|
it('returns correct colors', () => {
|
|
expect(sourceColor('database')).toBe('green');
|
|
expect(sourceColor('environment')).toBe('blue');
|
|
expect(sourceColor('none')).toBe('default');
|
|
});
|
|
});
|
|
|
|
describe('extractErrorMessage', () => {
|
|
it('extracts axios-style response error message', () => {
|
|
const err = {
|
|
response: { data: { message: 'API出错' } },
|
|
};
|
|
expect(extractErrorMessage(err)).toBe('API出错');
|
|
});
|
|
|
|
it('falls back to message property', () => {
|
|
const err = { message: 'Network error' };
|
|
expect(extractErrorMessage(err)).toBe('Network error');
|
|
});
|
|
|
|
it('falls back to default on unknown type', () => {
|
|
expect(extractErrorMessage('unknown string')).toBe('操作失败');
|
|
expect(extractErrorMessage(null)).toBe('操作失败');
|
|
expect(extractErrorMessage(undefined)).toBe('操作失败');
|
|
});
|
|
|
|
it('sanitizes: newlines replaced with spaces', () => {
|
|
const err = { message: 'line1\nline2\r\nline3' };
|
|
expect(extractErrorMessage(err)).toBe('line1 line2 line3');
|
|
});
|
|
|
|
it('sanitizes: message > 120 chars truncated with ellipsis', () => {
|
|
const long = 'x'.repeat(200);
|
|
const err = { message: long };
|
|
const result = extractErrorMessage(err);
|
|
expect(result).toHaveLength(121); // 120 + '…' (1 char)
|
|
expect(result.endsWith('\u2026')).toBe(true);
|
|
});
|
|
|
|
it('sanitizes: empty trimmed message falls back', () => {
|
|
const err = { message: ' ' };
|
|
expect(extractErrorMessage(err)).toBe('操作失败');
|
|
});
|
|
|
|
it('sanitizes: plain object message property sanitized', () => {
|
|
const err = {
|
|
message: ' some \n\nerror \r\nmessage ',
|
|
};
|
|
expect(extractErrorMessage(err)).toBe('some error message');
|
|
});
|
|
});
|
|
});
|