Kurs-Übersicht: fehlende Hausaufgaben; Erinnerungen als eigene Aufgabenart; Kalender-/Sitzplan-Bugfixes
Kurs-Übersicht: neue Karte "Fehlende Hausaufgaben" listet Schüler mit nicht gemachter Hausaufgabe aus der letzten Mitarbeitssitzung. Aufgabenverwaltung: WorkTask.Kind unterscheidet jetzt Arbeitsaufträge von reinen Erinnerungen ohne Zeitbezug (z.B. "morgen Ansage an die Klasse machen") - eigener Button "🔔 Erinnerung", eigenes Icon in Liste/Dashboard, läuft nicht in die Zeitauswertung ein. Drei Bugfixes aus Nutzer-Feedback: - Dashboard-Kalender zeigte eine Stunde doppelt, wenn sie über "Sitzung erzeugen" mit einer Mitarbeitssitzung verknüpft war. - Der Sitzplan-Tab legte beim bloßen Öffnen einer Gruppe (nicht erst bei echter Nutzung) eine leere "Sitzplan"-Sitzung für heute an. - Der "Meine Klasse"-Ring im Kalender erschien erst, sobald für den Tag eine Lesson existierte, statt schon laut Stundenplan. Außerdem: Drawer-Icons pinnen jetzt explizit auf die farbige Emoji-Schrift (Windows kann sonst je nach Font-Fallback auf eine einfarbige Variante ausweichen). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,8 +6,9 @@ using Xunit;
|
||||
namespace LehrerApp.Desktop.Tests;
|
||||
|
||||
/// Tests für 9.1 (heutige Stunden mit Uhrzeit und Raum im Dashboard) und 9.2 (Absprung von einer
|
||||
/// Stunde). Deckt nur die neue Zeit-/Raum-Auflösung ab, nicht die übrigen, unveränderten
|
||||
/// Dashboard-Bausteine (Kalender, offene Aufgaben, Fehlzeiten-Warnungen, ...).
|
||||
/// Stunde), außerdem die Kalender-Sitzungsanzeige (3.3.4) und die Mindeststichprobe der
|
||||
/// Fehlzeiten-Warnung (5.2.3). Deckt nicht die übrigen, unveränderten Dashboard-Bausteine
|
||||
/// (offene Aufgaben, ...).
|
||||
public sealed class DashboardViewModelTests
|
||||
{
|
||||
private static PeriodScheduleService NewPeriodSchedule()
|
||||
@@ -41,7 +42,7 @@ public sealed class DashboardViewModelTests
|
||||
FakeWorkTasks? tasks = null, FakeStudents? students = null, FakeDocumentation? documentation = null,
|
||||
DashboardSettingsService? dashboardSettings = null, FakeSchoolHolidays? schoolHolidays = null,
|
||||
FakeLessons? lessons = null, FakeSubstitutionEntries? substitutions = null,
|
||||
FakeSessions? sessions = null)
|
||||
FakeSessions? sessions = null, FakeEntries? entries = null)
|
||||
{
|
||||
lessons ??= new FakeLessons();
|
||||
lessons.Add(lesson);
|
||||
@@ -49,7 +50,7 @@ public sealed class DashboardViewModelTests
|
||||
new FakeGroups([group]), new FakeSubjects([]), lessons,
|
||||
exams ?? new FakeExams([]), results ?? new FakeResults(), grades ?? new FakeGrades(),
|
||||
reportGrades ?? new FakeReportGrades(), memberships ?? new FakeMemberships([]),
|
||||
tasks ?? new FakeWorkTasks(), sessions ?? new FakeSessions([]), new FakeEntries(),
|
||||
tasks ?? new FakeWorkTasks(), sessions ?? new FakeSessions([]), entries ?? new FakeEntries(),
|
||||
students ?? new FakeStudents([]), documentation ?? new FakeDocumentation(),
|
||||
slots ?? new FakeTimetableSlots(), periodSchedule ?? NewPeriodSchedule(),
|
||||
new AttendanceBalanceService(), new SchoolYearService(), dashboardSettings ?? NewDashboardSettings(),
|
||||
@@ -243,6 +244,45 @@ public sealed class DashboardViewModelTests
|
||||
e => e.Kind == CalendarEventKind.ParticipationSession && e.Subtitle == "Aufsatz");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Kalender_AusStundeErzeugteSitzungErzeugtKeinenDoppelteintrag()
|
||||
{
|
||||
// Regressionstest (Nutzer-Feedback): "Sitzung erzeugen" (3.3.1) verknüpft die Sitzung über
|
||||
// LessonId mit der Stunde — dieselbe Unterrichtsstunde darf im Kalender nicht zusätzlich
|
||||
// als eigener Sitzungstermin auftauchen.
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "9c" };
|
||||
var lesson = new Lesson { GroupId = group.Id, Date = today, Topic = "Brechung" };
|
||||
var session = new ParticipationSession { GroupId = group.Id, Date = today, LessonId = lesson.Id, Comment = "Brechung" };
|
||||
var vm = BuildVm(group, lesson, sessions: new FakeSessions([session]));
|
||||
|
||||
var day = vm.CalendarDays.Single(d => d.Date == today);
|
||||
Assert.True(day.HasLesson);
|
||||
Assert.False(day.HasSession);
|
||||
|
||||
vm.SelectCalendarDayCommand.Execute(day);
|
||||
|
||||
Assert.Single(vm.SelectedDayEvents);
|
||||
Assert.DoesNotContain(vm.SelectedDayEvents, e => e.Kind == CalendarEventKind.ParticipationSession);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Kalender_EigeneKlasseAmStundenplanTagOhneLessonZeigtDenRingTrotzdem()
|
||||
{
|
||||
// Regressionstest (Nutzer-Feedback): der "Meine Klasse"-Ring soll schon laut Stundenplan
|
||||
// gelten, nicht erst, sobald für den Tag eine Lesson angelegt wurde.
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var tomorrow = today.AddDays(1);
|
||||
var group = new LearningGroup { Name = "9c", IsOwnClass = true };
|
||||
var slots = new FakeTimetableSlots();
|
||||
slots.Add(new TimetableSlot { GroupId = group.Id, Weekday = tomorrow.DayOfWeek, PeriodNumber = 3 });
|
||||
|
||||
var vm = BuildVm(group, new Lesson { GroupId = group.Id, Date = today }, slots: slots);
|
||||
|
||||
var day = vm.CalendarDays.Single(d => d.Date == tomorrow);
|
||||
Assert.True(day.IsOwnClassDay);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DashboardKacheln_SichtbarkeitUndReihenfolgeWerdenGespeichert()
|
||||
{
|
||||
@@ -373,4 +413,53 @@ public sealed class DashboardViewModelTests
|
||||
|
||||
Assert.Empty(vm.UnplannedLessons);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttendanceWarnings_KleineStichprobeMitHoherQuoteWirdNichtGemeldet()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "9c" };
|
||||
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
||||
var sessions = new FakeSessions([]);
|
||||
var entries = new FakeEntries();
|
||||
|
||||
// Nur 3 erfasste Termine, alle unentschuldigt (100 %) — Stichprobe zu klein für eine Meldung.
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
var session = new ParticipationSession { GroupId = group.Id, Date = today.AddDays(-i - 1) };
|
||||
sessions.Save(session);
|
||||
entries.Add(new ParticipationEntry { SessionId = session.Id, StudentId = student.Id, Attendance = AttendanceStatus.Unexcused });
|
||||
}
|
||||
|
||||
var vm = BuildVm(group, new Lesson { GroupId = group.Id, Date = today },
|
||||
students: new FakeStudents([student]), sessions: sessions, entries: entries);
|
||||
|
||||
Assert.Empty(vm.AttendanceWarnings);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AttendanceWarnings_MeldetHoheQuoteAbMindeststichprobe()
|
||||
{
|
||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||
var group = new LearningGroup { Name = "9c" };
|
||||
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
||||
var sessions = new FakeSessions([]);
|
||||
var entries = new FakeEntries();
|
||||
|
||||
// 10 erfasste Termine, 3 davon unentschuldigt (30 % > 20 % Schwelle) — genug Stichprobe.
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var session = new ParticipationSession { GroupId = group.Id, Date = today.AddDays(-i - 1) };
|
||||
sessions.Save(session);
|
||||
var status = i < 3 ? AttendanceStatus.Unexcused : AttendanceStatus.Present;
|
||||
entries.Add(new ParticipationEntry { SessionId = session.Id, StudentId = student.Id, Attendance = status });
|
||||
}
|
||||
|
||||
var vm = BuildVm(group, new Lesson { GroupId = group.Id, Date = today },
|
||||
students: new FakeStudents([student]), sessions: sessions, entries: entries);
|
||||
|
||||
var item = Assert.Single(vm.AttendanceWarnings);
|
||||
Assert.Equal(student.FullName, item.StudentName);
|
||||
Assert.Equal(30.0, item.AbsenceRatePercent);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user