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([]); }); });