mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-19 20:02:03 +08:00
- 工具中心详情页统一承载入口标题和说明 - 数据同步、表结构比对和数据比对嵌入时隐藏内部 hero - 数据目录、快捷键、连接包和安全更新嵌入时隐藏内部 Modal 标题 - 补充工具中心全 pane 标题归属回归断言
183 lines
5.8 KiB
TypeScript
183 lines
5.8 KiB
TypeScript
import { readFileSync } from 'node:fs';
|
|
import React from 'react';
|
|
import { act, create } from 'react-test-renderer';
|
|
import { describe, expect, it, vi } from 'vitest';
|
|
import { I18nProvider } from '../i18n/provider';
|
|
import type { SecurityUpdateStatus } from '../types';
|
|
import type { OverlayWorkbenchTheme } from '../utils/overlayWorkbenchTheme';
|
|
import SecurityUpdateSettingsModal from './SecurityUpdateSettingsModal';
|
|
|
|
vi.mock('../i18n/runtime', () => ({
|
|
syncLanguageRuntime: vi.fn(async () => undefined),
|
|
}));
|
|
|
|
vi.mock('antd', async () => {
|
|
const React = await import('react');
|
|
return {
|
|
Button: ({
|
|
children,
|
|
}: {
|
|
children?: React.ReactNode;
|
|
}) => React.createElement('button', null, children),
|
|
Empty: ({
|
|
description,
|
|
}: {
|
|
description?: React.ReactNode;
|
|
}) => React.createElement('div', null, description),
|
|
Modal: ({
|
|
children,
|
|
footer,
|
|
open,
|
|
title,
|
|
}: {
|
|
children?: React.ReactNode;
|
|
footer?: React.ReactNode;
|
|
open?: boolean;
|
|
title?: React.ReactNode;
|
|
}) => (open ? React.createElement('section', null, title, footer, children) : null),
|
|
Tag: ({
|
|
children,
|
|
}: {
|
|
children?: React.ReactNode;
|
|
}) => React.createElement('span', null, children),
|
|
};
|
|
});
|
|
|
|
vi.mock('@ant-design/icons', async () => {
|
|
const React = await import('react');
|
|
return {
|
|
SafetyCertificateOutlined: () => React.createElement('span', null, 'certificate'),
|
|
};
|
|
});
|
|
|
|
const source = readFileSync(new URL('./SecurityUpdateSettingsModal.tsx', import.meta.url), 'utf8');
|
|
|
|
const overlayTheme: OverlayWorkbenchTheme = {
|
|
isDark: false,
|
|
shellBg: '#fff',
|
|
shellBorder: '1px solid #eee',
|
|
shellShadow: 'none',
|
|
shellBackdropFilter: 'none',
|
|
sectionBg: '#fff',
|
|
sectionBorder: '1px solid #eee',
|
|
mutedText: '#666',
|
|
titleText: '#111',
|
|
iconBg: '#f5f5f5',
|
|
iconColor: '#1677ff',
|
|
hoverBg: '#f5f5f5',
|
|
selectedBg: '#e6f4ff',
|
|
selectedText: '#1677ff',
|
|
divider: '#eee',
|
|
};
|
|
|
|
const baseStatus: SecurityUpdateStatus = {
|
|
overallStatus: 'needs_attention',
|
|
summary: {
|
|
total: 2,
|
|
updated: 1,
|
|
pending: 1,
|
|
skipped: 0,
|
|
failed: 0,
|
|
},
|
|
issues: [
|
|
{
|
|
id: 'issue-1',
|
|
title: 'RAW issue title',
|
|
message: 'RAW issue message',
|
|
severity: 'high',
|
|
status: 'needs_attention',
|
|
action: 'open_connection',
|
|
},
|
|
],
|
|
backupPath: 'C:\\raw\\backup.zip',
|
|
lastError: 'RAW system error',
|
|
};
|
|
|
|
const renderSettingsModalText = async (status: SecurityUpdateStatus = baseStatus) => {
|
|
let renderer: ReturnType<typeof create>;
|
|
|
|
await act(async () => {
|
|
renderer = create(
|
|
<I18nProvider
|
|
preference="en-US"
|
|
systemLanguages={['en-US']}
|
|
onPreferenceChange={() => undefined}
|
|
>
|
|
<SecurityUpdateSettingsModal
|
|
open
|
|
darkMode={false}
|
|
overlayTheme={overlayTheme}
|
|
status={status}
|
|
onClose={() => undefined}
|
|
onStart={() => undefined}
|
|
onRetry={() => undefined}
|
|
onRestart={() => undefined}
|
|
onIssueAction={() => undefined}
|
|
/>
|
|
</I18nProvider>,
|
|
);
|
|
});
|
|
|
|
return JSON.stringify(renderer!.toJSON());
|
|
};
|
|
|
|
describe('SecurityUpdateSettingsModal i18n source guards', () => {
|
|
it('uses settings i18n keys instead of legacy Chinese shell copy', () => {
|
|
expect(source).toContain('security_update.settings.title');
|
|
expect(source).toContain('security_update.settings.current_status');
|
|
expect(source).toContain('security_update.settings.item_default_message');
|
|
expect(source).not.toContain('安全更新');
|
|
expect(source).not.toContain('管理已保存配置的安全更新状态与待处理项。');
|
|
expect(source).not.toContain('当前状态:');
|
|
expect(source).not.toContain('影响范围');
|
|
expect(source).not.toContain('待处理清单');
|
|
expect(source).not.toContain('当前项需要进一步处理后才能完成安全更新。');
|
|
});
|
|
|
|
it('lets the tool center provide the title when embedded', () => {
|
|
expect(source).toContain('title={embedded ? null : (');
|
|
expect(source).toContain('closable={embedded ? false : undefined}');
|
|
});
|
|
|
|
it('localizes settings chrome while preserving raw issue details, backup path and error text', async () => {
|
|
const modalText = await renderSettingsModalText();
|
|
expect(modalText).toContain('Security Update');
|
|
expect(modalText).toContain('Manage the security update status and pending items for saved configurations.');
|
|
expect(modalText).toContain('Check Again');
|
|
expect(modalText).toContain('Restart Update');
|
|
expect(modalText).toContain('Close');
|
|
expect(modalText).toContain('Current status: Needs Attention');
|
|
expect(modalText).toContain('Affected Scope');
|
|
expect(modalText).toContain('Pending Items');
|
|
expect(modalText).toContain('Status: Needs Attention');
|
|
expect(modalText).toContain('Level: High Risk');
|
|
expect(modalText).toContain('Latest Result');
|
|
expect(modalText).toContain('Backup location: ');
|
|
expect(modalText).toContain('Latest error: ');
|
|
expect(modalText).toContain('RAW issue title');
|
|
expect(modalText).toContain('RAW issue message');
|
|
expect(modalText).toContain('C:\\\\raw\\\\backup.zip');
|
|
expect(modalText).toContain('RAW system error');
|
|
});
|
|
|
|
it('localizes the empty pending state and issue default message fallback', async () => {
|
|
const emptyText = await renderSettingsModalText({
|
|
...baseStatus,
|
|
issues: [],
|
|
backupPath: undefined,
|
|
lastError: undefined,
|
|
});
|
|
expect(emptyText).toContain('No pending items');
|
|
|
|
const fallbackText = await renderSettingsModalText({
|
|
...baseStatus,
|
|
issues: [{
|
|
id: 'issue-without-message',
|
|
severity: 'medium',
|
|
status: 'pending',
|
|
}],
|
|
});
|
|
expect(fallbackText).toContain('This item needs more attention before the security update can be completed.');
|
|
});
|
|
});
|