import assert from 'node:assert/strict'; import test from 'node:test'; import { renderToStaticMarkup } from 'react-dom/server'; import { MediaHeader } from '../components/library/MediaHeader'; import { EpisodeList } from '../components/anime/EpisodeList'; import { AnimeOverviewStats } from '../components/anime/AnimeOverviewStats'; import { SessionRow } from '../components/sessions/SessionRow'; import { EventType, type SessionEvent } from '../types/stats'; import { buildLookupRateDisplay, getYomitanLookupEvents } from './yomitan-lookup'; test('buildLookupRateDisplay formats lookups per 100 words in short and long forms', () => { assert.deepEqual(buildLookupRateDisplay(23, 1000), { shortValue: '2.3 / 100 words', longValue: '2.3 lookups per 100 words', }); assert.equal(buildLookupRateDisplay(0, 0), null); }); test('getYomitanLookupEvents keeps only Yomitan lookup events', () => { const events: SessionEvent[] = [ { eventType: EventType.LOOKUP, tsMs: 1, payload: null }, { eventType: EventType.YOMITAN_LOOKUP, tsMs: 2, payload: null }, { eventType: EventType.CARD_MINED, tsMs: 3, payload: null }, ]; assert.deepEqual( getYomitanLookupEvents(events).map((event) => event.tsMs), [2], ); }); test('MediaHeader renders Yomitan lookup count and lookup rate copy', () => { const markup = renderToStaticMarkup( , ); assert.match(markup, /23/); assert.match(markup, /2\.3 \/ 100 words/); assert.match(markup, /2\.3 lookups per 100 words/); }); test('MediaHeader distinguishes word occurrences from known unique words', () => { const markup = renderToStaticMarkup( , ); assert.match(markup, /word occurrences/); assert.match(markup, /known unique words \(50%\)/); assert.match(markup, /17 \/ 34/); }); test('EpisodeList renders per-episode Yomitan lookup rate', () => { const markup = renderToStaticMarkup( , ); assert.match(markup, /Lookup Rate/); assert.match(markup, /2\.0 \/ 100 words/); assert.match(markup, /6%/); assert.doesNotMatch(markup, /90%/); }); test('AnimeOverviewStats renders aggregate Yomitan lookup metrics', () => { const markup = renderToStaticMarkup( , ); assert.match(markup, /Lookups/); assert.match(markup, /16/); assert.match(markup, /2\.0 \/ 100 words/); assert.match(markup, /Yomitan lookups per 100 words seen/); }); test('SessionRow prefers word-based count when available', () => { const markup = renderToStaticMarkup( {}} onDelete={() => {}} />, ); assert.match(markup, />4212