Some checks are pending
CI / validate (push) Waiting to run
Phase 2 des cards→wordeck Big-Bang-Rebrand:
- 4 package.json: @cards/* → @wordeck/*
- packages/cards-domain/ → packages/wordeck-domain/
- 41+12 Files: from '@cards/domain' → '@wordeck/domain'
- pgSchema('cards') → pgSchema('wordeck') (Drizzle-Schema)
- 17 Files: process.env.CARDS_* → process.env.WORDECK_*
- docker-compose Service-Names: cards-* → wordeck-*
- docker-compose Volume: /Volumes/ManaData/cards → wordeck
- env-vars in compose: CARDS_DB_PASSWORD/_API_VERSION/_DSGVO_SERVICE_KEY etc. → WORDECK_*
- Log-Prefixes + Error-Strings + manifest-id 'cards' → 'wordeck'
- CORS-Origin cardecky.mana.how → wordeck.com
- .env.production.example umbenannt + S3-Key entfernt (kein MinIO mehr)
Type-Check 0 Errors in api+domain+web, 51/51 Domain-Tests grün.
DB-Rename + Container/Volume-Rename auf mana-server folgen in nächstem
Commit nach Verzeichnis-Rename.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
99 lines
3.1 KiB
TypeScript
99 lines
3.1 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
|
|
import {
|
|
extractClusterIds,
|
|
hintForCluster,
|
|
subIndexCountForCloze,
|
|
clusterIdForSubIndex,
|
|
renderClozePrompt,
|
|
renderClozeAnswer,
|
|
} from '../src/cloze.ts';
|
|
|
|
describe('extractClusterIds', () => {
|
|
it('liefert leere Liste, wenn kein Cluster-Markup', () => {
|
|
expect(extractClusterIds('Plain text without cloze')).toEqual([]);
|
|
});
|
|
|
|
it('extrahiert einen einzelnen Cluster', () => {
|
|
expect(extractClusterIds('The capital of France is {{c1::Paris}}.')).toEqual([1]);
|
|
});
|
|
|
|
it('extrahiert mehrere Cluster aufsteigend sortiert', () => {
|
|
expect(extractClusterIds('{{c2::B}} kommt nach {{c1::A}}')).toEqual([1, 2]);
|
|
});
|
|
|
|
it('dedupliziert mehrfach auftretende Cluster-IDs', () => {
|
|
expect(extractClusterIds('{{c1::a}} und {{c1::b}} und {{c2::c}}')).toEqual([1, 2]);
|
|
});
|
|
|
|
it('ignoriert malformed Cluster (kein numerisches N)', () => {
|
|
expect(extractClusterIds('{{cX::weird}} {{c1::ok}}')).toEqual([1]);
|
|
});
|
|
|
|
it('akzeptiert Cluster mit Hint (::hint wird gedroppt)', () => {
|
|
expect(extractClusterIds('Die {{c1::Hauptstadt::Land}} von Frankreich.')).toEqual([1]);
|
|
});
|
|
});
|
|
|
|
describe('subIndexCountForCloze', () => {
|
|
it('zählt distinct Cluster', () => {
|
|
expect(subIndexCountForCloze('{{c1::a}} {{c2::b}} {{c3::c}}')).toBe(3);
|
|
});
|
|
|
|
it('returniert 0 bei text ohne Cluster', () => {
|
|
expect(subIndexCountForCloze('keine cloze')).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe('clusterIdForSubIndex', () => {
|
|
it('mapt subIndex auf sortierte Cluster-IDs', () => {
|
|
const text = '{{c3::c}} {{c1::a}} {{c2::b}}';
|
|
expect(clusterIdForSubIndex(text, 0)).toBe(1);
|
|
expect(clusterIdForSubIndex(text, 1)).toBe(2);
|
|
expect(clusterIdForSubIndex(text, 2)).toBe(3);
|
|
expect(clusterIdForSubIndex(text, 3)).toBe(null);
|
|
});
|
|
});
|
|
|
|
describe('hintForCluster', () => {
|
|
it('liefert den Hint, wenn vorhanden', () => {
|
|
expect(hintForCluster('Die {{c1::Antwort::Hinweis}}.', 1)).toBe('Hinweis');
|
|
});
|
|
|
|
it('liefert undefined ohne Hint-Annotation', () => {
|
|
expect(hintForCluster('Die {{c1::Antwort}}.', 1)).toBeUndefined();
|
|
});
|
|
|
|
it('liefert undefined für nicht-existierende Cluster', () => {
|
|
expect(hintForCluster('Die {{c1::Antwort::Hint}}.', 2)).toBeUndefined();
|
|
});
|
|
|
|
it('erste Hint-Annotation gewinnt bei mehreren Vorkommen', () => {
|
|
const text = '{{c1::a}} und {{c1::b::erster}} und {{c1::c::zweiter}}';
|
|
expect(hintForCluster(text, 1)).toBe('erster');
|
|
});
|
|
});
|
|
|
|
describe('renderClozePrompt', () => {
|
|
it('maskiert aktiven Cluster, expandiert andere', () => {
|
|
const out = renderClozePrompt('{{c1::A}} und {{c2::B}}', 1);
|
|
expect(out).toBe('[…] und B');
|
|
});
|
|
|
|
it('zeigt Hint im aktiven Cluster, wenn vorhanden', () => {
|
|
const out = renderClozePrompt('Die {{c1::Antwort::Hinweis}}.', 1);
|
|
expect(out).toBe('Die [Hinweis].');
|
|
});
|
|
|
|
it('expandiert nicht-aktiven Cluster auch wenn Hint vorhanden', () => {
|
|
const out = renderClozePrompt('{{c1::A::tipp}} und {{c2::B}}', 2);
|
|
expect(out).toBe('A und […]');
|
|
});
|
|
});
|
|
|
|
describe('renderClozeAnswer', () => {
|
|
it('expandiert alle Cluster, markiert aktiven mit Bold', () => {
|
|
const out = renderClozeAnswer('{{c1::A}} und {{c2::B}}', 1);
|
|
expect(out).toBe('**A** und B');
|
|
});
|
|
});
|