const test = require('node:test'); const assert = require('node:assert/strict'); const { layaFallbackMessage, present } = require('../public/js/services/liveAnalysisPresentation.js'); test('presents determinate channel analysis progress', () => { const view = present({ status: 'building', phase: 'projecting', processed: 25, total: 100 }); assert.equal(view.busy, true); assert.equal(view.statusLabel, 'Building channel catalog…'); assert.equal(view.progressIndeterminate, false); assert.equal(view.progressPercent, 25); assert.equal(view.progressText, '25 of 100 channels · 25%'); }); test('presents Laya identity progress using AI batch counters', () => { const view = present({ status: 'building', phase: 'laya_identity', layaProcessed: 3, layaTotal: 8, processed: 0, total: 39348 }); assert.equal(view.statusLabel, 'Analyzing with local AI…'); assert.equal(view.progressIndeterminate, false); assert.equal(view.progressPercent, 38); assert.equal(view.progressText, 'AI batch 3 of 8 · 38%'); }); test('presents local Laya language batch progress after projection', () => { const view = present({ status: 'building', phase: 'laya_language', languageProcessed: 5, languageTotal: 10 }); assert.equal(view.statusLabel, 'Detecting stream languages…'); assert.equal(view.progressIndeterminate, false); assert.equal(view.progressPercent, 50); assert.equal(view.progressText, 'Language batch 5 of 10 · 50%'); }); test('presents indeterminate progress when totals are unavailable', () => { const view = present({ status: 'queued', processed: null, total: null }); assert.equal(view.busy, true); assert.equal(view.progressIndeterminate, true); assert.equal(view.progressPercent, null); assert.equal(view.progressText, 'In progress…'); assert.equal(view.buttonLabel, 'Analyze channels'); assert.equal(present({ status: 'running', processed: null, total: 100 }).progressIndeterminate, true); }); test('presents writing as an indeterminate finalization phase', () => { const view = present({ status: 'building', phase: 'writing', processed: 39348, total: 39348 }); assert.equal(view.statusLabel, 'Saving channel catalog…'); assert.equal(view.progressIndeterminate, true); assert.equal(view.progressPercent, null); assert.equal(view.progressText, 'Finalizing…'); }); test('presents success and retry states', () => { assert.deepEqual( { label: present({ status: 'success', projectedCount: 12 }).statusLabel, button: present({ status: 'success' }).buttonLabel }, { label: 'Analysis complete', button: 'Analyze again' } ); const failed = present({ status: 'error', error: 'Safe projection error' }); assert.equal(failed.statusLabel, 'Analysis failed'); assert.equal(failed.buttonLabel, 'Try again'); assert.equal(failed.errorDetail, 'Safe projection error'); }); test('mentions Standard fallback only for unavailable active Local AI modes', () => { assert.equal(layaFallbackMessage('algo', { modelPresent: false, runtimeAvailable: false }), ''); assert.equal(layaFallbackMessage('hybrid', { modelPresent: true, runtimeAvailable: true }), ''); assert.equal( layaFallbackMessage('laya', { modelPresent: true, runtimeAvailable: false }), 'Local AI is unavailable. Standard channel matching will be used for this analysis.' ); });