import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; function readMainSource(): string { return fs.readFileSync(path.join(process.cwd(), 'src/main.ts'), 'utf8'); } test('manual watched session action starts immersion tracker before marking watched', () => { const source = readMainSource(); const actionBlock = source.match( /markActiveVideoWatched:\s*async\s*\(\)\s*=>\s*\{(?[\s\S]*?)\}\s*,/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /ensureImmersionTrackerStarted\(\);/); assert.ok( actionBlock.indexOf('ensureImmersionTrackerStarted();') < actionBlock.indexOf('markActiveVideoWatched()'), ); }); test('media path changes clear rendered subtitle state without clearing same-youtube parsed cues', () => { const source = readMainSource(); const actionBlock = source.match( /updateCurrentMediaPath:\s*\(path\)\s*=>\s*\{(?[\s\S]*?)autoplayReadyGate\.invalidatePendingAutoplayReadyFallbacks\(\);/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /appState\.currentSubText = '';/); assert.match(actionBlock, /appState\.currentSubAssText = '';/); assert.match(actionBlock, /appState\.currentSubtitleData = null;/); assert.match(actionBlock, /isSameYoutubeMediaPath\(/); assert.match(actionBlock, /if \(!preserveParsedSubtitleCues\)/); assert.match(actionBlock, /appState\.activeParsedSubtitleCues = \[\];/); assert.match(actionBlock, /appState\.activeParsedSubtitleSource = null;/); assert.match(actionBlock, /appState\.activeParsedSubtitleMediaPath = null;/); assert.match(actionBlock, /lastObservedTimePos = 0;/); assert.match(actionBlock, /broadcastToOverlayWindows\('subtitle:set',/); assert.match(actionBlock, /subtitleWsService\.broadcast\(/); assert.match(actionBlock, /annotationSubtitleWsService\.broadcast\(/); assert.ok( actionBlock.indexOf('appState.currentSubtitleData = null;') < actionBlock.indexOf("broadcastToOverlayWindows('subtitle:set'"), ); }); test('same media path updates do not reset autoplay ready fallback state', () => { const source = readMainSource(); const actionBlock = source.match( /updateCurrentMediaPath:\s*\(path\)\s*=>\s*\{(?[\s\S]*?)\n restoreMpvSubVisibility:/, )?.groups?.body; assert.ok(actionBlock); assert.match( actionBlock, /annotationSubtitleWsService\.broadcast\(resetSubtitlePayload, frequencyOptions\);\s+autoplayReadyGate\.invalidatePendingAutoplayReadyFallbacks\(\);\s+\}\s+currentMediaTokenizationGate\.updateCurrentMediaPath\(path\);/, ); }); test('manual visible overlay toggles suppress current-media autoplay release', () => { const source = readMainSource(); const actionBlock = source.match( /function toggleVisibleOverlay\(\): void \{(?[\s\S]*?)\n\}/, )?.groups?.body; assert.ok(actionBlock); assert.match(actionBlock, /autoplayReadyGate\.markCurrentMediaAutoplayReady\(\);/); assert.ok( actionBlock.indexOf('autoplayReadyGate.markCurrentMediaAutoplayReady();') < actionBlock.indexOf('toggleVisibleOverlayHandler();'), ); }); test('main process uses one shared mpv plugin runtime config helper', () => { const source = readMainSource(); assert.match(source, /function getMpvPluginRuntimeConfig\(\)/); assert.equal((source.match(/socketPath: appState\.mpvSocketPath/g) ?? []).length, 1); assert.equal( (source.match(/binaryPath: getResolvedConfig\(\)\.mpv\.subminerBinaryPath/g) ?? []).length, 0, ); }); test('subtitle sidebar snapshot prefers cached YouTube parsed cues before active-source parsing', () => { const source = readMainSource(); const snapshotBlock = source.match( /getSubtitleSidebarSnapshot:\s*async\s*\(\)\s*=>\s*\{(?[\s\S]*?const resolvedSource = await resolveActiveSubtitleSidebarSourceHandler)/, )?.groups?.body; assert.ok(snapshotBlock); assert.match(snapshotBlock, /shouldUseCachedYoutubeParsedCues\(/); assert.match(snapshotBlock, /cachedMediaPath:\s*appState\.activeParsedSubtitleMediaPath/); assert.match(snapshotBlock, /cachedCueCount:\s*appState\.activeParsedSubtitleCues\.length/); assert.ok( snapshotBlock.indexOf('shouldUseCachedYoutubeParsedCues(') < snapshotBlock.indexOf('resolveActiveSubtitleSidebarSourceHandler'), ); });