mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-06-09 15:13:32 -07:00
447 lines
12 KiB
TypeScript
447 lines
12 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { runAppReadyRuntime } from './startup';
|
|
|
|
test('runAppReadyRuntime minimal startup skips Yomitan and first-run setup while still handling CLI args', async () => {
|
|
const calls: string[] = [];
|
|
|
|
await runAppReadyRuntime({
|
|
ensureDefaultConfigBootstrap: () => {
|
|
calls.push('bootstrap');
|
|
},
|
|
loadSubtitlePosition: () => {
|
|
calls.push('load-subtitle-position');
|
|
},
|
|
resolveKeybindings: () => {
|
|
calls.push('resolve-keybindings');
|
|
},
|
|
createMpvClient: () => {
|
|
calls.push('create-mpv');
|
|
},
|
|
reloadConfig: () => {
|
|
calls.push('reload-config');
|
|
},
|
|
getResolvedConfig: () => ({}),
|
|
getConfigWarnings: () => [],
|
|
logConfigWarning: () => {
|
|
calls.push('config-warning');
|
|
},
|
|
setLogLevel: () => {
|
|
calls.push('set-log-level');
|
|
},
|
|
initRuntimeOptionsManager: () => {
|
|
calls.push('init-runtime-options');
|
|
},
|
|
setSecondarySubMode: () => {
|
|
calls.push('set-secondary-sub-mode');
|
|
},
|
|
defaultSecondarySubMode: 'hover',
|
|
defaultWebsocketPort: 0,
|
|
defaultAnnotationWebsocketPort: 0,
|
|
defaultTexthookerPort: 0,
|
|
hasMpvWebsocketPlugin: () => false,
|
|
startSubtitleWebsocket: () => {
|
|
calls.push('subtitle-ws');
|
|
},
|
|
startAnnotationWebsocket: () => {
|
|
calls.push('annotation-ws');
|
|
},
|
|
startTexthooker: () => {
|
|
calls.push('texthooker');
|
|
},
|
|
log: () => {
|
|
calls.push('log');
|
|
},
|
|
createMecabTokenizerAndCheck: async () => {
|
|
calls.push('mecab');
|
|
},
|
|
createSubtitleTimingTracker: () => {
|
|
calls.push('subtitle-timing');
|
|
},
|
|
createImmersionTracker: () => {
|
|
calls.push('immersion');
|
|
},
|
|
startJellyfinRemoteSession: async () => {
|
|
calls.push('jellyfin');
|
|
},
|
|
loadYomitanExtension: async () => {
|
|
calls.push('load-yomitan');
|
|
},
|
|
handleFirstRunSetup: async () => {
|
|
calls.push('first-run');
|
|
},
|
|
prewarmSubtitleDictionaries: async () => {
|
|
calls.push('prewarm');
|
|
},
|
|
startBackgroundWarmups: () => {
|
|
calls.push('warmups');
|
|
},
|
|
texthookerOnlyMode: false,
|
|
shouldAutoInitializeOverlayRuntimeFromConfig: () => false,
|
|
setVisibleOverlayVisible: () => {
|
|
calls.push('visible-overlay');
|
|
},
|
|
initializeOverlayRuntime: () => {
|
|
calls.push('init-overlay');
|
|
},
|
|
handleInitialArgs: () => {
|
|
calls.push('handle-initial-args');
|
|
},
|
|
shouldUseMinimalStartup: () => true,
|
|
shouldSkipHeavyStartup: () => false,
|
|
});
|
|
|
|
assert.deepEqual(calls, ['bootstrap', 'reload-config', 'handle-initial-args']);
|
|
});
|
|
|
|
test('runAppReadyRuntime headless refresh bootstraps Anki runtime without UI startup', async () => {
|
|
const calls: string[] = [];
|
|
|
|
await runAppReadyRuntime({
|
|
ensureDefaultConfigBootstrap: () => {
|
|
calls.push('bootstrap');
|
|
},
|
|
loadSubtitlePosition: () => {
|
|
calls.push('load-subtitle-position');
|
|
},
|
|
resolveKeybindings: () => {
|
|
calls.push('resolve-keybindings');
|
|
},
|
|
createMpvClient: () => {
|
|
calls.push('create-mpv');
|
|
},
|
|
reloadConfig: () => {
|
|
calls.push('reload-config');
|
|
},
|
|
getResolvedConfig: () => ({}),
|
|
getConfigWarnings: () => [],
|
|
logConfigWarning: () => {
|
|
calls.push('config-warning');
|
|
},
|
|
setLogLevel: () => {
|
|
calls.push('set-log-level');
|
|
},
|
|
initRuntimeOptionsManager: () => {
|
|
calls.push('init-runtime-options');
|
|
},
|
|
setSecondarySubMode: () => {
|
|
calls.push('set-secondary-sub-mode');
|
|
},
|
|
defaultSecondarySubMode: 'hover',
|
|
defaultWebsocketPort: 0,
|
|
defaultAnnotationWebsocketPort: 0,
|
|
defaultTexthookerPort: 0,
|
|
hasMpvWebsocketPlugin: () => false,
|
|
startSubtitleWebsocket: () => {
|
|
calls.push('subtitle-ws');
|
|
},
|
|
startAnnotationWebsocket: () => {
|
|
calls.push('annotation-ws');
|
|
},
|
|
startTexthooker: () => {
|
|
calls.push('texthooker');
|
|
},
|
|
log: () => {
|
|
calls.push('log');
|
|
},
|
|
createMecabTokenizerAndCheck: async () => {
|
|
calls.push('mecab');
|
|
},
|
|
createSubtitleTimingTracker: () => {
|
|
calls.push('subtitle-timing');
|
|
},
|
|
createImmersionTracker: () => {
|
|
calls.push('immersion');
|
|
},
|
|
startJellyfinRemoteSession: async () => {
|
|
calls.push('jellyfin');
|
|
},
|
|
loadYomitanExtension: async () => {
|
|
calls.push('load-yomitan');
|
|
},
|
|
handleFirstRunSetup: async () => {
|
|
calls.push('first-run');
|
|
},
|
|
prewarmSubtitleDictionaries: async () => {
|
|
calls.push('prewarm');
|
|
},
|
|
startBackgroundWarmups: () => {
|
|
calls.push('warmups');
|
|
},
|
|
texthookerOnlyMode: false,
|
|
shouldAutoInitializeOverlayRuntimeFromConfig: () => false,
|
|
setVisibleOverlayVisible: () => {
|
|
calls.push('visible-overlay');
|
|
},
|
|
initializeOverlayRuntime: () => {
|
|
calls.push('init-overlay');
|
|
},
|
|
runHeadlessInitialCommand: async () => {
|
|
calls.push('run-headless-command');
|
|
},
|
|
handleInitialArgs: () => {
|
|
calls.push('handle-initial-args');
|
|
},
|
|
shouldRunHeadlessInitialCommand: () => true,
|
|
shouldUseMinimalStartup: () => false,
|
|
shouldSkipHeavyStartup: () => false,
|
|
});
|
|
|
|
assert.deepEqual(calls, [
|
|
'bootstrap',
|
|
'reload-config',
|
|
'init-runtime-options',
|
|
'run-headless-command',
|
|
]);
|
|
});
|
|
|
|
test('runAppReadyRuntime loads Yomitan before headless overlay fallback initialization', async () => {
|
|
const calls: string[] = [];
|
|
|
|
await runAppReadyRuntime({
|
|
ensureDefaultConfigBootstrap: () => {
|
|
calls.push('bootstrap');
|
|
},
|
|
loadSubtitlePosition: () => {
|
|
calls.push('load-subtitle-position');
|
|
},
|
|
resolveKeybindings: () => {
|
|
calls.push('resolve-keybindings');
|
|
},
|
|
createMpvClient: () => {
|
|
calls.push('create-mpv');
|
|
},
|
|
reloadConfig: () => {
|
|
calls.push('reload-config');
|
|
},
|
|
getResolvedConfig: () => ({}),
|
|
getConfigWarnings: () => [],
|
|
logConfigWarning: () => {},
|
|
setLogLevel: () => {},
|
|
initRuntimeOptionsManager: () => {
|
|
calls.push('init-runtime-options');
|
|
},
|
|
setSecondarySubMode: () => {},
|
|
defaultSecondarySubMode: 'hover',
|
|
defaultWebsocketPort: 0,
|
|
defaultAnnotationWebsocketPort: 0,
|
|
defaultTexthookerPort: 0,
|
|
hasMpvWebsocketPlugin: () => false,
|
|
startSubtitleWebsocket: () => {},
|
|
startAnnotationWebsocket: () => {},
|
|
startTexthooker: () => {},
|
|
log: () => {},
|
|
createMecabTokenizerAndCheck: async () => {},
|
|
createSubtitleTimingTracker: () => {
|
|
calls.push('subtitle-timing');
|
|
},
|
|
createImmersionTracker: () => {},
|
|
startJellyfinRemoteSession: async () => {},
|
|
loadYomitanExtension: async () => {
|
|
calls.push('load-yomitan');
|
|
},
|
|
handleFirstRunSetup: async () => {},
|
|
prewarmSubtitleDictionaries: async () => {},
|
|
startBackgroundWarmups: () => {},
|
|
texthookerOnlyMode: false,
|
|
shouldAutoInitializeOverlayRuntimeFromConfig: () => false,
|
|
setVisibleOverlayVisible: () => {},
|
|
initializeOverlayRuntime: () => {
|
|
calls.push('init-overlay');
|
|
},
|
|
handleInitialArgs: () => {
|
|
calls.push('handle-initial-args');
|
|
},
|
|
shouldRunHeadlessInitialCommand: () => true,
|
|
shouldUseMinimalStartup: () => false,
|
|
shouldSkipHeavyStartup: () => false,
|
|
});
|
|
|
|
assert.deepEqual(calls, [
|
|
'bootstrap',
|
|
'reload-config',
|
|
'init-runtime-options',
|
|
'create-mpv',
|
|
'subtitle-timing',
|
|
'load-yomitan',
|
|
'init-overlay',
|
|
'handle-initial-args',
|
|
]);
|
|
});
|
|
|
|
test('runAppReadyRuntime loads Yomitan before auto-initializing overlay runtime', async () => {
|
|
const calls: string[] = [];
|
|
|
|
await runAppReadyRuntime({
|
|
ensureDefaultConfigBootstrap: () => {
|
|
calls.push('bootstrap');
|
|
},
|
|
loadSubtitlePosition: () => {
|
|
calls.push('load-subtitle-position');
|
|
},
|
|
resolveKeybindings: () => {
|
|
calls.push('resolve-keybindings');
|
|
},
|
|
createMpvClient: () => {
|
|
calls.push('create-mpv');
|
|
},
|
|
reloadConfig: () => {
|
|
calls.push('reload-config');
|
|
},
|
|
getResolvedConfig: () => ({
|
|
websocket: { enabled: false },
|
|
annotationWebsocket: { enabled: false },
|
|
texthooker: { launchAtStartup: false },
|
|
}),
|
|
getConfigWarnings: () => [],
|
|
logConfigWarning: () => {},
|
|
setLogLevel: () => {
|
|
calls.push('set-log-level');
|
|
},
|
|
initRuntimeOptionsManager: () => {
|
|
calls.push('init-runtime-options');
|
|
},
|
|
setSecondarySubMode: () => {
|
|
calls.push('set-secondary-sub-mode');
|
|
},
|
|
defaultSecondarySubMode: 'hover',
|
|
defaultWebsocketPort: 0,
|
|
defaultAnnotationWebsocketPort: 0,
|
|
defaultTexthookerPort: 0,
|
|
hasMpvWebsocketPlugin: () => false,
|
|
startSubtitleWebsocket: () => {
|
|
calls.push('subtitle-ws');
|
|
},
|
|
startAnnotationWebsocket: () => {
|
|
calls.push('annotation-ws');
|
|
},
|
|
startTexthooker: () => {
|
|
calls.push('texthooker');
|
|
},
|
|
log: () => {
|
|
calls.push('log');
|
|
},
|
|
createMecabTokenizerAndCheck: async () => {},
|
|
createSubtitleTimingTracker: () => {
|
|
calls.push('subtitle-timing');
|
|
},
|
|
createImmersionTracker: () => {
|
|
calls.push('immersion');
|
|
},
|
|
startJellyfinRemoteSession: async () => {},
|
|
loadYomitanExtension: async () => {
|
|
calls.push('load-yomitan');
|
|
},
|
|
handleFirstRunSetup: async () => {
|
|
calls.push('first-run');
|
|
},
|
|
prewarmSubtitleDictionaries: async () => {},
|
|
startBackgroundWarmups: () => {
|
|
calls.push('warmups');
|
|
},
|
|
texthookerOnlyMode: false,
|
|
shouldAutoInitializeOverlayRuntimeFromConfig: () => true,
|
|
setVisibleOverlayVisible: () => {
|
|
calls.push('visible-overlay');
|
|
},
|
|
initializeOverlayRuntime: () => {
|
|
calls.push('init-overlay');
|
|
},
|
|
handleInitialArgs: () => {
|
|
calls.push('handle-initial-args');
|
|
},
|
|
shouldUseMinimalStartup: () => false,
|
|
shouldSkipHeavyStartup: () => false,
|
|
});
|
|
|
|
assert.ok(calls.indexOf('load-yomitan') !== -1);
|
|
assert.ok(calls.indexOf('init-overlay') !== -1);
|
|
assert.ok(calls.indexOf('load-yomitan') < calls.indexOf('init-overlay'));
|
|
});
|
|
|
|
test('runAppReadyRuntime reuses guarded Yomitan loader after scheduling startup warmups', async () => {
|
|
const calls: string[] = [];
|
|
|
|
await runAppReadyRuntime({
|
|
ensureDefaultConfigBootstrap: () => {
|
|
calls.push('bootstrap');
|
|
},
|
|
loadSubtitlePosition: () => {
|
|
calls.push('load-subtitle-position');
|
|
},
|
|
resolveKeybindings: () => {
|
|
calls.push('resolve-keybindings');
|
|
},
|
|
createMpvClient: () => {
|
|
calls.push('create-mpv');
|
|
},
|
|
reloadConfig: () => {
|
|
calls.push('reload-config');
|
|
},
|
|
getResolvedConfig: () => ({
|
|
websocket: { enabled: false },
|
|
annotationWebsocket: { enabled: false },
|
|
texthooker: { launchAtStartup: false },
|
|
}),
|
|
getConfigWarnings: () => [],
|
|
logConfigWarning: () => {},
|
|
setLogLevel: () => {
|
|
calls.push('set-log-level');
|
|
},
|
|
initRuntimeOptionsManager: () => {
|
|
calls.push('init-runtime-options');
|
|
},
|
|
setSecondarySubMode: () => {
|
|
calls.push('set-secondary-sub-mode');
|
|
},
|
|
defaultSecondarySubMode: 'hover',
|
|
defaultWebsocketPort: 0,
|
|
defaultAnnotationWebsocketPort: 0,
|
|
defaultTexthookerPort: 0,
|
|
hasMpvWebsocketPlugin: () => false,
|
|
startSubtitleWebsocket: () => {},
|
|
startAnnotationWebsocket: () => {},
|
|
startTexthooker: () => {},
|
|
log: () => {
|
|
calls.push('log');
|
|
},
|
|
createMecabTokenizerAndCheck: async () => {},
|
|
createSubtitleTimingTracker: () => {
|
|
calls.push('subtitle-timing');
|
|
},
|
|
createImmersionTracker: () => {
|
|
calls.push('immersion');
|
|
},
|
|
startJellyfinRemoteSession: async () => {},
|
|
loadYomitanExtension: async () => {
|
|
calls.push('load-yomitan-direct');
|
|
},
|
|
ensureYomitanExtensionLoaded: async () => {
|
|
calls.push('load-yomitan-guarded');
|
|
},
|
|
handleFirstRunSetup: async () => {
|
|
calls.push('first-run');
|
|
},
|
|
prewarmSubtitleDictionaries: async () => {},
|
|
startBackgroundWarmups: () => {
|
|
calls.push('warmups');
|
|
},
|
|
texthookerOnlyMode: false,
|
|
shouldAutoInitializeOverlayRuntimeFromConfig: () => false,
|
|
setVisibleOverlayVisible: () => {
|
|
calls.push('visible-overlay');
|
|
},
|
|
initializeOverlayRuntime: () => {
|
|
calls.push('init-overlay');
|
|
},
|
|
handleInitialArgs: () => {
|
|
calls.push('handle-initial-args');
|
|
},
|
|
shouldUseMinimalStartup: () => false,
|
|
shouldSkipHeavyStartup: () => false,
|
|
});
|
|
|
|
assert.equal(calls.includes('load-yomitan-direct'), false);
|
|
assert.equal(calls.includes('load-yomitan-guarded'), true);
|
|
});
|