Files
NianToB/tests/unit/yinian-store.test.ts
2026-05-12 19:44:44 +08:00

150 lines
5.2 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest';
import { useYinianStore } from '@/stores/yinian';
import { useYinianSkillsStore } from '@/stores/yinian-skills';
const session = {
authenticated: true as const,
user: { id: 'user_1', name: '王管理员' },
hotels: [
{
id: 'workspace_hangzhou_ops',
name: '智念企业组织空间',
city: '杭州',
role: 'manager' as const,
permissions: ['hotel:view'],
ota: [],
},
{
id: 'workspace_shanghai_growth',
name: '智念增长组织空间',
city: '上海',
role: 'viewer' as const,
permissions: ['hotel:view'],
ota: [],
},
],
currentHotelId: 'workspace_hangzhou_ops',
accessTokenExpiresAt: 100,
};
const config = {
serverTime: 1,
user: session.user,
hotel: session.hotels[0],
hotels: session.hotels,
entitlements: [],
notificationChannels: [],
featureFlags: {},
uiPolicy: { defaultPage: 'today' as const, showAdvancedSettings: false },
};
describe('useYinianStore', () => {
beforeEach(() => {
useYinianStore.setState({
status: 'idle',
session: { authenticated: false },
config: null,
error: null,
});
useYinianSkillsStore.setState({
localSkills: [],
lastSync: null,
loading: false,
error: null,
});
vi.mocked(window.yinian.auth.restoreSession).mockReset();
vi.mocked(window.yinian.auth.getSessionState).mockReset();
vi.mocked(window.yinian.auth.loginWithPassword).mockReset();
vi.mocked(window.yinian.auth.logout).mockReset();
vi.mocked(window.yinian.app.getConfig).mockReset();
vi.mocked(window.yinian.app.switchHotel).mockReset();
vi.mocked(window.yinian.skills.getRegistry).mockReset();
});
it('restores session and loads matching registry on init', async () => {
vi.mocked(window.yinian.auth.restoreSession).mockResolvedValueOnce(session);
vi.mocked(window.yinian.app.getConfig).mockResolvedValueOnce(config);
vi.mocked(window.yinian.skills.getRegistry).mockResolvedValueOnce({
hotelId: 'workspace_hangzhou_ops',
updatedAt: 10,
skills: [],
});
await useYinianStore.getState().init();
expect(useYinianStore.getState().status).toBe('authenticated');
expect(window.yinian.skills.getRegistry).toHaveBeenCalledWith('workspace_hangzhou_ops');
});
it('falls back to session state when restoreSession handler is not registered yet', async () => {
vi.mocked(window.yinian.auth.restoreSession).mockRejectedValueOnce(
new Error("Error invoking remote method 'yinian:auth:restoreSession': Error: No handler registered for 'yinian:auth:restoreSession'"),
);
vi.mocked(window.yinian.auth.getSessionState).mockResolvedValueOnce({ authenticated: false });
await useYinianStore.getState().init();
expect(window.yinian.auth.getSessionState).toHaveBeenCalled();
expect(useYinianStore.getState().status).toBe('unauthenticated');
expect(useYinianStore.getState().error).toBeNull();
});
it('opens login when yinian auth handlers are absent in a mismatched build', async () => {
vi.mocked(window.yinian.auth.restoreSession).mockRejectedValueOnce(
new Error("Error invoking remote method 'yinian:auth:restoreSession': Error: No handler registered for 'yinian:auth:restoreSession'"),
);
vi.mocked(window.yinian.auth.getSessionState).mockRejectedValueOnce(
new Error("Error invoking remote method 'yinian:auth:getSessionState': Error: No handler registered for 'yinian:auth:getSessionState'"),
);
await useYinianStore.getState().init();
expect(useYinianStore.getState().status).toBe('unauthenticated');
expect(useYinianStore.getState().session.authenticated).toBe(false);
expect(useYinianStore.getState().error).toBeNull();
});
it('switches workspace and refreshes registry for the new hotel', async () => {
const switched = { ...session, currentHotelId: 'workspace_shanghai_growth' };
vi.mocked(window.yinian.app.switchHotel).mockResolvedValueOnce(switched);
vi.mocked(window.yinian.app.getConfig).mockResolvedValueOnce({
...config,
hotel: session.hotels[1],
});
vi.mocked(window.yinian.skills.getRegistry).mockResolvedValueOnce({
hotelId: 'workspace_shanghai_growth',
updatedAt: 10,
skills: [],
});
useYinianStore.setState({ session, status: 'authenticated', config });
await useYinianStore.getState().switchHotel('workspace_shanghai_growth');
expect(useYinianStore.getState().session.authenticated).toBe(true);
expect(window.yinian.skills.getRegistry).toHaveBeenCalledWith('workspace_shanghai_growth');
});
it('resets yinian skill state on logout', async () => {
vi.mocked(window.yinian.auth.logout).mockResolvedValueOnce({ authenticated: false });
useYinianSkillsStore.setState({
localSkills: [
{
skillId: 'daily-report',
name: '日报生成助手',
version: '0.1.0',
enabled: true,
installedAt: 1,
lastSyncedAt: 2,
status: 'installed',
source: 'mock',
},
],
});
await useYinianStore.getState().logout();
expect(useYinianStore.getState().session.authenticated).toBe(false);
expect(useYinianSkillsStore.getState().localSkills).toEqual([]);
});
});