This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/backend/tests/test_frontend_integration.py
Benjamin Admin bfdaf63ba9 fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

438 lines
15 KiB
Python

"""
E2E-Tests für Frontend-Module Integration.
Testet die Verbindung zwischen Frontend-Modulen und ihren APIs:
- Worksheets Frontend → Worksheets API
- Correction Frontend → Corrections API
- Letters Frontend → Letters API
- Companion Frontend → State Engine API
"""
import pytest
from fastapi.testclient import TestClient
import sys
import json
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from main import app
client = TestClient(app)
class TestWorksheetsIntegration:
"""E2E-Tests für Worksheets Frontend → API Integration."""
def test_generate_mc_endpoint(self):
"""Testet MC-Generierung wie Frontend sie aufruft."""
response = client.post(
"/api/worksheets/generate/multiple-choice",
json={
"source_text": "Die Fotosynthese ist ein Prozess, bei dem Pflanzen Lichtenergie nutzen, um aus Kohlendioxid und Wasser Zucker und Sauerstoff herzustellen. Dieser Prozess findet in den Chloroplasten statt.",
"num_questions": 3,
"difficulty": "medium",
"topic": "Fotosynthese",
"subject": "Biologie"
}
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert "content" in data
assert data["content"]["content_type"] == "multiple_choice"
assert "questions" in data["content"]["data"]
assert len(data["content"]["data"]["questions"]) >= 1
def test_generate_cloze_endpoint(self):
"""Testet Lückentext-Generierung."""
response = client.post(
"/api/worksheets/generate/cloze",
json={
"source_text": "Berlin ist die Hauptstadt von Deutschland. Die Stadt hat etwa 3,6 Millionen Einwohner und liegt an der Spree.",
"num_gaps": 3,
"gap_type": "word",
"hint_type": "first_letter"
}
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert data["content"]["content_type"] == "cloze"
def test_generate_mindmap_endpoint(self):
"""Testet Mindmap-Generierung."""
response = client.post(
"/api/worksheets/generate/mindmap",
json={
"source_text": "Das Mittelalter war eine Epoche der europäischen Geschichte. Es begann etwa 500 n. Chr. und endete um 1500. Wichtige Aspekte waren das Lehnswesen, die Kirche und das Rittertum.",
"max_branches": 4,
"depth": 2
}
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert data["content"]["content_type"] == "mindmap"
# API returns 'mermaid' key (not 'mermaid_code')
assert "mermaid" in data["content"]["data"] or "mermaid_code" in data["content"]["data"]
def test_generate_quiz_endpoint(self):
"""Testet Quiz-Generierung."""
response = client.post(
"/api/worksheets/generate/quiz",
json={
"source_text": "Der Wasserkreislauf beschreibt die kontinuierliche Bewegung des Wassers auf der Erde. Wasser verdunstet, bildet Wolken und fällt als Niederschlag.",
"num_items": 3,
"quiz_types": ["true_false"]
}
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert data["content"]["content_type"] == "quiz"
def test_generate_batch_endpoint(self):
"""Testet Batch-Generierung mehrerer Typen."""
response = client.post(
"/api/worksheets/generate/batch",
json={
"source_text": "Python ist eine Programmiersprache. Sie wurde 1991 von Guido van Rossum entwickelt. Python nutzt dynamische Typisierung.",
"content_types": ["multiple_choice", "cloze"]
}
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert len(data["contents"]) == 2
class TestCorrectionsIntegration:
"""E2E-Tests für Correction Frontend → API Integration."""
def test_create_correction_workflow(self):
"""Testet kompletten Korrektur-Workflow."""
# Step 1: Korrektur erstellen
create_response = client.post(
"/api/corrections/",
json={
"student_id": "test-student-e2e",
"student_name": "Test Schueler",
"class_name": "10a",
"exam_title": "E2E-Testklausur",
"subject": "Mathematik",
"max_points": 100
}
)
assert create_response.status_code == 200
create_data = create_response.json()
assert create_data["success"] is True
correction_id = create_data["correction"]["id"]
# Step 2: Status abrufen
get_response = client.get(f"/api/corrections/{correction_id}")
assert get_response.status_code == 200
get_data = get_response.json()
assert get_data["correction"]["status"] == "uploaded"
# Step 3: Korrektur aktualisieren (simuliert Review)
update_response = client.put(
f"/api/corrections/{correction_id}",
json={
"total_points": 85,
"grade": "2",
"teacher_notes": "Gute Arbeit!",
"status": "reviewing"
}
)
assert update_response.status_code == 200
update_data = update_response.json()
assert update_data["correction"]["total_points"] == 85
assert update_data["correction"]["grade"] == "2"
# Step 4: Abschließen
complete_response = client.post(f"/api/corrections/{correction_id}/complete")
assert complete_response.status_code == 200
# Step 5: Finalen Status prüfen
final_response = client.get(f"/api/corrections/{correction_id}")
assert final_response.status_code == 200
assert final_response.json()["correction"]["status"] == "completed"
# Cleanup
client.delete(f"/api/corrections/{correction_id}")
def test_list_corrections(self):
"""Testet Korrektur-Liste."""
response = client.get("/api/corrections/")
assert response.status_code == 200
data = response.json()
assert "corrections" in data
assert "total" in data
class TestLettersIntegration:
"""E2E-Tests für Letters Frontend → API Integration."""
def test_create_letter_workflow(self):
"""Testet kompletten Brief-Workflow."""
# Step 1: Brief erstellen
create_response = client.post(
"/api/letters/",
json={
"recipient_name": "Familie Testmann",
"recipient_address": "Teststr. 1",
"student_name": "Max Testmann",
"student_class": "7a",
"subject": "E2E-Testbrief",
"content": "Sehr geehrte Eltern, dies ist ein Testbrief.",
"letter_type": "general",
"tone": "professional",
"teacher_name": "Frau Test",
"teacher_title": "Klassenlehrerin"
}
)
assert create_response.status_code == 200
letter_data = create_response.json()
letter_id = letter_data["id"]
assert letter_data["status"] == "draft"
# Step 2: Brief abrufen
get_response = client.get(f"/api/letters/{letter_id}")
assert get_response.status_code == 200
assert get_response.json()["student_name"] == "Max Testmann"
# Step 3: Brief aktualisieren
update_response = client.put(
f"/api/letters/{letter_id}",
json={
"content": "Sehr geehrte Eltern, dies ist ein aktualisierter Testbrief."
}
)
assert update_response.status_code == 200
# Cleanup
client.delete(f"/api/letters/{letter_id}")
def test_improve_letter_content(self):
"""Testet GFK-Verbesserung."""
response = client.post(
"/api/letters/improve",
json={
"content": "Ihr Kind muss sich verbessern. Es ist immer zu spät.",
"communication_type": "general",
"tone": "professional"
}
)
assert response.status_code == 200
data = response.json()
assert "improved_content" in data
assert "gfk_score" in data
assert "changes" in data
def test_list_letter_types(self):
"""Testet Abruf der Brieftypen."""
response = client.get("/api/letters/types")
assert response.status_code == 200
data = response.json()
assert "types" in data
assert len(data["types"]) >= 5
def test_list_letter_tones(self):
"""Testet Abruf der Tonalitäten."""
response = client.get("/api/letters/tones")
assert response.status_code == 200
data = response.json()
assert "tones" in data
assert len(data["tones"]) >= 4
class TestStateEngineIntegration:
"""E2E-Tests für Companion Frontend → State Engine API Integration."""
def test_get_dashboard(self):
"""Testet Dashboard-Abruf wie Companion-Mode."""
response = client.get("/api/state/dashboard?teacher_id=e2e-test-teacher")
assert response.status_code == 200
data = response.json()
assert "context" in data
assert "suggestions" in data
assert "stats" in data
assert "progress" in data
assert "phases" in data
def test_get_suggestions(self):
"""Testet Vorschläge-Abruf."""
response = client.get("/api/state/suggestions?teacher_id=e2e-test-teacher")
assert response.status_code == 200
data = response.json()
assert "suggestions" in data
assert "current_phase" in data
assert "priority_counts" in data
def test_complete_milestone_workflow(self):
"""Testet Meilenstein-Abschluss-Workflow."""
teacher_id = "e2e-milestone-test"
# Meilenstein abschließen
response = client.post(
f"/api/state/milestone?teacher_id={teacher_id}",
json={"milestone": "e2e_test_milestone"}
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert "e2e_test_milestone" in data["completed_milestones"]
# Prüfen ob Meilenstein gespeichert
context_response = client.get(f"/api/state/context?teacher_id={teacher_id}")
assert context_response.status_code == 200
context = context_response.json()["context"]
assert "e2e_test_milestone" in context["completed_milestones"]
def test_phase_transition(self):
"""Testet Phasenübergang."""
teacher_id = "e2e-transition-test"
# Erst alle Onboarding-Meilensteine abschließen
for milestone in ["school_select", "consent_accept", "profile_complete"]:
resp = client.post(
f"/api/state/milestone?teacher_id={teacher_id}",
json={"milestone": milestone}
)
# Verify milestones are being accepted
assert resp.status_code == 200
# Transition zu school_year_start sollte möglich sein
response = client.post(
f"/api/state/transition?teacher_id={teacher_id}",
json={"target_phase": "school_year_start"}
)
# Accept both 200 (success) and 400 (if conditions not met due to test isolation)
# In production, milestones persist; in tests, context may be reset between requests
if response.status_code == 200:
data = response.json()
assert data["success"] is True
else:
# Document test environment limitation
assert response.status_code == 400
# Verify it's a condition-related rejection, not a server error
data = response.json()
assert "detail" in data
def test_invalid_phase_transition(self):
"""Testet ungültigen Phasenübergang."""
response = client.post(
"/api/state/transition?teacher_id=e2e-invalid-test",
json={"target_phase": "archived"}
)
# Sollte 400 zurückgeben da direkter Sprung zu archived nicht erlaubt
assert response.status_code == 400
class TestCrossModuleIntegration:
"""Tests für modul-übergreifende Funktionalität."""
def test_studio_html_renders(self):
"""Testet dass Studio HTML alle Module enthält."""
response = client.get("/studio")
assert response.status_code == 200
html = response.text
# Prüfe ob alle Panel-IDs vorhanden
assert "panel-worksheets" in html
assert "panel-correction" in html
assert "panel-letters" in html
def test_all_apis_accessible(self):
"""Testet dass alle APIs erreichbar sind."""
endpoints = [
("/api/worksheets/generate/multiple-choice", "POST"),
("/api/corrections/", "GET"),
("/api/letters/", "GET"),
("/api/state/phases", "GET"),
]
for endpoint, method in endpoints:
if method == "GET":
response = client.get(endpoint)
else:
response = client.post(endpoint, json={
"source_text": "Test",
"num_questions": 1
})
# Sollte nicht 404 oder 500 sein
assert response.status_code in [200, 400, 422], f"{endpoint} returned {response.status_code}"
class TestExportFunctionality:
"""Tests für Export-Funktionen aller Module."""
def test_corrections_pdf_export_endpoint_exists(self):
"""Testet dass PDF-Export Endpoint existiert."""
# Erst Korrektur erstellen
create_response = client.post(
"/api/corrections/",
json={
"student_id": "pdf-test",
"student_name": "PDF Test",
"class_name": "10a",
"exam_title": "PDF-Test",
"subject": "Test",
"max_points": 100
}
)
correction_id = create_response.json()["correction"]["id"]
# PDF-Export versuchen
response = client.get(f"/api/corrections/{correction_id}/export-pdf")
# 500 ist ok wenn PDF-Service nicht verfügbar, aber Endpoint existiert
assert response.status_code in [200, 500]
# Cleanup
client.delete(f"/api/corrections/{correction_id}")
def test_letters_pdf_export_endpoint_exists(self):
"""Testet dass Letters PDF-Export existiert."""
response = client.post(
"/api/letters/export-pdf",
json={
"letter_data": {
"recipient_name": "Test",
"recipient_address": "Test",
"student_name": "Test",
"student_class": "Test",
"subject": "Test",
"content": "Test",
"letter_type": "general",
"tone": "professional",
"teacher_name": "Test",
"teacher_title": "Test"
}
}
)
# 500 ist ok wenn PDF-Service nicht verfügbar
assert response.status_code in [200, 500]
if __name__ == "__main__":
pytest.main([__file__, "-v"])