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');
});
});