CI / build-and-test (push) Canceled after 0s
Dashboard warnings (attendance, and now homework backlog and lateness) apply across all classes, but the existing Vorgänge case-file tab only works for the teacher's own class since it resolves the WebUntis classbook roster. Instead of loosening that coupling, students get their own narrower Vorgänge tab, and all three cross-class warnings now jump straight there, offering to open a matching case or create a new one. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
142 lines
6.0 KiB
C#
142 lines
6.0 KiB
C#
using LehrerApp.Core.Models;
|
|
using LehrerApp.Desktop.ViewModels.ClassTeacher;
|
|
using LehrerApp.Desktop.ViewModels.Students;
|
|
using Xunit;
|
|
|
|
namespace LehrerApp.Desktop.Tests;
|
|
|
|
/// Tests für den schülerbezogenen "Vorgänge"-Tab im Schülerdetail (StudentVorgaengeViewModel) —
|
|
/// der universelle, klassenübergreifende Einstiegspunkt für die Dashboard-Warnungen (Fehlzeiten,
|
|
/// Hausaufgaben-Rückstand, Verspätungen). Anders als ClassTeacherCasesViewModel keine
|
|
/// Roster-/WebUntis-Abhängigkeit, deshalb reine In-Memory-Fakes ohne Untis-Cache-Setup.
|
|
public sealed class StudentVorgaengeViewModelTests
|
|
{
|
|
private static StudentVorgaengeViewModel BuildVm(FakeVorgangRepository? vorgaenge = null,
|
|
FakeDocumentation? documentation = null, FakeStudents? students = null) =>
|
|
new(vorgaenge ?? new FakeVorgangRepository(), documentation ?? new FakeDocumentation(),
|
|
students ?? new FakeStudents([]));
|
|
|
|
[Fact]
|
|
public void Load_ZeigtNurVorgaengeDiesesSchuelers()
|
|
{
|
|
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
|
var other = new Student { FirstName = "Ben", LastName = "Fremd" };
|
|
var vorgaenge = new FakeVorgangRepository();
|
|
vorgaenge.Add(new Vorgang { Title = "Eigener Vorgang", StudentIds = [student.Id] });
|
|
vorgaenge.Add(new Vorgang { Title = "Fremder Vorgang", StudentIds = [other.Id] });
|
|
|
|
var vm = BuildVm(vorgaenge: vorgaenge, students: new FakeStudents([student, other]));
|
|
vm.Load(student.Id);
|
|
|
|
var item = Assert.Single(vm.Cases);
|
|
Assert.Equal("Eigener Vorgang", item.Model.Title);
|
|
}
|
|
|
|
[Fact]
|
|
public void Load_OnlyOpenFiltertGeschlosseneVorgaenge()
|
|
{
|
|
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
|
var vorgaenge = new FakeVorgangRepository();
|
|
vorgaenge.Add(new Vorgang { Title = "Offen", StudentIds = [student.Id], Status = VorgangStatus.Open });
|
|
vorgaenge.Add(new Vorgang { Title = "Geschlossen", StudentIds = [student.Id], Status = VorgangStatus.Closed });
|
|
|
|
var vm = BuildVm(vorgaenge: vorgaenge, students: new FakeStudents([student]));
|
|
vm.Load(student.Id);
|
|
|
|
Assert.Equal("Offen", Assert.Single(vm.Cases).Model.Title);
|
|
|
|
vm.OnlyOpen = false;
|
|
Assert.Equal(2, vm.Cases.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task HandleWarningNavigation_RevealtBestehendenOffenenVorgangMitPassendemTag_OhneRueckfrage()
|
|
{
|
|
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
|
var vorgaenge = new FakeVorgangRepository();
|
|
vorgaenge.Add(new Vorgang { Title = "Fehlzeiten", StudentIds = [student.Id], Tags = ["Absentismus"] });
|
|
|
|
var vm = BuildVm(vorgaenge: vorgaenge, students: new FakeStudents([student]));
|
|
vm.Load(student.Id);
|
|
|
|
var confirmCalled = false;
|
|
vm.OnConfirmCreateForWarning = _ => { confirmCalled = true; return Task.FromResult(true); };
|
|
|
|
await vm.HandleWarningNavigation("Absentismus", "Fehlzeiten");
|
|
|
|
Assert.False(confirmCalled);
|
|
Assert.True(Assert.Single(vm.Cases).IsRevealed);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task HandleWarningNavigation_IgnoriertGeschlosseneVorgaengeMitPassendemTag()
|
|
{
|
|
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
|
var vorgaenge = new FakeVorgangRepository();
|
|
vorgaenge.Add(new Vorgang
|
|
{ Title = "Alt", StudentIds = [student.Id], Tags = ["Absentismus"], Status = VorgangStatus.Closed });
|
|
|
|
var vm = BuildVm(vorgaenge: vorgaenge, students: new FakeStudents([student]));
|
|
vm.Load(student.Id); // OnlyOpen=true (Default) -> der geschlossene Vorgang ist gar nicht in Cases
|
|
|
|
var confirmCalled = false;
|
|
vm.OnConfirmCreateForWarning = _ => { confirmCalled = true; return Task.FromResult(false); };
|
|
vm.OnEditVorgang = (_, _) => Task.FromResult<Vorgang?>(null);
|
|
|
|
await vm.HandleWarningNavigation("Absentismus", "Fehlzeiten");
|
|
|
|
Assert.True(confirmCalled);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task HandleWarningNavigation_KeinPassenderVorgang_FragtNachUndLegtAnBeiZustimmung()
|
|
{
|
|
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
|
var vorgaenge = new FakeVorgangRepository();
|
|
var vm = BuildVm(vorgaenge: vorgaenge, students: new FakeStudents([student]));
|
|
vm.Load(student.Id);
|
|
|
|
string? confirmedTag = null;
|
|
vm.OnConfirmCreateForWarning = tag => { confirmedTag = tag; return Task.FromResult(true); };
|
|
List<StudentOption>? passedOptions = null;
|
|
Vorgang? passedDraft = null;
|
|
vm.OnEditVorgang = (options, editing) =>
|
|
{
|
|
passedOptions = options;
|
|
passedDraft = editing;
|
|
return Task.FromResult(editing);
|
|
};
|
|
|
|
await vm.HandleWarningNavigation("Hausaufgaben", "Hausaufgaben");
|
|
|
|
Assert.Equal("Hausaufgaben", confirmedTag);
|
|
Assert.Equal(student.Id, Assert.Single(passedOptions!).Id);
|
|
Assert.Equal("Hausaufgaben", passedDraft!.Title);
|
|
Assert.Contains("Hausaufgaben", passedDraft.Tags);
|
|
Assert.Equal([student.Id], passedDraft.StudentIds);
|
|
|
|
var created = Assert.Single(vorgaenge.GetAll());
|
|
Assert.Equal("Hausaufgaben", created.Title);
|
|
Assert.True(Assert.Single(vm.Cases).IsRevealed);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task HandleWarningNavigation_KeinPassenderVorgang_LegtNichtsAnBeiAblehnung()
|
|
{
|
|
var student = new Student { FirstName = "Anna", LastName = "Beispiel" };
|
|
var vorgaenge = new FakeVorgangRepository();
|
|
var vm = BuildVm(vorgaenge: vorgaenge, students: new FakeStudents([student]));
|
|
vm.Load(student.Id);
|
|
|
|
vm.OnConfirmCreateForWarning = _ => Task.FromResult(false);
|
|
var editDialogCalled = false;
|
|
vm.OnEditVorgang = (_, _) => { editDialogCalled = true; return Task.FromResult<Vorgang?>(null); };
|
|
|
|
await vm.HandleWarningNavigation("Verspätungen", "Verspätungen");
|
|
|
|
Assert.False(editDialogCalled);
|
|
Assert.Empty(vorgaenge.GetAll());
|
|
Assert.Empty(vm.Cases);
|
|
}
|
|
}
|