Files
NianToB/tests/unit/today-page.test.tsx

207 lines
6.4 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import { Today } from '@/pages/Today';
import { useYinianStore } from '@/stores/yinian';
import { useYinianSkillsStore } from '@/stores/yinian-skills';
import { useSkillsStore } from '@/stores/skills';
import type { YinianConfigSnapshot, YinianLocalSkill } from '../../shared/yinian';
const hotelHangzhou = {
id: 'workspace_hangzhou_ops',
name: '智念企业组织空间',
brand: '智念',
city: '杭州',
role: 'manager' as const,
permissions: ['dashboard.read', 'skills.sync'],
ota: [],
};
const hotelShanghai = {
id: 'workspace_shanghai_growth',
name: '智念增长组织空间',
city: '上海',
role: 'viewer' as const,
permissions: ['dashboard.read'],
ota: [],
};
function createConfig(overrides: Partial<YinianConfigSnapshot> = {}): YinianConfigSnapshot {
return {
serverTime: 1,
user: { id: 'user_1', name: '王管理员' },
hotel: hotelHangzhou,
hotels: [hotelHangzhou, hotelShanghai],
entitlements: [],
notificationChannels: [],
featureFlags: {},
uiPolicy: { defaultPage: 'today', showAdvancedSettings: false },
...overrides,
};
}
function createLocalSkill(overrides: Partial<YinianLocalSkill>): YinianLocalSkill {
return {
skillId: 'daily-report',
name: '日报生成助手',
version: '1.0.0',
enabled: true,
installedAt: 1,
lastSyncedAt: Date.now() - 5 * 60_000,
status: 'installed',
source: 'mock',
...overrides,
};
}
describe('Today page', () => {
beforeEach(() => {
vi.clearAllMocks();
useYinianStore.setState({
status: 'authenticated',
session: {
authenticated: true,
user: { id: 'user_1', name: '王管理员' },
hotels: [hotelHangzhou, hotelShanghai],
currentHotelId: hotelHangzhou.id,
accessTokenExpiresAt: 100,
},
config: createConfig(),
error: null,
});
useYinianSkillsStore.setState({
localSkills: [],
lastSync: null,
loading: false,
error: null,
});
useSkillsStore.setState({
skills: [],
loading: false,
error: null,
});
});
it('shows quick actions and plain status cards when workspace has no entitlements', () => {
render(<Today />);
expect(screen.getAllByText('智念企业组织空间').length).toBeGreaterThan(0);
expect(screen.getByText('开始对话')).toBeInTheDocument();
expect(screen.getByText('管理知识库')).toBeInTheDocument();
expect(screen.getByText('管理应用')).toBeInTheDocument();
expect(screen.queryByText('0/0')).not.toBeInTheDocument();
expect(screen.getAllByText('0 个').length).toBeGreaterThan(0);
expect(screen.queryByText('需要关注')).not.toBeInTheDocument();
expect(screen.queryByText('最近会话')).not.toBeInTheDocument();
});
it('summarizes entitlements with local registry readiness', () => {
useYinianStore.setState({
config: createConfig({
entitlements: [
{
skillId: 'daily-report',
name: '日报生成助手',
version: '1.0.0',
enabled: true,
category: 'reporting',
triggers: ['scheduled', 'manual'],
lastRunAt: Date.now() - 60 * 60_000,
},
{
skillId: 'data-check',
name: '数据检查助手',
version: '1.2.0',
enabled: true,
category: 'ota-monitoring',
triggers: ['scheduled'],
},
{
skillId: 'customer-reply-helper',
name: '客户回复助手',
version: '0.9.0',
enabled: false,
category: 'guest-comm',
triggers: ['manual'],
},
],
notificationChannels: [
{
id: 'ops',
kind: 'wecom',
label: '业务通知群',
recipient: 'room_1',
enabled: true,
source: 'nianxx',
},
],
}),
});
useYinianSkillsStore.setState({
localSkills: [
createLocalSkill({ skillId: 'daily-report', name: '日报生成助手', version: '1.0.0', status: 'skipped' }),
createLocalSkill({ skillId: 'data-check', name: '数据检查助手', version: '1.1.0', status: 'installed' }),
],
});
useSkillsStore.setState({
skills: [
{
id: 'daily-report',
name: '日报生成助手',
description: '',
enabled: true,
isCore: false,
source: 'openclaw-managed',
},
{
id: 'data-check',
name: '数据检查助手',
description: '',
enabled: true,
isCore: false,
source: 'openclaw-managed',
},
],
});
render(<Today />);
expect(screen.getByText('管理应用')).toBeInTheDocument();
expect(screen.queryByText('2/2')).not.toBeInTheDocument();
expect(screen.queryByText('下发 2 个 · 本地 2 个')).not.toBeInTheDocument();
expect(screen.getAllByText('2 个').length).toBeGreaterThanOrEqual(2);
expect(screen.queryByText(/待处理 1 个/)).not.toBeInTheDocument();
expect(screen.getAllByText(/日报生成助手/).length).toBeGreaterThan(0);
expect(screen.queryByText('数据检查助手 有新版本')).not.toBeInTheDocument();
});
it('updates displayed workspace and counters after hotel switch refreshes config', () => {
const { rerender } = render(<Today />);
expect(screen.getAllByText('智念企业组织空间').length).toBeGreaterThan(0);
useYinianStore.setState({
config: createConfig({
hotel: hotelShanghai,
entitlements: [
{
skillId: 'customer-reply-helper',
name: '客户回复助手',
version: '0.9.0',
enabled: true,
category: 'guest-comm',
triggers: ['manual'],
},
],
}),
});
useYinianSkillsStore.setState({ localSkills: [] });
rerender(<Today />);
expect(screen.getAllByText('智念增长组织空间').length).toBeGreaterThan(0);
expect(screen.queryByText('1/0')).not.toBeInTheDocument();
expect(screen.getByText('客户回复助手')).toBeInTheDocument();
expect(screen.queryByText(/待处理 1 个/)).not.toBeInTheDocument();
expect(screen.queryByText('智念企业组织空间')).not.toBeInTheDocument();
});
});