From 5d58704c582a0c647ad82ea2992bd6fafdff30be Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Tue, 17 Dec 2024 16:54:48 +0000 Subject: [PATCH 1/8] fill out edit induction status page, move managed by CPD logic to person --- .../DataStore/Postgres/Models/Person.cs | 7 +++++ .../EditInduction/EditInductionState.cs | 2 ++ .../PersonDetail/EditInduction/Status.cshtml | 12 +++++++- .../EditInduction/Status.cshtml.cs | 9 ++++++ .../Persons/PersonDetail/Induction.cshtml.cs | 10 +------ .../DataStore/Postgres/Models/PersonTests.cs | 30 +++++++++++++++++++ 6 files changed, 60 insertions(+), 10 deletions(-) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/Person.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/Person.cs index 2faf9183c..0d423acd5 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/Person.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/Person.cs @@ -322,6 +322,13 @@ public static bool ValidateInductionData( return true; } + public bool InductionStatusManagedByCpd(DateOnly? now) + { + var sevenYearsAgo = now?.AddYears(-7); + return InductionCompletedDate is not null + && InductionCompletedDate < sevenYearsAgo; + } + private static void AssertInductionChangeIsValid( InductionStatus status, DateOnly? startDate, diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs index a170d5e5e..7b229f556 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs @@ -10,6 +10,7 @@ public class EditInductionState : IRegisterJourney requestDataKeys: ["personId"], appendUniqueKey: true); + public string? PersonName { get; set; } public InductionStatus InductionStatus { get; set; } public DateOnly? StartDate { get; set; } public DateOnly? CompletedDate { get; set; } @@ -28,6 +29,7 @@ public async Task EnsureInitializedAsync(TrsDbContext dbContext, Guid personId, var person = await dbContext.Persons .SingleAsync(q => q.PersonId == personId); InductionStatus = person!.InductionStatus; + PersonName = person.LastName; if (JourneyStartPage == null) { JourneyStartPage = startPage; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml index ecd6a2881..4a53c109f 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml @@ -1,7 +1,7 @@ @page "/persons/{PersonId}/edit-induction/status" @model TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction.StatusModel @{ - ViewBag.Title = "Edit status: " + Model.InductionStatus.GetName(); + ViewBag.Title = "What is their induction status?"; } @section BeforeContent { @@ -12,7 +12,17 @@
+ Induction - @Model.PersonName
+ + + + @foreach (var inductionStatus in InductionStatusRegistry.All) + { + @inductionStatus.Name + } + +
Continue diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs index 9901837d0..cf433cc18 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs @@ -1,3 +1,4 @@ +using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using TeachingRecordSystem.Core.DataStore.Postgres; @@ -10,7 +11,10 @@ public class StatusModel : CommonJourneyPage protected TrsDbContext _dbContext; [BindProperty] + [Display(Name = "Select a status")] + [Required(ErrorMessage = "Select a status")] public InductionStatus InductionStatus { get; set; } + public string? PersonName { get; set; } public InductionJourneyPage NextPage { @@ -34,6 +38,7 @@ public StatusModel(TrsLinkGenerator linkGenerator, TrsDbContext dbContext) : bas public void OnGet() { InductionStatus = JourneyInstance!.State.InductionStatus; + PersonName = JourneyInstance!.State.PersonName; } public async Task OnPostAsync() @@ -53,6 +58,10 @@ public async Task OnPostAsync() public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { await JourneyInstance!.State.EnsureInitializedAsync(_dbContext, PersonId, InductionJourneyPage.Status); + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonId = personInfo.PersonId; + PersonName = personInfo.Name; await next(); } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs index 62335778a..03f0188b3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs @@ -68,7 +68,7 @@ public async Task OnGetAsync() StartDate = person!.InductionStartDate; CompletionDate = person!.InductionCompletedDate; ExemptionReasons = person!.InductionExemptionReasons; - _statusIsManagedByCpd = StatusManagedByCpdRule(person!.CpdInductionStatus, person.CpdInductionCompletedDate); + _statusIsManagedByCpd = person.InductionStatusManagedByCpd(clock.Today); _teacherHoldsQualifiedTeacherStatus = TeacherHoldsQualifiedTeacherStatusRule(result?.Contact.dfeta_QTSDate); } @@ -76,12 +76,4 @@ private bool TeacherHoldsQualifiedTeacherStatusRule(DateTime? qtsDate) { return qtsDate is null; } - - private bool StatusManagedByCpdRule(InductionStatus? status, DateOnly? inductionCompletedDate) - { - var sevenYearsAgo = clock.Today.AddYears(-7); - return status is not null - && inductionCompletedDate is not null - && inductionCompletedDate < sevenYearsAgo; - } } diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs index 3ac8b9c31..31a55c00f 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs @@ -1,5 +1,6 @@ using System.Diagnostics; using TeachingRecordSystem.Core.DataStore.Postgres.Models; +using TeachingRecordSystem.Core.Dqt; namespace TeachingRecordSystem.Core.Tests.DataStore.Postgres.Models; @@ -228,4 +229,33 @@ public void TrySetWelshInductionStatus_StatusIsAtLowerPriorityStatus_UpdatesStat Assert.Equal(expectedStatus, person.InductionStatus); Assert.Equal(expectedExemptionReasons, person.InductionExemptionReasons); } + + [Theory] + [InlineData(-3, false)] + [InlineData(-7, true)] + public void InductionManagedByCpd_ReturnsTrue(int yearsSinceCompleted, bool expected) + { + // CML TODO figure out the date-time types + // Arrange + var dateTimeCompleted = Clock.UtcNow.AddYears(yearsSinceCompleted).AddDays(-1); + var dateCompleted = dateTimeCompleted.ToDateOnlyWithDqtBstFix(true); + var person = new Person + { + PersonId = Guid.NewGuid(), + CreatedOn = dateTimeCompleted, + UpdatedOn = dateTimeCompleted, + Trn = "1234567", + FirstName = "Joe", + MiddleName = "", + LastName = "Bloggs", + DateOfBirth = new(1990, 1, 1), + }; + person.SetInductionStatus(InductionStatus.Passed, dateCompleted, dateCompleted, InductionExemptionReasons.None, SystemUser.SystemUserId, Clock.UtcNow, out _); + + // Act + var result = person.InductionStatusManagedByCpd(Clock.UtcNow.ToDateOnlyWithDqtBstFix(true)); + + // Assert + Assert.Equal(expected,result); + } } From d538c3bdf817c15de680395062fe0071c8b82388 Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 18 Dec 2024 15:17:00 +0000 Subject: [PATCH 2/8] show applicable radio buttons --- .../EditInduction/EditInductionState.cs | 7 +- .../PersonDetail/EditInduction/Status.cshtml | 8 +- .../EditInduction/Status.cshtml.cs | 36 ++++- .../ValidationAttributes/NotEqualAttribute.cs | 23 +++ .../EditInduction/EditInductionStatusTests.cs | 140 +++++++++++++++++- 5 files changed, 200 insertions(+), 14 deletions(-) create mode 100644 TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs index 7b229f556..f56c4943d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs @@ -10,13 +10,14 @@ public class EditInductionState : IRegisterJourney requestDataKeys: ["personId"], appendUniqueKey: true); - public string? PersonName { get; set; } public InductionStatus InductionStatus { get; set; } + public InductionStatus InitialInductionStatus{ get; set; } public DateOnly? StartDate { get; set; } public DateOnly? CompletedDate { get; set; } public InductionExemptionReasons? ExemptionReasons { get; set; } public string? ChangeReason { get; set; } public InductionJourneyPage? JourneyStartPage { get; set; } + public bool RecordManagedInCpd { get; set; } public bool Initialized { get; set; } @@ -28,8 +29,8 @@ public async Task EnsureInitializedAsync(TrsDbContext dbContext, Guid personId, } var person = await dbContext.Persons .SingleAsync(q => q.PersonId == personId); - InductionStatus = person!.InductionStatus; - PersonName = person.LastName; + + InitialInductionStatus = person!.InductionStatus; if (JourneyStartPage == null) { JourneyStartPage = startPage; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml index 4a53c109f..c1e1c39c8 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml @@ -12,14 +12,14 @@
- Induction - @Model.PersonName + Induction - @Model.PersonName - - @foreach (var inductionStatus in InductionStatusRegistry.All) + + @foreach (var inductionStatus in Model.StatusChoices) { - @inductionStatus.Name + @inductionStatus.Title } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs index cf433cc18..875b78f2d 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs @@ -2,19 +2,34 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using TeachingRecordSystem.Core.DataStore.Postgres; +using TeachingRecordSystem.SupportUi.ValidationAttributes; namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction; [Journey(JourneyNames.EditInduction), ActivatesJourney, RequireJourneyInstance] public class StatusModel : CommonJourneyPage { + private static List ValidStatusesWhenManagedByCpd = new() { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.FailedInWales }; + protected TrsDbContext _dbContext; + protected IClock _clock; + protected bool InductionStatusManagedByCpd; [BindProperty] [Display(Name = "Select a status")] - [Required(ErrorMessage = "Select a status")] + [NotEqual(InductionStatus.None, ErrorMessage = "Select a status")] public InductionStatus InductionStatus { get; set; } + public InductionStatus InitialInductionStatus { get; set; } public string? PersonName { get; set; } + public IEnumerable StatusChoices + { + get + { + return InductionStatusManagedByCpd ? + InductionStatusRegistry.All.Where(i => ValidStatusesWhenManagedByCpd.Contains(i.Value) && i.Value != InitialInductionStatus) + : InductionStatusRegistry.All.ToArray()[1..].Where(i => i.Value != InitialInductionStatus); + } + } public InductionJourneyPage NextPage { @@ -30,15 +45,25 @@ _ when InductionStatus.RequiresStartDate() => InductionJourneyPage.StartDate, } public string BackLink => LinkGenerator.PersonInduction(PersonId); - public StatusModel(TrsLinkGenerator linkGenerator, TrsDbContext dbContext) : base(linkGenerator) + public StatusModel(TrsLinkGenerator linkGenerator, TrsDbContext dbContext, IClock clock) : base(linkGenerator) { _dbContext = dbContext; + _clock = clock; } - public void OnGet() + public async Task OnGetAsync() { + var person = await _dbContext.Persons.SingleAsync(q => q.PersonId == PersonId); + InductionStatusManagedByCpd = person.InductionStatusManagedByCpd(_clock.UtcNow.ToDateOnlyWithDqtBstFix(true)); // CML TODO understand date-time stuff InductionStatus = JourneyInstance!.State.InductionStatus; - PersonName = JourneyInstance!.State.PersonName; + InitialInductionStatus = JourneyInstance!.State.InitialInductionStatus; + await JourneyInstance!.UpdateStateAsync(state => + { + if (state.InitialInductionStatus == InductionStatus.None) + { + state.InitialInductionStatus = InitialInductionStatus; + } + }); } public async Task OnPostAsync() @@ -58,11 +83,10 @@ public async Task OnPostAsync() public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { await JourneyInstance!.State.EnsureInitializedAsync(_dbContext, PersonId, InductionJourneyPage.Status); + var personInfo = context.HttpContext.GetCurrentPersonFeature(); - PersonId = personInfo.PersonId; PersonName = personInfo.Name; - await next(); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs new file mode 100644 index 000000000..fb47d8b5f --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs @@ -0,0 +1,23 @@ +namespace TeachingRecordSystem.SupportUi.ValidationAttributes; + +using System.ComponentModel.DataAnnotations; + +public class NotEqualAttribute : ValidationAttribute +{ + private readonly object _notAllowedValue; + + public NotEqualAttribute(object notAllowedValue) + { + _notAllowedValue = notAllowedValue; + } + + protected override ValidationResult? IsValid(object value, ValidationContext validationContext) + { + if (value != null && value.Equals(_notAllowedValue)) + { + return new ValidationResult(ErrorMessage ?? $"The value cannot be {_notAllowedValue}."); + } + + return ValidationResult.Success; + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs index 2ee303e71..23cedf04f 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs @@ -1,4 +1,6 @@ +using AngleSharp.Dom; using AngleSharp.Html.Dom; +using TeachingRecordSystem.Core.DataStore.Postgres.Models; using TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInduction; namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Persons.PersonDetail.EditInduction; @@ -6,7 +8,36 @@ namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Persons.PersonDetail.Ed public class EditInductionStatusTests(HostFixture hostFixture) : TestBase(hostFixture) { [Fact] - public async Task ContinueAndCancelButtons_ExistOnPage() + public async Task Get_PageLegend_Expected() + { + // Arrange + InductionStatus inductionStatus = InductionStatus.Passed; + var person = await TestData.CreatePersonAsync(p => p + .WithQts() + .WithFirstName("Alfred") + .WithMiddleName("The") + .WithLastName("Great")); + var expectedCaption = "Induction - Alfred The Great"; + var journeyInstance = await CreateJourneyInstanceAsync( + person.PersonId, + new EditInductionState() + { + Initialized = true, + InductionStatus = inductionStatus + }); + var request = new HttpRequestMessage(HttpMethod.Get, $"/persons/{person.PersonId}/edit-induction/status?{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponseAsync(response); + var caption = doc.GetElementByTestId("induction-status-caption"); + Assert.Equal(expectedCaption, caption!.TextContent); + } + + [Fact] + public async Task Get_ContinueAndCancelButtons_ExistOnPage() { // Arrange InductionStatus inductionStatus = InductionStatus.Passed; @@ -35,6 +66,113 @@ public async Task ContinueAndCancelButtons_ExistOnPage() Assert.Equal("Cancel and return to record", buttons.ElementAt(1)!.TextContent); } + [Theory] + [InlineData(InductionStatus.RequiredToComplete, new InductionStatus[] {InductionStatus.Exempt, InductionStatus.InProgress, InductionStatus.Passed, InductionStatus.Failed, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.Exempt, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.InProgress, InductionStatus.Passed, InductionStatus.Failed, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.InProgress, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.Passed, InductionStatus.Failed, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.Passed, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.InProgress, InductionStatus.Failed, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.Failed, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.InProgress, InductionStatus.Passed, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.FailedInWales, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.InProgress, InductionStatus.Passed, InductionStatus.Failed })] + public async Task Get_InductionNotManagedByCpd_ExpectedRadioButtonsExistOnPage(InductionStatus inductionStatus, InductionStatus[] expectedStatuses) + { + // Arrange + var expectedChoices = expectedStatuses.Select(s => s.ToString()); + + var person = await TestData.CreatePersonAsync(p => p.WithQts()); + + var journeyInstance = await CreateJourneyInstanceAsync( + person.PersonId, + new EditInductionState() + { + Initialized = true, + InitialInductionStatus = inductionStatus + }); + var request = new HttpRequestMessage(HttpMethod.Get, $"/persons/{person.PersonId}/edit-induction/status?{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponseAsync(response); + var statusChoices = doc.QuerySelectorAll("[type=radio]").Select(r => r.Value); + var statusChoicesLegend = doc.GetElementByTestId("status-choices-legend"); + Assert.Equal("Select a status", statusChoicesLegend!.TextContent); + Assert.Equal(expectedChoices, statusChoices); + } + + [Theory] + [InlineData(InductionStatus.Passed, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.Failed, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.FailedInWales, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt })] + public async Task Get_InductionManagedByCpd_ExpectedRadioButtonsExistOnPage(InductionStatus inductionStatus, InductionStatus[] expectedStatuses) + { + // Arrange + var expectedChoices = expectedStatuses.Select(s => s.ToString()); + var overSevenYearsAgo = Clock.Today.AddYears(-7).AddDays(-1); + var person = await TestData.CreatePersonAsync(p => p.WithQts()); + await WithDbContext(async dbContext => + { + dbContext.Attach(person.Person); + person.Person.SetCpdInductionStatus( + InductionStatus.Passed, + startDate: Clock.Today.AddYears(-7).AddMonths(-6), + completedDate: overSevenYearsAgo, + cpdModifiedOn: Clock.UtcNow, + updatedBy: SystemUser.SystemUserId, + now: Clock.UtcNow, + out _); + await dbContext.SaveChangesAsync(); + }); + + var journeyInstance = await CreateJourneyInstanceAsync( + person.PersonId, + new EditInductionState() + { + Initialized = true, + InitialInductionStatus = inductionStatus + }); + var request = new HttpRequestMessage(HttpMethod.Get, $"/persons/{person.PersonId}/edit-induction/status?{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponseAsync(response); + var statusChoices = doc.QuerySelectorAll("[type=radio]").Select(r => r.Value); + var statusChoicesLegend = doc.GetElementByTestId("status-choices-legend"); + Assert.Equal("Select a status", statusChoicesLegend!.TextContent); + Assert.Equal(expectedChoices, statusChoices); + } + + [Fact] + public async Task Post_SelectedStatus_PersistsStatus() + { + // Arrange + var person = await TestData.CreatePersonAsync(p => p.WithQts()); + + var journeyInstance = await CreateJourneyInstanceAsync( + person.PersonId, + new EditInductionState() + { + Initialized = true, + InductionStatus = InductionStatus.Passed + }); + var postRequest = new HttpRequestMessage(HttpMethod.Post, $"/persons/{person.PersonId}/edit-induction/status?{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["InductionStatus"] = "Exempt" + }) + }; + + // Act + var response = await HttpClient.SendAsync(postRequest); + + // Assert + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Equal("Exempt", journeyInstance.State.InductionStatus.GetTitle()); + } + private Task> CreateJourneyInstanceAsync(Guid personId, EditInductionState? state = null) => CreateJourneyInstance( JourneyNames.EditInduction, From 5e7fe83e067290b0b39a7803bf35c4e5cb2546ca Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 18 Dec 2024 15:42:40 +0000 Subject: [PATCH 3/8] model validation --- .../Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs index 875b78f2d..e734c674e 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs @@ -68,6 +68,10 @@ public async Task OnGetAsync() public async Task OnPostAsync() { + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } await JourneyInstance!.UpdateStateAsync(state => { state.InductionStatus = InductionStatus; From ae1cef5f94b3751f8a61e17323391858d654a83e Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 18 Dec 2024 15:51:27 +0000 Subject: [PATCH 4/8] remove warning --- .../Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs | 2 +- .../ValidationAttributes/NotEqualAttribute.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs index e734c674e..52f6145ad 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs @@ -54,7 +54,7 @@ public StatusModel(TrsLinkGenerator linkGenerator, TrsDbContext dbContext, ICloc public async Task OnGetAsync() { var person = await _dbContext.Persons.SingleAsync(q => q.PersonId == PersonId); - InductionStatusManagedByCpd = person.InductionStatusManagedByCpd(_clock.UtcNow.ToDateOnlyWithDqtBstFix(true)); // CML TODO understand date-time stuff + InductionStatusManagedByCpd = person.InductionStatusManagedByCpd(_clock.Today); InductionStatus = JourneyInstance!.State.InductionStatus; InitialInductionStatus = JourneyInstance!.State.InitialInductionStatus; await JourneyInstance!.UpdateStateAsync(state => diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs index fb47d8b5f..c4b2879c9 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/ValidationAttributes/NotEqualAttribute.cs @@ -11,7 +11,7 @@ public NotEqualAttribute(object notAllowedValue) _notAllowedValue = notAllowedValue; } - protected override ValidationResult? IsValid(object value, ValidationContext validationContext) + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { if (value != null && value.Equals(_notAllowedValue)) { From 5d1dddff67355a8364cbede2a07b45fa10d91ded Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 18 Dec 2024 16:06:37 +0000 Subject: [PATCH 5/8] test for page validation error --- .../EditInduction/EditInductionStatusTests.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs index 23cedf04f..10097bae2 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs @@ -173,6 +173,34 @@ public async Task Post_SelectedStatus_PersistsStatus() Assert.Equal("Exempt", journeyInstance.State.InductionStatus.GetTitle()); } + [Fact] + public async Task Post_NoSelectedStatus_ShowsPageError() + { + // Arrange + var person = await TestData.CreatePersonAsync(p => p.WithQts()); + + var journeyInstance = await CreateJourneyInstanceAsync( + person.PersonId, + new EditInductionState() + { + Initialized = true, + InductionStatus = InductionStatus.Passed + }); + var postRequest = new HttpRequestMessage(HttpMethod.Post, $"/persons/{person.PersonId}/edit-induction/status?{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["InductionStatus"] = InductionStatus.None.ToString() + }) + }; + + // Act + var response = await HttpClient.SendAsync(postRequest); + + // Assert + await AssertEx.HtmlResponseHasErrorAsync(response, nameof(StatusModel.InductionStatus), "Select a status"); + } + private Task> CreateJourneyInstanceAsync(Guid personId, EditInductionState? state = null) => CreateJourneyInstance( JourneyNames.EditInduction, From e7c519413f5534f13770da6b3c116339b89c6478 Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 18 Dec 2024 16:30:18 +0000 Subject: [PATCH 6/8] warning message --- .../PersonDetail/EditInduction/Status.cshtml | 5 ++- .../EditInduction/Status.cshtml.cs | 18 ++++++++++- .../Persons/PersonDetail/Induction.cshtml.cs | 2 +- .../EditInduction/EditInductionStatusTests.cs | 32 +++++++++++++++++++ .../Persons/PersonDetail/InductionTests.cs | 2 +- 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml index c1e1c39c8..f5b80cba2 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml @@ -9,7 +9,10 @@ }

@ViewBag.Title

- +@if (!String.IsNullOrEmpty(Model.StatusWarningMessage)) +{ + @Model.StatusWarningMessage +}
Induction - @Model.PersonName diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs index 52f6145ad..b2ad62658 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs @@ -9,7 +9,8 @@ namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.EditInductio [Journey(JourneyNames.EditInduction), ActivatesJourney, RequireJourneyInstance] public class StatusModel : CommonJourneyPage { - private static List ValidStatusesWhenManagedByCpd = new() { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.FailedInWales }; + private static readonly List ValidStatusesWhenManagedByCpd = new() { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.FailedInWales }; + private const string InductionIsManagedByCpdWarning = "To change this teacher’s induction status to passed, failed, or in progress, use the Record inductions as an appropriate body service."; protected TrsDbContext _dbContext; protected IClock _clock; @@ -30,6 +31,20 @@ public IEnumerable StatusChoices : InductionStatusRegistry.All.ToArray()[1..].Where(i => i.Value != InitialInductionStatus); } } + public string? StatusWarningMessage + { + get + { + if (InductionStatusManagedByCpd) + { + return InductionIsManagedByCpdWarning; + } + else + { + return null; + } + } + } public InductionJourneyPage NextPage { @@ -43,6 +58,7 @@ _ when InductionStatus.RequiresStartDate() => InductionJourneyPage.StartDate, }; } } + public string BackLink => LinkGenerator.PersonInduction(PersonId); public StatusModel(TrsLinkGenerator linkGenerator, TrsDbContext dbContext, IClock clock) : base(linkGenerator) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs index 03f0188b3..4972c4512 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Induction.cshtml.cs @@ -9,7 +9,7 @@ namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail; public class InductionModel(TrsDbContext dbContext, ICrmQueryDispatcher crmQueryDispatcher, IClock clock) : PageModel { private const string NoQualifiedTeacherStatusWarning = "This teacher has not been awarded QTS and is therefore ineligible for induction."; - private const string InductionIsManagedByCpdWarning = "To change a teacher\u2019s induction status to passed, failed, or in progress, use the Record inductions as an appropriate body service."; + private const string InductionIsManagedByCpdWarning = "To change this teacher’s induction status to passed, failed, or in progress, use the Record inductions as an appropriate body service."; private bool _statusIsManagedByCpd; private bool _teacherHoldsQualifiedTeacherStatus; diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs index 10097bae2..c1d514c48 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs @@ -201,6 +201,38 @@ public async Task Post_NoSelectedStatus_ShowsPageError() await AssertEx.HtmlResponseHasErrorAsync(response, nameof(StatusModel.InductionStatus), "Select a status"); } + [Fact] + public async Task Get_WithPersonIdForPersonWithInductionStatusManagedByCPD_ShowsWarning() + { + //Arrange + var expectedWarning = "To change this teacher’s induction status "; + var overSevenYearsAgo = Clock.Today.AddYears(-7).AddDays(-1); + + var person = await TestData.CreatePersonAsync(); + await WithDbContext(async dbContext => + { + dbContext.Attach(person.Person); + person.Person.SetCpdInductionStatus( + InductionStatus.Passed, + startDate: Clock.Today.AddYears(-7).AddMonths(-6), + completedDate: overSevenYearsAgo, + cpdModifiedOn: Clock.UtcNow, + updatedBy: SystemUser.SystemUserId, + now: Clock.UtcNow, + out _); + await dbContext.SaveChangesAsync(); + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/persons/{person.ContactId}/induction"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponseAsync(response); + Assert.Contains(expectedWarning, doc.GetElementByTestId("induction-status-warning")!.Children[1].TextContent); + } + private Task> CreateJourneyInstanceAsync(Guid personId, EditInductionState? state = null) => CreateJourneyInstance( JourneyNames.EditInduction, diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/InductionTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/InductionTests.cs index 171050df4..976b7d505 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/InductionTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/InductionTests.cs @@ -226,7 +226,7 @@ public async Task Get_WithPersonIdForPersonWithInductionStatusRequiringCompletio public async Task Get_WithPersonIdForPersonWithInductionStatusManagedByCPD_ShowsWarning() { //Arrange - var expectedWarning = "To change a teacher’s induction status "; + var expectedWarning = "To change this teacher’s induction status "; var overSevenYearsAgo = Clock.Today.AddYears(-7).AddDays(-1); var person = await TestData.CreatePersonAsync(); From cd6bf76c9c5f22215aa9d94b0b4bd4cd46aa4659 Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Wed, 18 Dec 2024 16:45:47 +0000 Subject: [PATCH 7/8] pass linting --- .../Persons/PersonDetail/EditInduction/EditInductionState.cs | 2 +- .../Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs | 2 +- .../DataStore/Postgres/Models/PersonTests.cs | 2 +- .../PersonDetail/EditInduction/EditInductionStatusTests.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs index f56c4943d..f389fb78c 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/EditInductionState.cs @@ -11,7 +11,7 @@ public class EditInductionState : IRegisterJourney appendUniqueKey: true); public InductionStatus InductionStatus { get; set; } - public InductionStatus InitialInductionStatus{ get; set; } + public InductionStatus InitialInductionStatus { get; set; } public DateOnly? StartDate { get; set; } public DateOnly? CompletedDate { get; set; } public InductionExemptionReasons? ExemptionReasons { get; set; } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs index b2ad62658..b656e181a 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs @@ -103,7 +103,7 @@ public async Task OnPostAsync() public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) { await JourneyInstance!.State.EnsureInitializedAsync(_dbContext, PersonId, InductionJourneyPage.Status); - + var personInfo = context.HttpContext.GetCurrentPersonFeature(); PersonId = personInfo.PersonId; PersonName = personInfo.Name; diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs index 31a55c00f..ab1ff3c3b 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.Core.Tests/DataStore/Postgres/Models/PersonTests.cs @@ -256,6 +256,6 @@ public void InductionManagedByCpd_ReturnsTrue(int yearsSinceCompleted, bool expe var result = person.InductionStatusManagedByCpd(Clock.UtcNow.ToDateOnlyWithDqtBstFix(true)); // Assert - Assert.Equal(expected,result); + Assert.Equal(expected, result); } } diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs index c1d514c48..4c344dc45 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs @@ -67,7 +67,7 @@ public async Task Get_ContinueAndCancelButtons_ExistOnPage() } [Theory] - [InlineData(InductionStatus.RequiredToComplete, new InductionStatus[] {InductionStatus.Exempt, InductionStatus.InProgress, InductionStatus.Passed, InductionStatus.Failed, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.RequiredToComplete, new InductionStatus[] { InductionStatus.Exempt, InductionStatus.InProgress, InductionStatus.Passed, InductionStatus.Failed, InductionStatus.FailedInWales })] [InlineData(InductionStatus.Exempt, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.InProgress, InductionStatus.Passed, InductionStatus.Failed, InductionStatus.FailedInWales })] [InlineData(InductionStatus.InProgress, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.Passed, InductionStatus.Failed, InductionStatus.FailedInWales })] [InlineData(InductionStatus.Passed, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.InProgress, InductionStatus.Failed, InductionStatus.FailedInWales })] From 166247a062ff322b0b5cb30ab44bd1e051298f58 Mon Sep 17 00:00:00 2001 From: CLAWLOR Date: Thu, 19 Dec 2024 08:21:29 +0000 Subject: [PATCH 8/8] bug fix and tests --- .../EditInduction/Status.cshtml.cs | 3 ++ .../EditInduction/EditInductionStatusTests.cs | 52 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs index b656e181a..6cab52d31 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/EditInduction/Status.cshtml.cs @@ -86,6 +86,9 @@ public async Task OnPostAsync() { if (!ModelState.IsValid) { + var person = await _dbContext.Persons.SingleAsync(q => q.PersonId == PersonId); + InductionStatusManagedByCpd = person.InductionStatusManagedByCpd(_clock.Today); + InitialInductionStatus = JourneyInstance!.State.InitialInductionStatus; return this.PageWithErrors(); } await JourneyInstance!.UpdateStateAsync(state => diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs index 4c344dc45..d46a428e7 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Persons/PersonDetail/EditInduction/EditInductionStatusTests.cs @@ -201,8 +201,56 @@ public async Task Post_NoSelectedStatus_ShowsPageError() await AssertEx.HtmlResponseHasErrorAsync(response, nameof(StatusModel.InductionStatus), "Select a status"); } + [Theory] + [InlineData(InductionStatus.Passed, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.Failed, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt, InductionStatus.FailedInWales })] + [InlineData(InductionStatus.FailedInWales, new InductionStatus[] { InductionStatus.RequiredToComplete, InductionStatus.Exempt })] + public async Task Post_PersonManagedByCpd_NoSelectedStatus_ShowsPageError(InductionStatus initialInductionStatus, InductionStatus[] expectedChoices) + { + var overSevenYearsAgo = Clock.Today.AddYears(-7).AddDays(-1); + var person = await TestData.CreatePersonAsync(p => p.WithQts()); + await WithDbContext(async dbContext => + { + dbContext.Attach(person.Person); + person.Person.SetCpdInductionStatus( + InductionStatus.Passed, + startDate: Clock.Today.AddYears(-7).AddMonths(-6), + completedDate: overSevenYearsAgo, + cpdModifiedOn: Clock.UtcNow, + updatedBy: SystemUser.SystemUserId, + now: Clock.UtcNow, + out _); + await dbContext.SaveChangesAsync(); + }); + var journeyInstance = await CreateJourneyInstanceAsync( + person.PersonId, + new EditInductionState() + { + Initialized = true, + InitialInductionStatus = initialInductionStatus + }); + var postRequest = new HttpRequestMessage(HttpMethod.Post, $"/persons/{person.PersonId}/edit-induction/status?{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["InductionStatus"] = InductionStatus.None.ToString() + }) + }; + + // Act + var response = await HttpClient.SendAsync(postRequest); + + // Assert + await AssertEx.HtmlResponseHasErrorAsync(response, nameof(StatusModel.InductionStatus), "Select a status"); + var doc = await response.GetDocumentAsync(); + var statusChoices = doc.QuerySelectorAll("[type=radio]").Select(r => r.Value); + var statusChoicesLegend = doc.GetElementByTestId("status-choices-legend"); + Assert.Equal("Select a status", statusChoicesLegend!.TextContent); + Assert.Equal(expectedChoices.Select(c => c.ToString()), statusChoices); + } + [Fact] - public async Task Get_WithPersonIdForPersonWithInductionStatusManagedByCPD_ShowsWarning() + public async Task Get_ForPersonWithInductionStatusManagedByCPD_ShowsWarning() { //Arrange var expectedWarning = "To change this teacher’s induction status "; @@ -230,7 +278,7 @@ await WithDbContext(async dbContext => // Assert var doc = await AssertEx.HtmlResponseAsync(response); - Assert.Contains(expectedWarning, doc.GetElementByTestId("induction-status-warning")!.Children[1].TextContent); + Assert.Contains(expectedWarning, doc!.GetElementByTestId("induction-status-warning")!.Children[1].TextContent); } private Task> CreateJourneyInstanceAsync(Guid personId, EditInductionState? state = null) =>