Files
Momento/memento-note/tests/unit/chunk-indexing.test.ts
Antigravity 104af3149f
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m28s
CI / Deploy production (on server) (push) Has been skipped
feat: générateur d'exercices + planning de révision IA
- Générateur d'exercices : bouton dans menu note → IA crée 5 exercices
  - Niveaux variés (facile/moyen/difficile) avec emojis 🟢🟡🔴
  - Corrigés détaillés dans des toggles (cliquer pour révéler)
  - Callout warning pour le niveau
  - Notes créées dans le même carnet
- Planning de révision : bouton dans barre carnet → IA crée planning
  - Choix date d'examen
  - Répétition espacée (première lecture → revoir → révision globale)
  - Rappels automatiques ajoutés aux notes (9h le jour J)
  - Vue chronologique avec activités et notes par jour
- Services : exercise-generator.service.ts + study-planner.service.ts
- Endpoints : /api/ai/generate-exercises + /api/ai/study-plan
- i18n FR/EN complet
2026-06-14 19:57:21 +00:00

133 lines
4.6 KiB
TypeScript

import { test, expect, describe, beforeAll, afterAll, beforeEach } from 'vitest'
import { prisma } from '../../lib/prisma'
import { ChunkIndexingService } from '../../lib/ai/services/chunk-indexing.service'
import { embeddingService } from '../../lib/ai/services/embedding.service'
import crypto from 'crypto'
const testNoteId = 'test-chunk-000001'
describe('US-CHUNK-2 : Indexation incrémentale avec dedup', () => {
let originalEmbedText: any
beforeAll(async () => {
originalEmbedText = embeddingService.embedText
embeddingService.embedText = async (text: string) => {
const hash = crypto.createHash('md5').update(text).digest()
return Array.from({ length: 1536 }, (_, i) => hash[i % 16] / 255)
}
await prisma.note.upsert({
where: { id: testNoteId },
create: {
id: testNoteId,
title: 'Test Note for Chunk Indexing',
content: '<p>Test</p>',
},
update: {},
})
})
afterAll(async () => {
embeddingService.embedText = originalEmbedText
await prisma.noteEmbeddingChunk.deleteMany({ where: { noteId: testNoteId } })
await prisma.note.delete({ where: { id: testNoteId } }).catch(() => {})
})
beforeEach(async () => {
await prisma.noteEmbeddingChunk.deleteMany({ where: { noteId: testNoteId } })
})
const longContent = Array.from({ length: 8 }, (_, i) =>
`Section ${i} de la note de test. `.repeat(60).trim(),
).join('\n\n')
test('première indexation → tous les fragments sont nouveaux', async () => {
const service = new ChunkIndexingService()
const result = await service.indexNote(testNoteId, 'Note de test', longContent)
expect(result.newFragments).toBeGreaterThan(0)
expect(result.deleted).toBe(0)
expect(result.skipped).toBe(0)
})
test('deuxième indexation (même contenu) → tout skipped, 0 nouveau', async () => {
const service = new ChunkIndexingService()
await service.indexNote(testNoteId, 'Note de test', longContent)
const result = await service.indexNote(testNoteId, 'Note de test', longContent)
expect(result.newFragments).toBe(0)
expect(result.skipped).toBeGreaterThan(0)
expect(result.deleted).toBe(0)
})
test('modification d\'une section → 1 nouveau, reste skip', async () => {
const service = new ChunkIndexingService()
await service.indexNote(testNoteId, 'Note de test', longContent)
const sections = Array.from({ length: 8 }, (_, i) =>
`Section ${i === 3 ? 'MODIFIÉE' : i} de la note de test. `.repeat(60).trim(),
)
const modified = sections.join('\n\n')
const result = await service.indexNote(testNoteId, 'Note de test', modified)
expect(result.newFragments).toBeGreaterThanOrEqual(1)
expect(result.deleted).toBeGreaterThanOrEqual(1)
})
test('suppression d\'une section → fragments stale nettoyés', async () => {
const service = new ChunkIndexingService()
const sections = Array.from({ length: 8 }, (_, i) =>
`Section ${i} de la note de test. `.repeat(60).trim(),
)
await service.indexNote(testNoteId, 'Note de test', sections.join('\n\n'))
const beforeCount = await prisma.noteEmbeddingChunk.count({
where: { noteId: testNoteId },
})
const shorter = sections.slice(0, 4).join('\n\n')
const result = await service.indexNote(testNoteId, 'Note de test', shorter)
const afterCount = await prisma.noteEmbeddingChunk.count({
where: { noteId: testNoteId },
})
expect(afterCount).toBeLessThan(beforeCount)
expect(result.deleted).toBeGreaterThan(0)
})
test('note vide → tous les fragments supprimés', async () => {
const service = new ChunkIndexingService()
await service.indexNote(testNoteId, 'Note de test', longContent)
const result = await service.indexNote(testNoteId, '', '')
const count = await prisma.noteEmbeddingChunk.count({
where: { noteId: testNoteId },
})
expect(count).toBe(0)
})
test('deleteNoteChunks → supprime tout', async () => {
const service = new ChunkIndexingService()
await service.indexNote(testNoteId, 'Note de test', longContent)
await service.deleteNoteChunks(testNoteId)
const count = await prisma.noteEmbeddingChunk.count({
where: { noteId: testNoteId },
})
expect(count).toBe(0)
})
test('hasChunks → détection correcte', async () => {
const service = new ChunkIndexingService()
const before = await service.hasChunks(testNoteId)
expect(before).toBe(false)
await service.indexNote(testNoteId, 'Note de test', longContent)
const after = await service.hasChunks(testNoteId)
expect(after).toBe(true)
})
})