feat: prepare Zhinian desktop pilot
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled

This commit is contained in:
inman
2026-05-07 21:49:20 +08:00
parent cddaf37016
commit 0abc48189c
103 changed files with 10975 additions and 2049 deletions

View File

@@ -4,6 +4,8 @@ import { YinianSkills } from '@/pages/YinianSkills';
import { useYinianStore } from '@/stores/yinian';
import { useYinianSkillsStore } from '@/stores/yinian-skills';
import { useSkillsStore } from '@/stores/skills';
import { useQuickTasksStore } from '@/stores/quick-tasks';
import i18n from '@/i18n';
import type { YinianConfigSnapshot, YinianLocalSkill } from '../../shared/yinian';
const toastSuccessMock = vi.fn();
@@ -62,9 +64,14 @@ function createLocalSkill(overrides: Partial<YinianLocalSkill>): YinianLocalSkil
};
}
function clickCapabilityTab(label: '服务下发' | '本地安装') {
fireEvent.click(screen.getByRole('button', { name: new RegExp(`^${label}\\s+\\d+$`) }));
}
describe('YinianSkills page', () => {
beforeEach(() => {
beforeEach(async () => {
vi.clearAllMocks();
await i18n.changeLanguage('zh');
useYinianStore.setState({
status: 'authenticated',
session: {
@@ -89,6 +96,7 @@ describe('YinianSkills page', () => {
error: null,
fetchSkills: vi.fn().mockResolvedValue(undefined),
});
useQuickTasksStore.setState({ tasks: [] });
vi.mocked(window.yinian.skills.getRegistry).mockReset();
vi.mocked(window.yinian.skills.getRegistry).mockResolvedValue(undefined);
vi.mocked(window.yinian.skills.sync).mockReset();
@@ -97,8 +105,9 @@ describe('YinianSkills page', () => {
it('shows empty entitlement state', () => {
render(<YinianSkills />);
expect(screen.getByText('智念企业组织空间')).toBeInTheDocument();
expect(screen.getByTestId('yinian-skills-empty-entitlements')).toHaveTextContent('当前组织空间尚未开通应用');
expect(screen.getByText('业务能力包')).toBeInTheDocument();
clickCapabilityTab('服务下发');
expect(screen.getByTestId('yinian-skills-empty-entitlements')).toHaveTextContent('当前组织空间尚未开通能力包');
});
it('maps entitlement and registry states for installed, update, disabled, and failed skills', () => {
@@ -149,6 +158,7 @@ describe('YinianSkills page', () => {
});
render(<YinianSkills />);
clickCapabilityTab('服务下发');
expect(screen.getByTestId('yinian-skill-state-daily-report')).toHaveTextContent('已是最新');
expect(screen.getByTestId('yinian-skill-state-data-check')).toHaveTextContent('有更新');
@@ -179,7 +189,7 @@ describe('YinianSkills page', () => {
});
render(<YinianSkills />);
fireEvent.click(screen.getByRole('button', { name: /本地安装/ }));
clickCapabilityTab('本地安装');
expect(screen.getByText('本地总结助手')).toBeInTheDocument();
expect(screen.getByText('整理本地会话内容')).toBeInTheDocument();
@@ -187,6 +197,52 @@ describe('YinianSkills page', () => {
expect(screen.getByText('/tmp/openclaw/skills/local-summary')).toBeInTheDocument();
});
it('hides OpenClaw built-in skills from local capability packs by default', () => {
useSkillsStore.setState({
skills: [
{
id: 'builtin-search',
slug: 'builtin-search',
name: 'OpenClaw 内置搜索',
description: 'OpenClaw 自带能力',
enabled: true,
version: '1.0.0',
isBundled: true,
source: 'openclaw-bundled',
},
{
id: 'extra-helper',
slug: 'extra-helper',
name: 'OpenClaw 扩展目录助手',
description: 'OpenClaw 扩展目录能力',
enabled: true,
version: '1.0.0',
source: 'openclaw-extra',
},
{
id: 'local-summary',
slug: 'local-summary',
name: '本地总结助手',
description: '整理本地会话内容',
enabled: true,
version: '0.2.0',
source: 'openclaw-managed',
baseDir: '/tmp/openclaw/skills/local-summary',
},
],
loading: false,
error: null,
fetchSkills: vi.fn().mockResolvedValue(undefined),
});
render(<YinianSkills />);
clickCapabilityTab('本地安装');
expect(screen.queryByText('OpenClaw 内置搜索')).not.toBeInTheDocument();
expect(screen.queryByText('OpenClaw 扩展目录助手')).not.toBeInTheDocument();
expect(screen.getByText('本地总结助手')).toBeInTheDocument();
});
it('shows empty registry warning when entitlements exist but no local skills are installed', () => {
useYinianStore.setState({
config: createConfig({
@@ -204,9 +260,10 @@ describe('YinianSkills page', () => {
});
render(<YinianSkills />);
clickCapabilityTab('服务下发');
expect(screen.getByTestId('yinian-skill-state-daily-report')).toHaveTextContent('已开通未同步');
expect(screen.getByTestId('yinian-skills-empty-registry')).toHaveTextContent('这台电脑还没有准备好应用');
expect(screen.getByTestId('yinian-skills-empty-registry')).toHaveTextContent('这台电脑还没有准备好能力包');
});
it('sync button stores result and shows success toast', async () => {
@@ -231,7 +288,7 @@ describe('YinianSkills page', () => {
});
render(<YinianSkills />);
const syncButton = screen.getByRole('button', { name: '同步应用' });
const syncButton = screen.getByRole('button', { name: '同步能力包' });
await waitFor(() => {
expect(syncButton).not.toBeDisabled();
});
@@ -239,7 +296,7 @@ describe('YinianSkills page', () => {
await waitFor(() => {
expect(window.yinian.skills.sync).toHaveBeenCalled();
expect(toastSuccessMock).toHaveBeenCalledWith('应用已同步');
expect(toastSuccessMock).toHaveBeenCalledWith('能力包已同步');
});
expect(useYinianSkillsStore.getState().localSkills).toHaveLength(1);
});