feat: update desktop workflows and app center
This commit is contained in:
176
tests/unit/sidebar-layout.test.tsx
Normal file
176
tests/unit/sidebar-layout.test.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
import { fireEvent, render, screen } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Sidebar } from '@/components/layout/Sidebar';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
import { useCronStore } from '@/stores/cron';
|
||||
import { useGatewayStore } from '@/stores/gateway';
|
||||
import { useSettingsStore } from '@/stores/settings';
|
||||
import { useTaskCenterStore } from '@/stores/task-center';
|
||||
import { useYinianStore } from '@/stores/yinian';
|
||||
import i18n from '@/i18n';
|
||||
|
||||
const hotel = {
|
||||
id: 'hotel-1',
|
||||
name: '智念空间',
|
||||
city: '杭州',
|
||||
role: 'manager' as const,
|
||||
permissions: [],
|
||||
ota: [],
|
||||
};
|
||||
|
||||
function renderSidebar(initialEntry = '/chat') {
|
||||
return render(
|
||||
<MemoryRouter initialEntries={[initialEntry]}>
|
||||
<Sidebar />
|
||||
</MemoryRouter>,
|
||||
);
|
||||
}
|
||||
|
||||
function getTestIdOrder(): string[] {
|
||||
const sidebar = screen.getByTestId('sidebar');
|
||||
return [...sidebar.querySelectorAll('[data-testid]')]
|
||||
.map((element) => element.getAttribute('data-testid'))
|
||||
.filter((value): value is string => Boolean(value));
|
||||
}
|
||||
|
||||
describe('Sidebar layout', () => {
|
||||
beforeEach(async () => {
|
||||
window.localStorage.clear();
|
||||
await i18n.changeLanguage('zh');
|
||||
useSettingsStore.setState({
|
||||
sidebarCollapsed: false,
|
||||
devModeUnlocked: false,
|
||||
});
|
||||
useGatewayStore.setState({
|
||||
status: { state: 'stopped', port: 18789, gatewayReady: false },
|
||||
});
|
||||
useYinianStore.setState({
|
||||
status: 'authenticated',
|
||||
session: {
|
||||
authenticated: true,
|
||||
user: { id: 'user-1', name: '王管理员' },
|
||||
hotels: [hotel],
|
||||
currentHotelId: hotel.id,
|
||||
accessTokenExpiresAt: 100,
|
||||
},
|
||||
config: {
|
||||
serverTime: 1,
|
||||
user: { id: 'user-1', name: '王管理员' },
|
||||
hotel,
|
||||
hotels: [hotel],
|
||||
entitlements: [],
|
||||
notificationChannels: [],
|
||||
featureFlags: {},
|
||||
uiPolicy: { defaultPage: 'today', showAdvancedSettings: false },
|
||||
},
|
||||
error: null,
|
||||
});
|
||||
useChatStore.setState({
|
||||
currentSessionKey: 'agent:main:main',
|
||||
currentAgentId: 'main',
|
||||
sessions: [{ key: 'agent:main:main', displayName: 'main' }],
|
||||
messages: [],
|
||||
sessionLabels: {},
|
||||
sessionLastActivity: {},
|
||||
sending: false,
|
||||
activeRunId: null,
|
||||
activeRunSessionKey: null,
|
||||
streamingText: '',
|
||||
streamingMessage: null,
|
||||
streamingTools: [],
|
||||
pendingFinal: false,
|
||||
lastUserMessageAt: null,
|
||||
pendingToolImages: [],
|
||||
error: null,
|
||||
loading: false,
|
||||
});
|
||||
useCronStore.setState({
|
||||
jobs: Array.from({ length: 6 }, (_, index) => ({
|
||||
id: `cron-${index + 1}`,
|
||||
name: `快捷任务 ${index + 1}`,
|
||||
message: `执行快捷任务 ${index + 1}`,
|
||||
schedule: '0 9 * * *',
|
||||
enabled: true,
|
||||
createdAt: '2026-05-13T00:00:00.000Z',
|
||||
updatedAt: '2026-05-13T00:00:00.000Z',
|
||||
agentId: 'main',
|
||||
})),
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
useTaskCenterStore.setState({
|
||||
scheduledBindings: {},
|
||||
runRecords: [],
|
||||
pinnedTaskIds: ['cron-1', 'cron-2', 'cron-3', 'cron-4', 'cron-5', 'cron-6'],
|
||||
});
|
||||
});
|
||||
|
||||
it('places chat first, keeps pinned tasks under task center, and keeps account identity in the footer', () => {
|
||||
renderSidebar();
|
||||
|
||||
const order = getTestIdOrder();
|
||||
const indexOf = (testId: string) => order.indexOf(testId);
|
||||
|
||||
expect(order[0]).toBe('sidebar-new-chat');
|
||||
expect(indexOf('sidebar-new-chat')).toBeLessThan(indexOf('sidebar-collapse-toggle'));
|
||||
expect(indexOf('sidebar-collapse-toggle')).toBeLessThan(indexOf('sidebar-chat-history'));
|
||||
expect(indexOf('sidebar-new-chat')).toBeLessThan(indexOf('sidebar-chat-history'));
|
||||
expect(indexOf('sidebar-chat-history')).toBeLessThan(indexOf('sidebar-nav-tasks'));
|
||||
expect(indexOf('sidebar-nav-tasks')).toBeLessThan(indexOf('sidebar-pinned-task-cron-1'));
|
||||
expect(indexOf('sidebar-pinned-task-cron-5')).toBeLessThan(indexOf('sidebar-pinned-task-more'));
|
||||
expect(indexOf('sidebar-pinned-task-more')).toBeLessThan(indexOf('sidebar-nav-app-center'));
|
||||
expect(indexOf('sidebar-nav-app-center')).toBeLessThan(indexOf('sidebar-nav-knowledge'));
|
||||
expect(indexOf('sidebar-nav-knowledge')).toBeLessThan(indexOf('sidebar-account-summary'));
|
||||
expect(indexOf('sidebar-account-summary')).toBeLessThan(indexOf('sidebar-account-identity'));
|
||||
expect(indexOf('sidebar-account-identity')).toBeLessThan(indexOf('sidebar-nav-settings'));
|
||||
expect(screen.queryByTestId('sidebar-pinned-task-cron-6')).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('sidebar-pinned-task-more')).toHaveTextContent('查看更多 +1');
|
||||
expect(screen.getByTestId('sidebar-pinned-task-more')).toHaveAttribute('href', '/tasks');
|
||||
const newChat = screen.getByTestId('sidebar-new-chat');
|
||||
expect(newChat).toHaveAttribute('title', '新对话');
|
||||
expect(newChat.className).toContain('backdrop-blur-md');
|
||||
expect(screen.getByTestId('sidebar-collapse-toggle')).toHaveAttribute('title', '收起侧栏');
|
||||
expect(screen.getByTestId('sidebar-chat-history')).toHaveAttribute('title', '历史会话');
|
||||
expect(screen.getByTestId('sidebar-nav-tasks')).toHaveAttribute('title', '任务中心');
|
||||
expect(screen.getByTestId('sidebar-pinned-task-cron-1')).toHaveAttribute('title', '快捷任务 1');
|
||||
expect(screen.getByTestId('sidebar-account-summary')).toContainElement(screen.getByTestId('sidebar-account-identity'));
|
||||
expect(screen.getByTestId('sidebar-account-summary')).toContainElement(screen.getByTestId('sidebar-nav-settings'));
|
||||
expect(screen.getByTestId('sidebar-account-workspace')).toHaveTextContent('智念空间');
|
||||
expect(screen.getByTestId('sidebar-account-user')).toHaveTextContent('王管理员');
|
||||
expect(screen.queryByText('对话')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('任务')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('快捷触发')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('快速使用')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('hides pinned quick tasks when collapsed and keeps hover titles on icon buttons', () => {
|
||||
useSettingsStore.setState({
|
||||
sidebarCollapsed: true,
|
||||
devModeUnlocked: false,
|
||||
});
|
||||
|
||||
renderSidebar();
|
||||
|
||||
expect(screen.queryByTestId('sidebar-pinned-task-cron-1')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('sidebar-pinned-task-more')).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('sidebar-new-chat')).toHaveAttribute('title', '新对话');
|
||||
expect(screen.getByTestId('sidebar-collapse-toggle')).toHaveAttribute('title', '展开侧栏');
|
||||
expect(screen.getByTestId('sidebar-chat-history')).toHaveAttribute('title', '历史会话');
|
||||
expect(screen.getByTestId('sidebar-nav-tasks')).toHaveAttribute('title', '任务中心');
|
||||
expect(screen.getByTestId('sidebar-nav-settings')).toHaveAttribute('title', '设置');
|
||||
});
|
||||
|
||||
it('does not mark history active just because a new chat is open', () => {
|
||||
renderSidebar('/chat');
|
||||
|
||||
const historyButton = screen.getByTestId('sidebar-chat-history');
|
||||
expect(historyButton).toHaveAttribute('aria-expanded', 'false');
|
||||
expect(historyButton.className).not.toContain('ring-[#D5E8F3]/80');
|
||||
|
||||
fireEvent.click(historyButton);
|
||||
|
||||
expect(historyButton).toHaveAttribute('aria-expanded', 'true');
|
||||
expect(historyButton.className).toContain('ring-[#D5E8F3]/80');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user