mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-11-10 04:46:07 -08:00
127 lines
4.9 KiB
TypeScript
127 lines
4.9 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { runAppReadyRuntime, type AppReadyRuntimeDeps } from './startup';
|
|
|
|
// Every dep records its name in `calls`; overrides replace individual deps.
|
|
function createAppReadyDeps(overrides: Partial<AppReadyRuntimeDeps> = {}) {
|
|
const calls: string[] = [];
|
|
const record = (name: string) => () => {
|
|
calls.push(name);
|
|
};
|
|
const recordAsync = (name: string) => async () => {
|
|
calls.push(name);
|
|
};
|
|
const deps: AppReadyRuntimeDeps = {
|
|
ensureDefaultConfigBootstrap: record('bootstrap'),
|
|
loadSubtitlePosition: record('load-subtitle-position'),
|
|
resolveKeybindings: record('resolve-keybindings'),
|
|
createMpvClient: record('create-mpv'),
|
|
reloadConfig: record('reload-config'),
|
|
getResolvedConfig: () => ({
|
|
websocket: { enabled: false },
|
|
annotationWebsocket: { enabled: false },
|
|
texthooker: { launchAtStartup: false },
|
|
}),
|
|
getConfigWarnings: () => [],
|
|
logConfigWarning: record('config-warning'),
|
|
setLogLevel: record('set-log-level'),
|
|
initRuntimeOptionsManager: record('init-runtime-options'),
|
|
setSecondarySubMode: record('set-secondary-sub-mode'),
|
|
defaultSecondarySubMode: 'hover',
|
|
defaultWebsocketPort: 0,
|
|
defaultAnnotationWebsocketPort: 0,
|
|
defaultTexthookerPort: 0,
|
|
hasMpvWebsocketPlugin: () => false,
|
|
startSubtitleWebsocket: record('subtitle-ws'),
|
|
startAnnotationWebsocket: record('annotation-ws'),
|
|
startTexthooker: record('texthooker'),
|
|
log: record('log'),
|
|
createMecabTokenizerAndCheck: recordAsync('mecab'),
|
|
createSubtitleTimingTracker: record('subtitle-timing'),
|
|
createImmersionTracker: record('immersion'),
|
|
startJellyfinRemoteSession: recordAsync('jellyfin'),
|
|
loadYomitanExtension: recordAsync('load-yomitan'),
|
|
handleFirstRunSetup: recordAsync('first-run'),
|
|
prewarmSubtitleDictionaries: recordAsync('prewarm'),
|
|
startBackgroundWarmups: record('warmups'),
|
|
isTexthookerOnlyMode: () => false,
|
|
shouldAutoInitializeOverlayRuntimeFromConfig: () => false,
|
|
setVisibleOverlayVisible: record('visible-overlay'),
|
|
initializeOverlayRuntime: record('init-overlay'),
|
|
handleInitialArgs: record('handle-initial-args'),
|
|
shouldUseMinimalStartup: () => false,
|
|
shouldSkipHeavyStartup: () => false,
|
|
...overrides,
|
|
};
|
|
return { calls, deps };
|
|
}
|
|
|
|
function assertBefore(calls: string[], earlier: string, later: string) {
|
|
const earlierIndex = calls.indexOf(earlier);
|
|
const laterIndex = calls.indexOf(later);
|
|
assert.notEqual(earlierIndex, -1, `${earlier} was not called`);
|
|
assert.notEqual(laterIndex, -1, `${later} was not called`);
|
|
assert.ok(earlierIndex < laterIndex, `${earlier} should run before ${later}`);
|
|
}
|
|
|
|
test('runAppReadyRuntime minimal startup skips Yomitan and first-run setup while still handling CLI args', async () => {
|
|
const { calls, deps } = createAppReadyDeps({ shouldUseMinimalStartup: () => true });
|
|
|
|
await runAppReadyRuntime(deps);
|
|
|
|
assert.ok(calls.includes('handle-initial-args'));
|
|
for (const skipped of ['load-yomitan', 'first-run', 'create-mpv', 'init-overlay', 'warmups']) {
|
|
assert.equal(calls.includes(skipped), false, `${skipped} should be skipped`);
|
|
}
|
|
});
|
|
|
|
test('runAppReadyRuntime headless refresh bootstraps Anki runtime without UI startup', async () => {
|
|
const { calls, deps } = createAppReadyDeps({
|
|
shouldRunHeadlessInitialCommand: () => true,
|
|
runHeadlessInitialCommand: async () => {
|
|
calls.push('run-headless-command');
|
|
},
|
|
});
|
|
|
|
await runAppReadyRuntime(deps);
|
|
|
|
assertBefore(calls, 'init-runtime-options', 'run-headless-command');
|
|
for (const skipped of ['create-mpv', 'load-yomitan', 'init-overlay', 'handle-initial-args']) {
|
|
assert.equal(calls.includes(skipped), false, `${skipped} should be skipped`);
|
|
}
|
|
});
|
|
|
|
test('runAppReadyRuntime loads Yomitan before headless overlay fallback initialization', async () => {
|
|
const { calls, deps } = createAppReadyDeps({ shouldRunHeadlessInitialCommand: () => true });
|
|
|
|
await runAppReadyRuntime(deps);
|
|
|
|
assertBefore(calls, 'create-mpv', 'subtitle-timing');
|
|
assertBefore(calls, 'load-yomitan', 'init-overlay');
|
|
assertBefore(calls, 'init-overlay', 'handle-initial-args');
|
|
});
|
|
|
|
test('runAppReadyRuntime auto-initializes overlay runtime before warmups and Yomitan', async () => {
|
|
const { calls, deps } = createAppReadyDeps({
|
|
shouldAutoInitializeOverlayRuntimeFromConfig: () => true,
|
|
});
|
|
|
|
await runAppReadyRuntime(deps);
|
|
|
|
assertBefore(calls, 'init-overlay', 'warmups');
|
|
assert.equal(calls.includes('load-yomitan'), false);
|
|
});
|
|
|
|
test('runAppReadyRuntime reuses guarded Yomitan loader after scheduling startup warmups', async () => {
|
|
const { calls, deps } = createAppReadyDeps({
|
|
ensureYomitanExtensionLoaded: async () => {
|
|
calls.push('load-yomitan-guarded');
|
|
},
|
|
});
|
|
|
|
await runAppReadyRuntime(deps);
|
|
|
|
assert.equal(calls.includes('load-yomitan'), false);
|
|
assertBefore(calls, 'warmups', 'load-yomitan-guarded');
|
|
});
|