Skip to content

Commit

Permalink
show applicable radio buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
CathLass committed Dec 18, 2024
1 parent 5d58704 commit d538c3b
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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; }

Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@

<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<span class="govuk-caption-l">Induction - @Model.PersonName</span>
<span data-testid="induction-status-caption" class="govuk-caption-l">Induction - @Model.PersonName</span>
<form data-testid="submit-form" action="@LinkGenerator.InductionEditStatus(Model.PersonId, Model.JourneyInstance!.InstanceId)" method="post">
<govuk-radios asp-for="InductionStatus">
<govuk-radios-fieldset>
<govuk-radios-fieldset-legend class="govuk-fieldset__legend--m" />
@foreach (var inductionStatus in InductionStatusRegistry.All)
<govuk-radios-fieldset-legend data-testid="status-choices-legend" class="govuk-fieldset__legend--m" />
@foreach (var inductionStatus in Model.StatusChoices)
{
<govuk-radios-item value="@inductionStatus">@inductionStatus.Name</govuk-radios-item>
<govuk-radios-item value="@inductionStatus.Value" checked="@Model.InductionStatus==inductionStatus.Value">@inductionStatus.Title</govuk-radios-item>
}
</govuk-radios-fieldset>
</govuk-radios>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<InductionStatus> 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<InductionStatusInfo> 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
{
Expand All @@ -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<IActionResult> OnPostAsync()
Expand All @@ -58,11 +83,10 @@ public async Task<IActionResult> 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();
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,43 @@
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;

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;
Expand Down Expand Up @@ -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<IHtmlInputElement>("[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<IHtmlInputElement>("[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<string, string>
{
["InductionStatus"] = "Exempt"
})
};

// Act
var response = await HttpClient.SendAsync(postRequest);

// Assert
journeyInstance = await ReloadJourneyInstance(journeyInstance);
Assert.Equal("Exempt", journeyInstance.State.InductionStatus.GetTitle());
}

private Task<JourneyInstance<EditInductionState>> CreateJourneyInstanceAsync(Guid personId, EditInductionState? state = null) =>
CreateJourneyInstance(
JourneyNames.EditInduction,
Expand Down

0 comments on commit d538c3b

Please sign in to comment.