import { renderToStaticMarkup } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; import type { ModelLoadProgress, ModelOption } from '../../lib/contracts'; import { ChatSurface } from './ChatSurface'; const model: ModelOption = { id: 'bonsai-1.7b', manifestId: '1_7b', label: 'Bonsai 1.7B', architectureLabel: 'Qwen3 dense', parameters: '1.7B', runtimeLabel: 'WebGPU ยท WASM fallback', footprint: '237 MiB', availability: 'loaded', contextLimit: 32_768, defaultContext: 4_096, }; const progress: ModelLoadProgress = { modelId: model.id, modelLabel: model.label, stage: 'ready', stageProgress: 1, downloadedBytes: 1, totalBytes: 1, residentBytes: 1, nativeStage: null, shards: [], }; describe('ChatSurface message actions', () => { it('puts copy and role-specific regeneration controls under messages', () => { const html = renderToStaticMarkup( undefined} onDismissError={() => undefined} onRetryShard={() => undefined} onSend={() => undefined} onRegenerate={() => undefined} onEditUserMessage={() => undefined} onCancel={() => undefined} onToolsEnabledChange={() => undefined} onOpenConversationList={() => undefined} onOpenSettings={() => undefined} />, ); expect(html.match(/aria-label="Copy message"/g)).toHaveLength(2); expect(html).toContain('aria-label="Regenerate from this message"'); expect(html).toContain('aria-label="Regenerate this response"'); expect(html).toContain('aria-label="Edit message and regenerate response"'); expect(html).not.toContain('Regenerate last'); expect(html).toContain('aria-label="Show available tools"'); expect(html).toContain('html_artifact'); expect(html).toContain('artifact_update'); expect(html).toContain('bar_chart'); expect(html).toContain('pie_chart'); expect(html).toContain('web_search'); expect(html).toContain('Network tools ask before sending a query.'); }); it('keeps text visible and identifies a structured tool call while streaming', () => { const html = renderToStaticMarkup( undefined} onDismissError={() => undefined} onRetryShard={() => undefined} onSend={() => undefined} onRegenerate={() => undefined} onEditUserMessage={() => undefined} onCancel={() => undefined} onToolsEnabledChange={() => undefined} onOpenConversationList={() => undefined} onOpenSettings={() => undefined} />, ); expect(html).toContain('Visible streamed text'); expect(html).toContain('Generating html_artifact tool call'); expect(html).toContain('html_artifact'); expect(html).toContain('12,345 chars'); expect(html.match(/stream-cursor/g)).toHaveLength(2); }); it('renders generated artifacts inline with HTML and Rendered tabs', () => { const html = renderToStaticMarkup( Counter', sandboxedSource: '
Counter
', runtimeToken: 'artifact-one-runtime', createdAt: 1, }], }]} streamState="complete" modelLoadProgress={progress} toolsEnabled runtimeStatus="Ready" error={null} shardRetry={null} theme="light" onLoadModel={() => undefined} onDismissError={() => undefined} onRetryShard={() => undefined} onSend={() => undefined} onRegenerate={() => undefined} onEditUserMessage={() => undefined} onCancel={() => undefined} onToolsEnabledChange={() => undefined} onOpenConversationList={() => undefined} onOpenSettings={() => undefined} />, ); expect(html).toContain('id="artifact-artifact-one"'); expect(html).toContain('role="tab" aria-selected="true"'); expect(html).toContain('>HTML'); expect(html).toContain('>Rendered'); expect(html).toContain('<main>Counter</main>'); expect(html).not.toContain(' { const html = renderToStaticMarkup( Quarterly sales', sandboxedSource: '
Quarterly sales
', runtimeToken: 'artifact-one-runtime', createdAt: 1, }], }]} streamState="complete" modelLoadProgress={progress} toolsEnabled runtimeStatus="Ready" error={null} shardRetry={null} theme="light" onLoadModel={() => undefined} onDismissError={() => undefined} onRetryShard={() => undefined} onSend={() => undefined} onRegenerate={() => undefined} onEditUserMessage={() => undefined} onCancel={() => undefined} onToolsEnabledChange={() => undefined} onOpenConversationList={() => undefined} onOpenSettings={() => undefined} />, ); const before = html.indexOf('Before the chart.'); const tool = html.indexOf('bar_chart'); const artifact = html.indexOf('id="artifact-artifact-one"'); const after = html.indexOf('After the chart.'); expect(before).toBeGreaterThan(-1); expect(tool).toBeGreaterThan(before); expect(artifact).toBeGreaterThan(tool); expect(after).toBeGreaterThan(artifact); }); });