Enhance school simulation management by introducing a new SchoolWeekDays option, allowing configuration of the number of working days in a week. Update the API to include school week days in responses and enhance documentation to reflect these changes. Revise UI components to support the new management features, ensuring a seamless user experience when hiring and assigning staff. Update localization strings for improved clarity and consistency across the application.
ci / server (push) Failing after 3m37s
ci / client (push) Successful in 13s

This commit is contained in:
Leonid Pershin
2026-08-19 00:47:09 +03:00
parent 94842ab192
commit 2ebc783585
38 changed files with 1837 additions and 208 deletions
+27 -1
View File
@@ -26,6 +26,7 @@ public class SchoolApiTests(AppHostFixture fixture)
// creation form would offer the wrong hour.
Assert.Equal(DateTimeKind.Utc, state.DefaultStartDate.Kind);
Assert.Equal(5d, state.GameMinutesPerRealSecond);
Assert.Equal(5, state.SchoolWeekDays);
Assert.Empty(state.Schools);
}
@@ -167,6 +168,16 @@ public class SchoolApiTests(AppHostFixture fixture)
Assert.Equal(16, classroom.DefaultSeats);
Assert.Empty(classroom.Slots);
Assert.Empty(classroom.Positions);
Assert.NotNull(ru.DayFrame);
Assert.Equal("08:30", ru.DayFrame.FirstLesson);
Assert.Equal(7, ru.DayFrame.LessonCount);
Assert.Equal(3, ru.DayFrame.LongBreakAfter);
Assert.Equal("Учебный день", ru.DayFrame.Label);
Assert.NotNull(en.DayFrame);
Assert.Equal("School day", en.DayFrame.Label);
Assert.Equal("GymHall", Assert.Single(ru.Subjects, subject => subject.DefName == "PhysicalEducation").Room);
Assert.Null(Assert.Single(ru.Subjects, subject => subject.DefName == "Mathematics").Room);
Assert.Contains(ru.Holidays, holiday => holiday.DefName == "SpringBreak");
}
[Fact]
@@ -347,6 +358,7 @@ public class SchoolApiTests(AppHostFixture fixture)
int MaxSchools,
DateTime DefaultStartDate,
double GameMinutesPerRealSecond,
int SchoolWeekDays,
IReadOnlyList<SchoolResponse> Schools);
private sealed record RandomNameResponse(string Name);
@@ -367,6 +379,8 @@ public class SchoolApiTests(AppHostFixture fixture)
IReadOnlyList<DefInfoResponse> Things,
IReadOnlyList<DefInfoResponse> NameSets,
IReadOnlyList<SubjectInfoResponse> Subjects,
DayFrameResponse? DayFrame,
IReadOnlyList<HolidayInfoResponse> Holidays,
MapLayoutResponse DefaultMap);
private sealed record DefInfoResponse(string DefName, string Label);
@@ -382,7 +396,19 @@ public class SchoolApiTests(AppHostFixture fixture)
private sealed record RoomSlotResponse(string Key, string Thing);
private sealed record SubjectInfoResponse(string DefName, string Label);
private sealed record SubjectInfoResponse(string DefName, string Label, string? Room);
private sealed record DayFrameResponse(
string DefName,
string Label,
string FirstLesson,
int LessonCount,
int LessonMinutes,
int BreakMinutes,
int LongBreakAfter,
int LongBreakMinutes);
private sealed record HolidayInfoResponse(string DefName, string Label);
private sealed record MapLayoutResponse(TerritoryResponse? Territory);
@@ -33,6 +33,46 @@ public class StaffingApiTests(AppHostFixture fixture)
Assert.Empty(staffing.Staff);
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "Mathematics");
Assert.Contains(staffing.Uncovered, subject => subject.DefName == "PrimarySchool");
Assert.NotEmpty(staffing.Positions);
Assert.Contains(staffing.Positions, position => position.DefName == "Teacher");
Assert.Contains(staffing.Subjects, subject => subject.DefName == "Mathematics");
Assert.All(staffing.Applicants, applicant => Assert.NotEmpty(applicant.Skills));
}
[Fact]
public async Task Card_OpensAGeneratedApplicant()
{
using var client = fixture.App.CreateHttpClient("server");
await SchoolApiTests.ResetAsync(client);
var school = await SchoolApiTests.CreateAsync(client, "Штат карточка пула", Start);
var staffing = await GetStaffingAsync(client, school.Id);
var generated = staffing.Applicants.First(applicant => !applicant.IsParent);
var card = await client.GetFromJsonAsync<PersonCardResponse>(
$"/api/schools/{school.Id}/people/{Uri.EscapeDataString(generated.Id)}?lang=ru",
TestContext.Current.CancellationToken);
Assert.NotNull(card);
Assert.Equal(generated.Id, card.Id);
Assert.NotEmpty(card.Skills);
}
[Fact]
public async Task Hire_ParentKeepsBothRolesOnTheCard()
{
using var client = fixture.App.CreateHttpClient("server");
await SchoolApiTests.ResetAsync(client);
var school = await SchoolApiTests.CreateAsync(client, "Штат родитель", Start);
var before = await GetStaffingAsync(client, school.Id);
var parent = before.Applicants.First(applicant => applicant.IsParent);
await HireAsync(client, school.Id, parent.Id, "Teacher");
var card = await client.GetFromJsonAsync<PersonCardResponse>(
$"/api/schools/{school.Id}/people/{Uri.EscapeDataString(parent.Id)}?lang=ru",
TestContext.Current.CancellationToken);
Assert.NotNull(card);
Assert.Contains("parent", card.Roles);
Assert.Contains("staff", card.Roles);
}
[Fact]
@@ -217,11 +257,23 @@ public class StaffingApiTests(AppHostFixture fixture)
float Remaining,
IReadOnlyList<UncoveredSubjectResponse> Uncovered,
IReadOnlyList<ApplicantResponse> Applicants,
IReadOnlyList<StaffMemberResponse> Staff);
IReadOnlyList<StaffMemberResponse> Staff,
IReadOnlyList<DefLabelResponse> Positions,
IReadOnlyList<UncoveredSubjectResponse> Subjects);
private sealed record UncoveredSubjectResponse(string DefName, string Label, int GradeMin, int GradeMax, int HoursPerWeek);
private sealed record ApplicantResponse(string Id, string FullName, bool Female, int Age, bool IsParent, float HourlyWageAsk, float MonthlyBase);
private sealed record ApplicantResponse(
string Id,
string FullName,
bool Female,
int Age,
bool IsParent,
float HourlyWageAsk,
float MonthlyBase,
IReadOnlyList<LabeledStatResponse> Skills);
private sealed record LabeledStatResponse(string Id, string Label, string Value);
private sealed record StaffMemberResponse(
string Id,
@@ -237,6 +289,8 @@ public class StaffingApiTests(AppHostFixture fixture)
private sealed record DefLabelResponse(string DefName, string Label);
private sealed record PersonCardResponse(string Id, IReadOnlyList<string> Roles, IReadOnlyList<LabeledStatResponse> Skills);
private sealed record PeopleListResponse(
int Total,
int Page,