feat(stats): add v1 immersion stats dashboard (#19)

This commit is contained in:
2026-03-20 02:43:28 -07:00
committed by GitHub
parent 42abdd1268
commit 6749ff843c
555 changed files with 46356 additions and 2553 deletions
+34
View File
@@ -0,0 +1,34 @@
import assert from 'node:assert/strict';
import fs from 'node:fs';
import test from 'node:test';
import { fileURLToPath } from 'node:url';
const VOCABULARY_TAB_PATH = fileURLToPath(
new URL('../components/vocabulary/VocabularyTab.tsx', import.meta.url),
);
test('VocabularyTab declares all hooks before loading and error early returns', () => {
const source = fs.readFileSync(VOCABULARY_TAB_PATH, 'utf8');
const loadingGuardIndex = source.indexOf('if (loading) {');
assert.notEqual(loadingGuardIndex, -1, 'expected loading early return');
const hooksAfterLoadingGuard = source
.slice(loadingGuardIndex)
.match(/\buse(?:State|Effect|Memo|Callback|Ref|Reducer)\s*\(/g);
assert.deepEqual(hooksAfterLoadingGuard ?? [], []);
});
test('VocabularyTab memoizes summary and known-word aggregate calculations', () => {
const source = fs.readFileSync(VOCABULARY_TAB_PATH, 'utf8');
assert.match(
source,
/const summary = useMemo\([\s\S]*buildVocabularySummary\(filteredWords, kanji\)[\s\S]*\[filteredWords, kanji\][\s\S]*\);/,
);
assert.match(
source,
/const knownWordCount = useMemo\(\(\) => \{[\s\S]*for \(const w of filteredWords\) \{[\s\S]*knownWords\.has\(w\.headword\)[\s\S]*\}\s*return count;\s*\}, \[filteredWords, knownWords\]\);/,
);
});