Files
SubMiner/src/main/runtime/composers/ipc-runtime-composer.test.ts
sudacode 5feed360ca feat: add app-owned YouTube subtitle flow with absPlayer-style parsing (#31)
* fix: harden preload argv parsing for popup windows

* fix: align youtube playback with shared overlay startup

* fix: unwrap mpv youtube streams for anki media mining

* docs: update docs for youtube subtitle and mining flow

* refactor: unify cli and runtime wiring for startup and youtube flow

* feat: update subtitle sidebar overlay behavior

* chore: add shared log-file source for diagnostics

* fix(ci): add changelog fragment for immersion changes

* fix: address CodeRabbit review feedback

* fix: persist canonical title from youtube metadata

* style: format stats library tab

* fix: address latest review feedback

* style: format stats library files

* test: stub launcher youtube deps in CI

* test: isolate launcher youtube flow deps

* test: stub launcher youtube deps in failing case

* test: force x11 backend in launcher ci harness

* test: address latest review feedback

* fix(launcher): preserve user YouTube ytdl raw options

* docs(backlog): update task tracking notes

* fix(immersion): special-case youtube media paths in runtime and tracking

* feat(stats): improve YouTube media metadata and picker key handling

* fix(ci): format stats media library hook

* fix: address latest CodeRabbit review items

* docs: update youtube release notes and docs

* feat: auto-load youtube subtitles before manual picker

* fix: restore app-owned youtube subtitle flow

* docs: update youtube playback docs and config copy

* refactor: remove legacy youtube launcher mode plumbing

* fix: refine youtube subtitle startup binding

* docs: clarify youtube subtitle startup behavior

* fix: address PR #31 latest review follow-ups

* fix: address PR #31 follow-up review comments

* test: harden youtube picker test harness

* udpate backlog

* fix: add timeout to youtube metadata probe

* docs: refresh youtube and stats docs

* update backlog

* update backlog

* chore: release v0.9.0
2026-03-24 00:01:24 -07:00

116 lines
4.3 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { composeIpcRuntimeHandlers } from './ipc-runtime-composer';
test('composeIpcRuntimeHandlers returns callable IPC handlers and registration bridge', async () => {
let registered = false;
let receivedSourceTrackId: number | null | undefined;
const composed = composeIpcRuntimeHandlers({
mpvCommandMainDeps: {
triggerSubsyncFromConfig: async () => {},
openRuntimeOptionsPalette: () => {},
openYoutubeTrackPicker: () => {},
cycleRuntimeOption: () => ({ ok: true }),
showMpvOsd: () => {},
replayCurrentSubtitle: () => {},
playNextSubtitle: () => {},
shiftSubDelayToAdjacentSubtitle: async () => {},
sendMpvCommand: () => {},
getMpvClient: () => null,
isMpvConnected: () => false,
hasRuntimeOptionsManager: () => true,
},
handleMpvCommandFromIpcRuntime: () => {},
runSubsyncManualFromIpc: async (request) => {
receivedSourceTrackId = request.sourceTrackId;
return {
ok: true,
message: 'ok',
};
},
registration: {
runtimeOptions: {
getRuntimeOptionsManager: () => null,
showMpvOsd: () => {},
},
mainDeps: {
getMainWindow: () => null,
getVisibleOverlayVisibility: () => false,
focusMainWindow: () => {},
onOverlayModalClosed: () => {},
openYomitanSettings: () => {},
quitApp: () => {},
toggleVisibleOverlay: () => {},
tokenizeCurrentSubtitle: async () => null,
getCurrentSubtitleRaw: () => '',
getCurrentSubtitleAss: () => '',
getPlaybackPaused: () => null,
getSubtitlePosition: () => ({}) as never,
getSubtitleStyle: () => ({}) as never,
saveSubtitlePosition: () => {},
getMecabTokenizer: () => null,
getKeybindings: () => [],
getConfiguredShortcuts: () => ({}) as never,
getStatsToggleKey: () => 'Backquote',
getMarkWatchedKey: () => 'KeyW',
getControllerConfig: () => ({}) as never,
saveControllerConfig: () => {},
saveControllerPreference: () => {},
getSecondarySubMode: () => 'hover' as never,
getMpvClient: () => null,
getAnkiConnectStatus: () => false,
getRuntimeOptions: () => [],
reportOverlayContentBounds: () => {},
getAnilistStatus: () => ({}) as never,
clearAnilistToken: () => {},
openAnilistSetup: () => {},
getAnilistQueueStatus: () => ({}) as never,
retryAnilistQueueNow: async () => ({ ok: true, message: 'ok' }),
appendClipboardVideoToQueue: () => ({ ok: true, message: 'ok' }),
onYoutubePickerResolve: async () => ({ ok: true, message: 'ok' }),
},
ankiJimakuDeps: {
patchAnkiConnectEnabled: () => {},
getResolvedConfig: () => ({}) as never,
getRuntimeOptionsManager: () => null,
getSubtitleTimingTracker: () => null,
getMpvClient: () => null,
getAnkiIntegration: () => null,
setAnkiIntegration: () => {},
getKnownWordCacheStatePath: () => '',
showDesktopNotification: () => {},
createFieldGroupingCallback: () => (() => {}) as never,
broadcastRuntimeOptionsChanged: () => {},
getFieldGroupingResolver: () => null,
setFieldGroupingResolver: () => {},
parseMediaInfo: () => ({}) as never,
getCurrentMediaPath: () => null,
jimakuFetchJson: async () => ({ data: null }) as never,
getJimakuMaxEntryResults: () => 0,
getJimakuLanguagePreference: () => 'ja' as never,
resolveJimakuApiKey: async () => null,
isRemoteMediaPath: () => false,
downloadToFile: async () => ({ ok: true, path: '/tmp/file' }),
},
registerIpcRuntimeServices: () => {
registered = true;
},
},
});
assert.equal(typeof composed.handleMpvCommandFromIpc, 'function');
assert.equal(typeof composed.runSubsyncManualFromIpc, 'function');
assert.equal(typeof composed.registerIpcRuntimeHandlers, 'function');
const result = await composed.runSubsyncManualFromIpc({
engine: 'alass',
sourceTrackId: 7,
});
assert.deepEqual(result, { ok: true, message: 'ok' });
assert.equal(receivedSourceTrackId, 7);
composed.registerIpcRuntimeHandlers();
assert.equal(registered, true);
});