import { render, screen, waitFor } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { Sessions } from '@/pages/Sessions'; import { useOpencodeStore } from '@/stores/opencode'; const hostApiFetchMock = vi.fn(); vi.mock('@/lib/host-api', () => ({ hostApiFetch: (...args: unknown[]) => hostApiFetchMock(...args), ensureHostApiToken: vi.fn().mockResolvedValue('test-token'), })); vi.mock('@/lib/api-client', () => ({ invokeIpc: vi.fn(), })); describe('Sessions page', () => { beforeEach(() => { vi.clearAllMocks(); useOpencodeStore.setState({ status: { state: 'stopped', port: 4096 }, health: null, runtimeConfigSummary: null, projects: [], activeProject: null, sessions: [], sessionsByProjectId: {}, selectedSessionId: null, sessionStatuses: {}, sessionMessages: [], sessionMessagesBySessionId: {}, streamingMessage: null, streamingMessagesBySessionId: {}, streamingTools: [], streamingToolsBySessionId: {}, sendingSessionId: null, sendingSessionIds: {}, queuedSessionPrompts: {}, runtimeAutoStartAttempted: false, loading: false, error: null, }); }); it('renders sessions for the active project without exposing the runtime brand', async () => { const activeProject = { id: 'prj_1', path: 'D:/repo/packages/ui', name: 'ui', createdAt: '2026-05-12T00:00:00.000Z', updatedAt: '2026-05-12T00:00:00.000Z', lastOpenedAt: '2026-05-12T00:00:00.000Z', }; hostApiFetchMock.mockImplementation(async (path: string) => { if (path === '/api/opencode/projects') { return { projects: [activeProject], activeProject }; } if (path === '/api/opencode/status') { return { state: 'running', port: 4096, url: 'http://127.0.0.1:4096' }; } if (path === '/api/opencode/sessions') { return { sessions: [ { id: 'ses_1', title: 'Implement login', updatedAt: '2026-05-12T08:30:00.000Z', }, ], }; } throw new Error(`Unexpected path ${path}`); }); render(); await waitFor(() => expect(screen.getByText('Implement login')).toBeInTheDocument()); expect(screen.getByText('D:/repo/packages/ui')).toBeInTheDocument(); expect(document.body.textContent).not.toMatch(/opencode/i); expect(hostApiFetchMock).toHaveBeenCalledWith('/api/opencode/sessions'); }); it('shows a project selection empty state when no project is active', async () => { hostApiFetchMock.mockImplementation(async (path: string) => { if (path === '/api/opencode/projects') { return { projects: [], activeProject: null }; } if (path === '/api/opencode/status') { return { state: 'running', port: 4096, url: 'http://127.0.0.1:4096' }; } throw new Error(`Unexpected path ${path}`); }); render(); await waitFor(() => expect(screen.getByText('Select a project to view sessions')).toBeInTheDocument()); expect(hostApiFetchMock).not.toHaveBeenCalledWith('/api/opencode/sessions'); }); });