Files
wisp/src/lib/learn/summary.test.ts
T
NilsBriggen 40858e0025
CI / test (push) Successful in 16s
CI / build-apk (push) Has been skipped
CI / deploy-web (push) Successful in 30s
feat(phase3): learning helpers — summary, glossary, flashcards (SM-2), quizzes
Deterministic, on-device, no model:
- src/lib/learn pure modules (tokenize, summary [TextRank-ish], glossary
  [definition-pattern + frequency], flashcards [cloze/Q-A], srs [SM-2], quiz
  [MCQ with distractors]) — 37 unit tests.
- Flashcard persistence: Dexie v4 + native v4 `flashcards` table; create/list/
  listDue/updateSrs/delete/counts; cascades (transcript delete, course->Unsorted).
- UI: transcript "Study aids" (generate summary+glossary, click-to-seek; create
  flashcards), Study screen (SM-2 review + Anki CSV export), per-lecture Quiz,
  library Study link with due-count badge.

215 tests green, 0 tsc errors, web export builds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 15:37:42 +02:00

58 lines
1.9 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { summarize } from './summary';
import type { Segment } from '../types';
const seg = (start: number, text: string, id?: string): Segment => ({
id,
start,
end: start + 1,
text,
});
describe('summarize', () => {
it('returns [] for no segments', () => {
expect(summarize([])).toEqual([]);
});
it('returns [] when maxSentences <= 0', () => {
expect(summarize([seg(0, 'Neural networks learn.')], { maxSentences: 0 })).toEqual(
[],
);
});
it('picks the top-N highest-frequency sentences', () => {
// "neural" + "networks" dominate; the off-topic sentence should be dropped.
const segs = [
seg(0, 'Neural networks process data.'),
seg(1, 'Neural networks learn from neural networks.'),
seg(2, 'The weather today is sunny.'),
];
const out = summarize(segs, { maxSentences: 2 });
expect(out.length).toBe(2);
const texts = out.map((s) => s.text);
expect(texts).not.toContain('The weather today is sunny.');
});
it('returns sentences in chronological order with the right start + id', () => {
const segs = [
seg(10, 'Gradient descent optimizes the gradient.', 'segB'),
seg(2, 'Gradient descent uses the gradient slope.', 'segA'),
];
const out = summarize(segs, { maxSentences: 2 });
// Both kept; chronological order means start 2 comes before start 10.
expect(out.map((s) => s.start)).toEqual([2, 10]);
expect(out[0]!.segmentId).toBe('segA');
expect(out[1]!.segmentId).toBe('segB');
});
it('flattens multi-sentence segments and tags them with the segment start', () => {
const segs = [seg(5, 'Alpha beta gamma. Alpha beta delta.', 'multi')];
const out = summarize(segs, { maxSentences: 5 });
expect(out.length).toBe(2);
for (const s of out) {
expect(s.start).toBe(5);
expect(s.segmentId).toBe('multi');
}
});
});