mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-20 12:11:28 -07:00
- Hono HTTP server with 20+ REST endpoints for stats data - Stats overlay BrowserWindow with toggle keybinding - IPC channel definitions and preload bridge - Stats config section (toggleKey, serverPort, autoStartServer, autoOpenBrowser) - Config resolver for stats section - AnkiConnect proxy endpoints (guiBrowse, notesInfo) - Note ID passthrough in card mining callback chain - Stats CLI command with autoOpenBrowser respect
112 lines
3.5 KiB
TypeScript
112 lines
3.5 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { createRunStatsCliCommandHandler } from './stats-cli-command';
|
|
|
|
function makeHandler(overrides: Partial<Parameters<typeof createRunStatsCliCommandHandler>[0]> = {}) {
|
|
const calls: string[] = [];
|
|
const responses: Array<{ responsePath: string; payload: { ok: boolean; url?: string; error?: string } }> = [];
|
|
|
|
const handler = createRunStatsCliCommandHandler({
|
|
getResolvedConfig: () => ({
|
|
immersionTracking: { enabled: true },
|
|
stats: { serverPort: 5175 },
|
|
}),
|
|
ensureImmersionTrackerStarted: () => {
|
|
calls.push('ensureImmersionTrackerStarted');
|
|
},
|
|
getImmersionTracker: () => ({ cleanupVocabularyStats: undefined }),
|
|
ensureStatsServerStarted: () => {
|
|
calls.push('ensureStatsServerStarted');
|
|
return 'http://127.0.0.1:5175';
|
|
},
|
|
openExternal: async (url) => {
|
|
calls.push(`openExternal:${url}`);
|
|
},
|
|
writeResponse: (responsePath, payload) => {
|
|
responses.push({ responsePath, payload });
|
|
},
|
|
exitAppWithCode: (code) => {
|
|
calls.push(`exitAppWithCode:${code}`);
|
|
},
|
|
logInfo: (message) => {
|
|
calls.push(`info:${message}`);
|
|
},
|
|
logWarn: (message) => {
|
|
calls.push(`warn:${message}`);
|
|
},
|
|
logError: (message, error) => {
|
|
calls.push(`error:${message}:${error instanceof Error ? error.message : String(error)}`);
|
|
},
|
|
...overrides,
|
|
});
|
|
|
|
return { handler, calls, responses };
|
|
}
|
|
|
|
test('stats cli command starts tracker, server, browser, and writes success response', async () => {
|
|
const { handler, calls, responses } = makeHandler();
|
|
|
|
await handler({ statsResponsePath: '/tmp/subminer-stats-response.json' }, 'initial');
|
|
|
|
assert.deepEqual(calls, [
|
|
'ensureImmersionTrackerStarted',
|
|
'ensureStatsServerStarted',
|
|
'openExternal:http://127.0.0.1:5175',
|
|
'info:Stats dashboard available at http://127.0.0.1:5175',
|
|
]);
|
|
assert.deepEqual(responses, [
|
|
{
|
|
responsePath: '/tmp/subminer-stats-response.json',
|
|
payload: { ok: true, url: 'http://127.0.0.1:5175' },
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('stats cli command fails when immersion tracking is disabled', async () => {
|
|
const { handler, calls, responses } = makeHandler({
|
|
getResolvedConfig: () => ({
|
|
immersionTracking: { enabled: false },
|
|
stats: { serverPort: 5175 },
|
|
}),
|
|
});
|
|
|
|
await handler({ statsResponsePath: '/tmp/subminer-stats-response.json' }, 'initial');
|
|
|
|
assert.equal(calls.includes('ensureImmersionTrackerStarted'), false);
|
|
assert.ok(calls.includes('exitAppWithCode:1'));
|
|
assert.deepEqual(responses, [
|
|
{
|
|
responsePath: '/tmp/subminer-stats-response.json',
|
|
payload: { ok: false, error: 'Immersion tracking is disabled in config.' },
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('stats cli command runs vocab cleanup instead of opening dashboard when cleanup mode is requested', async () => {
|
|
const { handler, calls, responses } = makeHandler({
|
|
getImmersionTracker: () => ({
|
|
cleanupVocabularyStats: async () => ({ scanned: 3, kept: 1, deleted: 2, repaired: 1 }),
|
|
}),
|
|
});
|
|
|
|
await handler(
|
|
{
|
|
statsResponsePath: '/tmp/subminer-stats-response.json',
|
|
statsCleanup: true,
|
|
statsCleanupVocab: true,
|
|
},
|
|
'initial',
|
|
);
|
|
|
|
assert.deepEqual(calls, [
|
|
'ensureImmersionTrackerStarted',
|
|
'info:Stats vocabulary cleanup complete: scanned=3 kept=1 deleted=2 repaired=1',
|
|
]);
|
|
assert.deepEqual(responses, [
|
|
{
|
|
responsePath: '/tmp/subminer-stats-response.json',
|
|
payload: { ok: true },
|
|
},
|
|
]);
|
|
});
|