Spaces:
Sleeping
Sleeping
| import { describe, expect, it, vi } from 'vitest'; | |
| import { | |
| formatBootProgressLabel, | |
| resolveBootProgressBar, | |
| softWaitRatio, | |
| softStepRatio, | |
| withTimeout, | |
| waitForBackendHealthy, | |
| startProgressTicker, | |
| withSoftStepProgress, | |
| } from '../src/ui/BootProgress.js'; | |
| describe('BootProgress helpers', () => { | |
| it('formatBootProgressLabel prefers statusText then k/n label', () => { | |
| expect(formatBootProgressLabel({ statusText: '1/3 Encoding…' })).toBe('1/3 Encoding…'); | |
| expect(formatBootProgressLabel({ step: 2, total: 4, label: 'UMAP' })).toBe('2/4 UMAP'); | |
| expect(formatBootProgressLabel({ label: 'Connecting…' })).toBe('Connecting…'); | |
| expect(formatBootProgressLabel(null)).toBe(''); | |
| }); | |
| it('resolveBootProgressBar maps ratio and indeterminate', () => { | |
| expect(resolveBootProgressBar({ ratio: 0.66 })).toEqual({ | |
| pct: 66, | |
| indeterminate: false, | |
| }); | |
| expect(resolveBootProgressBar({ step: 1, total: 4 })).toEqual({ | |
| pct: 25, | |
| indeterminate: false, | |
| }); | |
| expect(resolveBootProgressBar({ | |
| statusText: 'Connecting…', | |
| indeterminate: true, | |
| })).toEqual({ pct: 0, indeterminate: true }); | |
| }); | |
| it('softWaitRatio climbs then caps under 1', () => { | |
| expect(softWaitRatio(0)).toBe(0); | |
| expect(softWaitRatio(45_000, 90_000)).toBeCloseTo(0.5); | |
| expect(softWaitRatio(200_000, 90_000)).toBe(0.92); | |
| }); | |
| it('softStepRatio stays inside the step band and climbs', () => { | |
| const early = softStepRatio(1, 3, 0, 30_000); | |
| const mid = softStepRatio(1, 3, 15_000, 30_000); | |
| const late = softStepRatio(1, 3, 60_000, 30_000); | |
| expect(early).toBeCloseTo(0); | |
| expect(mid).toBeGreaterThan(early); | |
| expect(mid).toBeLessThan(1 / 3); | |
| expect(late).toBeGreaterThan(mid); | |
| expect(late).toBeLessThan(1 / 3); | |
| }); | |
| it('withTimeout resolves fallback when promise is slow', async () => { | |
| const slow = new Promise(() => {}); | |
| const result = await withTimeout(slow, 20, { ok: false }); | |
| expect(result).toEqual({ ok: false }); | |
| }); | |
| it('withTimeout returns promise value when fast', async () => { | |
| const result = await withTimeout(Promise.resolve(42), 100, 0); | |
| expect(result).toBe(42); | |
| }); | |
| it('startProgressTicker fires while a hung await is in flight', async () => { | |
| const ticks = []; | |
| const stop = startProgressTicker(() => ticks.push(Date.now()), 40); | |
| await new Promise((r) => setTimeout(r, 130)); | |
| stop(); | |
| expect(ticks.length).toBeGreaterThanOrEqual(3); | |
| }); | |
| it('waitForBackendHealthy polls until ok and reports live progress during hung checks', async () => { | |
| let n = 0; | |
| const ticks = []; | |
| const health = await waitForBackendHealthy({ | |
| attemptTimeoutMs: 80, | |
| gapMs: 10, | |
| tickMs: 30, | |
| maxWaitMs: 3000, | |
| checkHealth: async () => { | |
| n += 1; | |
| // First two attempts hang past abort window → ticker must still move. | |
| if (n < 3) { | |
| await new Promise(() => {}); | |
| } | |
| return { ok: true, data: { model: 'x' } }; | |
| }, | |
| onProgress: (p) => ticks.push({ text: p.statusText, ratio: p.ratio }), | |
| }); | |
| expect(health.ok).toBe(true); | |
| expect(n).toBeGreaterThanOrEqual(3); | |
| expect(ticks.length).toBeGreaterThanOrEqual(4); | |
| expect(ticks[0].text).toMatch(/Waiting for backend/); | |
| const ratios = ticks.map((t) => t.ratio); | |
| expect(Math.max(...ratios)).toBeGreaterThan(ratios[0]); | |
| }); | |
| it('withSoftStepProgress advances ratio while work runs', async () => { | |
| const ticks = []; | |
| const result = await withSoftStepProgress( | |
| { | |
| step: 2, | |
| total: 4, | |
| label: 'UMAP', | |
| expectMs: 200, | |
| tickMs: 30, | |
| onProgress: (p) => ticks.push(p.ratio), | |
| }, | |
| async () => { | |
| await new Promise((r) => setTimeout(r, 100)); | |
| return 'done'; | |
| }, | |
| ); | |
| expect(result).toBe('done'); | |
| expect(ticks.length).toBeGreaterThanOrEqual(2); | |
| expect(ticks[0]).toBeGreaterThanOrEqual(0.25); | |
| expect(ticks[0]).toBeLessThan(0.5); | |
| expect(Math.max(...ticks)).toBeGreaterThan(ticks[0]); | |
| expect(Math.max(...ticks)).toBeLessThan(0.5); | |
| }); | |
| }); | |