aa23a263fe
- 移除 react-i18next、i18next 及相关依赖
- 删除旧的 i18n/ 目录和 useLazyTranslation 工具
- 新增 utils/chromeI18n.ts 类型安全 wrapper(useI18n Hook + getMessage)
- 生成 public/_locales/{zh,en}/messages.json(298 个翻译 key)
- 批量更新 39+ 组件文件的导入和翻译调用
- 转换翻译键格式:namespace:key → namespace_key
- 修复 ErrorBoundary/PageErrorBoundary 从 withTranslation HOC 改为直接调用 getMessage
- 更新 vitest.setup.ts mock 加载实际翻译文本
- 修复 11 个测试文件的断言以匹配中文翻译
- TypeScript、ESLint、547 项测试全部通过
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
132 lines
4.7 KiB
TypeScript
132 lines
4.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import {
|
|
FEATURES,
|
|
getAllFeatureKeys,
|
|
getDefaultPageOrder,
|
|
getDefaultVisibleFeatureKeys,
|
|
getFeatureByKey,
|
|
} from '@/config/features';
|
|
|
|
describe('features', () => {
|
|
describe('FEATURES', () => {
|
|
it('should have 11 features defined', () => {
|
|
expect(FEATURES).toHaveLength(11);
|
|
});
|
|
|
|
it('should have all required properties for each feature', () => {
|
|
FEATURES.forEach((feature) => {
|
|
expect(feature).toHaveProperty('key');
|
|
expect(feature).toHaveProperty('labelKey');
|
|
expect(feature).toHaveProperty('descriptionKey');
|
|
expect(feature).toHaveProperty('defaultVisible');
|
|
expect(feature).toHaveProperty('components');
|
|
expect(typeof feature.key).toBe('string');
|
|
expect(typeof feature.labelKey).toBe('string');
|
|
expect(typeof feature.descriptionKey).toBe('string');
|
|
expect(typeof feature.defaultVisible).toBe('boolean');
|
|
expect(typeof feature.components).toBe('object');
|
|
expect(feature.components).toHaveProperty('popup');
|
|
expect(feature.components).toHaveProperty('sidepanel');
|
|
expect(feature.components).toHaveProperty('tab');
|
|
|
|
// Optional UI properties for non-hidden features
|
|
if (feature.key !== 'dashboard') {
|
|
expect(feature).toHaveProperty('icon');
|
|
expect(feature).toHaveProperty('themeColorKey');
|
|
expect(typeof feature.themeColorKey).toBe('string');
|
|
}
|
|
});
|
|
});
|
|
|
|
it('should have unique keys for each feature', () => {
|
|
const keys = FEATURES.map((f) => f.key);
|
|
const uniqueKeys = new Set(keys);
|
|
expect(uniqueKeys.size).toBe(keys.length);
|
|
});
|
|
});
|
|
|
|
describe('getFeatureByKey', () => {
|
|
it('should return dashboard feature', () => {
|
|
const feature = getFeatureByKey('dashboard');
|
|
expect(feature).toBeDefined();
|
|
expect(feature?.key).toBe('dashboard');
|
|
expect(feature?.labelKey).toBe('dashboard_title');
|
|
});
|
|
|
|
it('should return timestamp feature', () => {
|
|
const feature = getFeatureByKey('timestamp');
|
|
expect(feature).toBeDefined();
|
|
expect(feature?.key).toBe('timestamp');
|
|
expect(feature?.labelKey).toBe('timestamp_title');
|
|
expect(feature?.themeColorKey).toBeDefined();
|
|
});
|
|
|
|
it('should return storageCleaner feature', () => {
|
|
const feature = getFeatureByKey('storageCleaner');
|
|
expect(feature).toBeDefined();
|
|
expect(feature?.key).toBe('storageCleaner');
|
|
expect(feature?.labelKey).toBe('storageCleaner_title');
|
|
});
|
|
|
|
it('should return undefined for invalid key', () => {
|
|
const feature = getFeatureByKey('invalid' as any);
|
|
expect(feature).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('getDefaultVisibleFeatureKeys', () => {
|
|
it('should return only visible features', () => {
|
|
const visibleKeys = getDefaultVisibleFeatureKeys();
|
|
visibleKeys.forEach((key) => {
|
|
const feature = getFeatureByKey(key);
|
|
expect(feature?.defaultVisible).toBe(true);
|
|
});
|
|
});
|
|
|
|
it('should include dashboard, timestamp, storageCleaner, qrCode', () => {
|
|
const visibleKeys = getDefaultVisibleFeatureKeys();
|
|
expect(visibleKeys).toContain('dashboard');
|
|
expect(visibleKeys).toContain('timestamp');
|
|
expect(visibleKeys).toContain('storageCleaner');
|
|
expect(visibleKeys).toContain('qrCode');
|
|
});
|
|
});
|
|
|
|
describe('getAllFeatureKeys', () => {
|
|
it('should return all feature keys', () => {
|
|
const allKeys = getAllFeatureKeys();
|
|
expect(allKeys).toHaveLength(11);
|
|
expect(allKeys).toContain('dashboard');
|
|
expect(allKeys).toContain('timestamp');
|
|
expect(allKeys).toContain('storageCleaner');
|
|
expect(allKeys).toContain('qrCode');
|
|
expect(allKeys).toContain('textStatistics');
|
|
expect(allKeys).toContain('jwt');
|
|
expect(allKeys).toContain('jsonDiff');
|
|
expect(allKeys).toContain('base64Converter');
|
|
expect(allKeys).toContain('markdownToHtml');
|
|
expect(allKeys).toContain('htmlToMarkdown');
|
|
expect(allKeys).toContain('rightClickRestorer');
|
|
});
|
|
});
|
|
|
|
describe('getDefaultPageOrder', () => {
|
|
it('should exclude dashboard from page order', () => {
|
|
const pageOrder = getDefaultPageOrder();
|
|
expect(pageOrder).not.toContain('dashboard');
|
|
});
|
|
|
|
it('should include timestamp, storageCleaner, qrCode in page order', () => {
|
|
const pageOrder = getDefaultPageOrder();
|
|
expect(pageOrder).toContain('timestamp');
|
|
expect(pageOrder).toContain('storageCleaner');
|
|
expect(pageOrder).toContain('qrCode');
|
|
});
|
|
|
|
it('should have 10 items in page order', () => {
|
|
const pageOrder = getDefaultPageOrder();
|
|
expect(pageOrder).toHaveLength(10);
|
|
});
|
|
});
|
|
});
|