import { renderToStaticMarkup } from 'react-dom/server'; import { describe, expect, it } from 'vitest'; import type { ModelLoadProgress, ModelShardProgress } from '../../lib/contracts'; import { ComposerActivity, describeLoadProgress, overallLoadProgress } from './ComposerActivity'; function shard(index: number, state: ModelShardProgress['state']): ModelShardProgress { return { index, path: `shard-${index + 1}.gguf`, loadedBytes: state === 'queued' ? 0 : 100, verifiedBytes: state === 'complete' || state === 'cached' ? 100 : 0, totalBytes: 100, state, }; } function progress(overrides: Partial = {}): ModelLoadProgress { return { modelId: 'bonsai-27b', modelLabel: 'Bonsai 27B', stage: 'download', stageProgress: 0.5, downloadedBytes: 400, totalBytes: 800, residentBytes: 0, nativeStage: null, shards: [ shard(0, 'complete'), shard(1, 'downloading'), ...Array.from({ length: 6 }, (_, index) => shard(index + 2, 'queued')), ], ...overrides, }; } describe('ComposerActivity', () => { it('combines the load pipeline into one weighted overall progress value', () => { expect(overallLoadProgress(progress())).toBeCloseTo(0.39625); expect(overallLoadProgress(progress({ stage: 'cache', stageProgress: 0.2 }))).toBeCloseTo(0.39625); expect(overallLoadProgress(progress({ stage: 'load', stageProgress: 0.5 }))).toBeCloseTo(0.95); expect(overallLoadProgress(progress({ stage: 'ready' }))).toBe(1); }); it('annotates the active shard and total ready shard count', () => { expect(describeLoadProgress(progress())).toEqual({ label: 'Downloading shard 2 of 8', detail: '1 of 8 shards ready ยท 400 B / 800 B', }); }); it('renders exactly one progressbar during load and disappears afterwards', () => { const loading = renderToStaticMarkup( , ); expect(loading.match(/role="progressbar"/g)).toHaveLength(1); expect(loading).not.toContain('Model transfer'); expect(loading).not.toContain('Load pipeline'); const ready = renderToStaticMarkup( , ); expect(ready).toBe(''); }); });