From 41933b0631c2f94f3854a93f918a174fadd7dcde Mon Sep 17 00:00:00 2001 From: Sam C <156680559+sam-c-dfe@users.noreply.github.com> Date: Mon, 8 Jul 2024 10:22:13 +0100 Subject: [PATCH] Initial commit of the qualification list page (#231) * Initial commit of the qualification list page. Needs unit tests fixing etc. WIP * Fixed build and unit tests * Refactored common logic out into UserJourneyCookieService so it can be shared by multiple controllers * Added chevron to the view * Fixed journey tests * Added new e2e test * Added aria label to search box and added hover & visited styling to the chevron * ReSharper & Sonar suggestions. --------- Co-authored-by: RobertGHippo --- .../Entities/QualificationListPage.cs | 20 +++ .../ContentfulContentFilterService.cs | 12 +- .../Services/IContentFilterService.cs | 2 +- .../Content/MockContentfulFilterService.cs | 2 +- .../Content/MockContentfulService.cs | 11 +- .../QualificationDetailsController.cs | 96 +++++++++-- .../Controllers/QuestionsController.cs | 46 ++---- .../Models/Content/BasicQualificationModel.cs | 12 ++ .../Models/Content/FilterModel.cs | 12 ++ .../Content/QualificationDetailsModel.cs | 7 +- .../Models/Content/QualificationListModel.cs | 22 ++- .../IUserJourneyCookieService.cs | 5 + .../UserJourneyCookieService.cs | 55 ++++++ .../Views/QualificationDetails/Get.cshtml | 87 +++++----- .../Views/Shared/_Header.cshtml | 5 + .../wwwroot/css/site.css | 29 ++++ .../e2e/journey/back-button-spec.cy.js | 4 +- .../cypress/e2e/journey/journey-spec.cy.js | 4 +- .../e2e/pages/qualification-list-spec.cy.js | 29 ++++ .../cypress/e2e/shared/urls-to-check.js | 4 +- .../QualificationDetailsControllerTests.cs | 77 +++++---- .../Controllers/QuestionsControllerTests.cs | 28 ++-- .../Mocks/MockContentfulFilterServiceTests.cs | 2 +- .../ContentfulContentFilterServiceTests.cs | 60 +++++-- .../Services/UserJourneyCookieServiceTests.cs | 156 ++++++++++++++++++ 25 files changed, 634 insertions(+), 153 deletions(-) create mode 100644 src/Dfe.EarlyYearsQualification.Web/Models/Content/BasicQualificationModel.cs create mode 100644 src/Dfe.EarlyYearsQualification.Web/Models/Content/FilterModel.cs create mode 100644 tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-list-spec.cy.js diff --git a/src/Dfe.EarlyYearsQualification.Content/Entities/QualificationListPage.cs b/src/Dfe.EarlyYearsQualification.Content/Entities/QualificationListPage.cs index 8c7b5b3d..66500adc 100644 --- a/src/Dfe.EarlyYearsQualification.Content/Entities/QualificationListPage.cs +++ b/src/Dfe.EarlyYearsQualification.Content/Entities/QualificationListPage.cs @@ -1,3 +1,5 @@ +using Contentful.Core.Models; + namespace Dfe.EarlyYearsQualification.Content.Entities; public class QualificationListPage @@ -5,4 +7,22 @@ public class QualificationListPage public string Header { get; init; } = string.Empty; public NavigationLink? BackButton { get; init; } + + public string SingleQualificationFoundText { get; init; } = string.Empty; + + public string MultipleQualificationsFoundText { get; init; } = string.Empty; + + public Document? PreSearchBoxContent { get; init; } + + public string SearchButtonText { get; init; } = string.Empty; + + public string LevelHeading { get; init; } = string.Empty; + + public string AwardingOrganisationHeading { get; init; } = string.Empty; + + public Document? PostQualificationListContent { get; init; } + + public string SearchCriteriaHeading { get; init; } = string.Empty; + + public Document? PostSearchCriteriaContent { get; init; } } \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Content/Services/ContentfulContentFilterService.cs b/src/Dfe.EarlyYearsQualification.Content/Services/ContentfulContentFilterService.cs index dc31d4a6..5d71f692 100644 --- a/src/Dfe.EarlyYearsQualification.Content/Services/ContentfulContentFilterService.cs +++ b/src/Dfe.EarlyYearsQualification.Content/Services/ContentfulContentFilterService.cs @@ -38,12 +38,13 @@ private static readonly ReadOnlyDictionary public QueryBuilder QueryBuilder { get; init; } = QueryBuilder.New; public async Task> GetFilteredQualifications(int? level, int? startDateMonth, - int? startDateYear) + int? startDateYear, string? awardingOrganisation) { - logger.LogInformation("Filtering options passed in - level: {Level}, startDateMonth: {StartDateMonth}, startDateYear: {StartDateYear}", + logger.LogInformation("Filtering options passed in - level: {Level}, startDateMonth: {StartDateMonth}, startDateYear: {StartDateYear}, awardingOrganisation: {AwardingOrganisation}", level, startDateMonth, - startDateYear); + startDateYear, + awardingOrganisation); // create query builder var queryBuilder = QueryBuilder.ContentTypeIs(ContentTypes.Qualification); @@ -53,6 +54,11 @@ public async Task> GetFilteredQualifications(int? level, int queryBuilder = queryBuilder.FieldEquals("fields.qualificationLevel", level.Value.ToString()); } + if (!string.IsNullOrEmpty(awardingOrganisation)) + { + queryBuilder = queryBuilder.FieldEquals("fields.awardingOrganisationTitle", awardingOrganisation); + } + // get qualifications ContentfulCollection? qualifications; try diff --git a/src/Dfe.EarlyYearsQualification.Content/Services/IContentFilterService.cs b/src/Dfe.EarlyYearsQualification.Content/Services/IContentFilterService.cs index 388dae64..8480a55f 100644 --- a/src/Dfe.EarlyYearsQualification.Content/Services/IContentFilterService.cs +++ b/src/Dfe.EarlyYearsQualification.Content/Services/IContentFilterService.cs @@ -4,5 +4,5 @@ namespace Dfe.EarlyYearsQualification.Content.Services; public interface IContentFilterService { - Task> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear); + Task> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear, string? awardingOrganisation); } \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulFilterService.cs b/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulFilterService.cs index 5540d53b..0ed1e5c3 100644 --- a/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulFilterService.cs +++ b/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulFilterService.cs @@ -5,7 +5,7 @@ namespace Dfe.EarlyYearsQualification.Mock.Content; public class MockContentfulFilterService : IContentFilterService { - public Task> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear) + public Task> GetFilteredQualifications(int? level, int? startDateMonth, int? startDateYear, string? awardingOrganisation) { var qualifications = new List diff --git a/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulService.cs b/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulService.cs index 569bfb15..8d43a093 100644 --- a/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulService.cs +++ b/src/Dfe.EarlyYearsQualification.Mock/Content/MockContentfulService.cs @@ -212,7 +212,16 @@ public Task> GetQualifications() DisplayText = "TEST", Href = "/questions/what-is-the-awarding-organisation", OpenInNewTab = false - } + }, + LevelHeading = "Level", + AwardingOrganisationHeading = "Awarding organisation", + SearchButtonText = "Refine", + SearchCriteriaHeading = "Your search", + MultipleQualificationsFoundText = "qualifications found", + SingleQualificationFoundText = "qualification found", + PreSearchBoxContent = ContentfulContentHelper.Text("Pre search box content"), + PostQualificationListContent = ContentfulContentHelper.Text("Post qualification list content"), + PostSearchCriteriaContent = ContentfulContentHelper.Text("Post search criteria content") }); } diff --git a/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs b/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs index 80b04f61..98888d83 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Controllers/QualificationDetailsController.cs @@ -1,8 +1,8 @@ +using System.Globalization; using Dfe.EarlyYearsQualification.Content.Entities; using Dfe.EarlyYearsQualification.Content.Renderers.Entities; using Dfe.EarlyYearsQualification.Content.Services; using Dfe.EarlyYearsQualification.Web.Controllers.Base; -using Dfe.EarlyYearsQualification.Web.Models; using Dfe.EarlyYearsQualification.Web.Models.Content; using Dfe.EarlyYearsQualification.Web.Services.UserJourneyCookieService; using Microsoft.AspNetCore.Http.Extensions; @@ -14,7 +14,9 @@ namespace Dfe.EarlyYearsQualification.Web.Controllers; public class QualificationDetailsController( ILogger logger, IContentService contentService, - IGovUkInsetTextRenderer renderer, + IContentFilterService contentFilterService, + IGovUkInsetTextRenderer govUkInsetTextRenderer, + IHtmlRenderer htmlRenderer, IUserJourneyCookieService userJourneyCookieService) : ServiceController { @@ -28,9 +30,7 @@ public async Task Get() return RedirectToAction("Index", "Error"); } - var filterParams = userJourneyCookieService.GetUserJourneyModelFromCookie(); - - var model = MapList(listPageContent, filterParams); + var model = await MapList(listPageContent, await GetFilteredQualifications()); return View(model); } @@ -38,7 +38,7 @@ public async Task Get() [HttpGet("qualification-details/{qualificationId}")] public async Task Index(string qualificationId) { - if (string.IsNullOrEmpty(qualificationId)) + if (!ModelState.IsValid || string.IsNullOrEmpty(qualificationId)) { return BadRequest(); } @@ -64,16 +64,90 @@ public async Task Index(string qualificationId) return View(model); } - private static QualificationListModel MapList(QualificationListPage content, UserJourneyModel? filters) + private async Task> GetFilteredQualifications() { + var level = userJourneyCookieService.GetLevelOfQualification(); + var (startDateMonth, startDateYear) = userJourneyCookieService.GetWhenWasQualificationAwarded(); + var awardingOrganisation = userJourneyCookieService.GetAwardingOrganisation(); + + return await contentFilterService.GetFilteredQualifications(level, startDateMonth, startDateYear, + awardingOrganisation); + } + + private async Task MapList(QualificationListPage content, + List? qualifications) + { + var basicQualificationsModels = GetBasicQualificationsModels(qualifications); + + var filterModel = GetFilterModel(); + return new QualificationListModel { BackButton = content.BackButton, - Filters = filters, - Header = content.Header + Filters = filterModel, + Header = content.Header, + SingleQualificationFoundText = content.SingleQualificationFoundText, + MultipleQualificationsFoundText = content.MultipleQualificationsFoundText, + PreSearchBoxContent = await htmlRenderer.ToHtml(content.PreSearchBoxContent), + SearchButtonText = content.SearchButtonText, + LevelHeading = content.LevelHeading, + AwardingOrganisationHeading = content.AwardingOrganisationHeading, + PostSearchCriteriaContent = await htmlRenderer.ToHtml(content.PostSearchCriteriaContent), + PostQualificationListContent = await htmlRenderer.ToHtml(content.PostQualificationListContent), + SearchCriteriaHeading = content.SearchCriteriaHeading, + Qualifications = basicQualificationsModels.OrderBy(x => x.QualificationName).ToList() }; } + private FilterModel GetFilterModel() + { + var filterModel = new FilterModel + { + Country = userJourneyCookieService.GetWhereWasQualificationAwarded()! + }; + + var (startDateMonth, startDateYear) = userJourneyCookieService.GetWhenWasQualificationAwarded(); + if (startDateMonth is not null && startDateYear is not null) + { + var date = new DateOnly(startDateYear.Value, startDateMonth.Value, 1); + filterModel.StartDate = $"{date.ToString("MMMM", CultureInfo.InvariantCulture)} {startDateYear.Value}"; + } + + var level = userJourneyCookieService.GetLevelOfQualification(); + if (level is not null && level > 0) + { + filterModel.Level = $"Level {level}"; + } + + var awardingOrganisation = userJourneyCookieService.GetAwardingOrganisation(); + if (!string.IsNullOrEmpty(awardingOrganisation)) + { + filterModel.AwardingOrganisation = awardingOrganisation; + } + + return filterModel; + } + + private static List GetBasicQualificationsModels(List? qualifications) + { + var basicQualificationsModels = new List(); + if (qualifications is not null && qualifications.Count > 0) + { + foreach (var qualification in qualifications) + { + basicQualificationsModels.Add(new BasicQualificationModel + { + QualificationId = qualification.QualificationId, + QualificationLevel = qualification.QualificationLevel, + QualificationName = qualification.QualificationName, + AwardingOrganisationTitle = qualification.AwardingOrganisationTitle + }); + } + } + + return basicQualificationsModels; + } + private async Task MapDetails(Qualification qualification, DetailsPage content) { return new QualificationDetailsModel @@ -95,11 +169,11 @@ private async Task MapDetails(Qualification qualifica BookmarkText = content.BookmarkText, CheckAnotherQualificationHeading = content.CheckAnotherQualificationHeading, CheckAnotherQualificationText = - await renderer.ToHtml(content.CheckAnotherQualificationText), + await govUkInsetTextRenderer.ToHtml(content.CheckAnotherQualificationText), DateAddedLabel = content.DateAddedLabel, DateOfCheckLabel = content.DateOfCheckLabel, FurtherInfoHeading = content.FurtherInfoHeading, - FurtherInfoText = await renderer.ToHtml(content.FurtherInfoText), + FurtherInfoText = await govUkInsetTextRenderer.ToHtml(content.FurtherInfoText), LevelLabel = content.LevelLabel, MainHeader = content.MainHeader, QualificationNumberLabel = content.QualificationNumberLabel diff --git a/src/Dfe.EarlyYearsQualification.Web/Controllers/QuestionsController.cs b/src/Dfe.EarlyYearsQualification.Web/Controllers/QuestionsController.cs index 4f98decb..29970c20 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Controllers/QuestionsController.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Controllers/QuestionsController.cs @@ -127,21 +127,6 @@ public async Task WhatLevelIsTheQualification(RadioQuestionModel return RedirectToAction(nameof(this.WhatIsTheAwardingOrganisation)); } - private bool WithinDateRange() - { - var cookie = userJourneyCookieService.GetUserJourneyModelFromCookie(); - var qualificationAwardedDateSplit = cookie.WhenWasQualificationAwarded.Split('/'); - if (qualificationAwardedDateSplit.Length == 2 - && int.TryParse(qualificationAwardedDateSplit[0], out var parsedStartMonth) - && int.TryParse(qualificationAwardedDateSplit[1], out var parsedStartYear)) - { - var date = new DateOnly(parsedStartYear, parsedStartMonth, 1); - return date >= new DateOnly(2014, 09, 01) && date <= new DateOnly(2019, 08, 31); - } - - return false; - } - [HttpGet("what-is-the-awarding-organisation")] public async Task WhatIsTheAwardingOrganisation() { @@ -186,28 +171,23 @@ public async Task WhatIsTheAwardingOrganisation(DropdownQuestionM return RedirectToAction("Get", "QualificationDetails"); } - private async Task> GetFilteredQualifications() + private bool WithinDateRange() { - var cookie = userJourneyCookieService.GetUserJourneyModelFromCookie(); - - int? level = null; - if (int.TryParse(cookie.LevelOfQualification, out var parsedLevel)) - { - level = parsedLevel; - } - - int? startDateMonth = null; - int? startDateYear = null; - var qualificationAwardedDateSplit = cookie.WhenWasQualificationAwarded.Split('/'); - if (qualificationAwardedDateSplit.Length == 2 - && int.TryParse(qualificationAwardedDateSplit[0], out var parsedStartMonth) - && int.TryParse(qualificationAwardedDateSplit[1], out var parsedStartYear)) + (int? startDateMonth, int? startDateYear) = userJourneyCookieService.GetWhenWasQualificationAwarded(); + if (startDateMonth is not null && startDateYear is not null) { - startDateMonth = parsedStartMonth; - startDateYear = parsedStartYear; + var date = new DateOnly(startDateYear.Value, startDateMonth.Value, 1); + return date >= new DateOnly(2014, 09, 01) && date <= new DateOnly(2019, 08, 31); } - return await contentFilterService.GetFilteredQualifications(level, startDateMonth, startDateYear); + return false; + } + + private async Task> GetFilteredQualifications() + { + int? level = userJourneyCookieService.GetLevelOfQualification(); + (int? startDateMonth, int? startDateYear) = userJourneyCookieService.GetWhenWasQualificationAwarded(); + return await contentFilterService.GetFilteredQualifications(level, startDateMonth, startDateYear, null); } private async Task GetRadioView(string questionPageId, string actionName, string controllerName) diff --git a/src/Dfe.EarlyYearsQualification.Web/Models/Content/BasicQualificationModel.cs b/src/Dfe.EarlyYearsQualification.Web/Models/Content/BasicQualificationModel.cs new file mode 100644 index 00000000..b4f91ba2 --- /dev/null +++ b/src/Dfe.EarlyYearsQualification.Web/Models/Content/BasicQualificationModel.cs @@ -0,0 +1,12 @@ +namespace Dfe.EarlyYearsQualification.Web.Models.Content; + +public class BasicQualificationModel +{ + public string QualificationId { get; init; } = string.Empty; + + public string QualificationName { get; init; } = string.Empty; + + public string AwardingOrganisationTitle { get; init; } = string.Empty; + + public int QualificationLevel { get; init; } +} \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Models/Content/FilterModel.cs b/src/Dfe.EarlyYearsQualification.Web/Models/Content/FilterModel.cs new file mode 100644 index 00000000..1e6b3e4b --- /dev/null +++ b/src/Dfe.EarlyYearsQualification.Web/Models/Content/FilterModel.cs @@ -0,0 +1,12 @@ +namespace Dfe.EarlyYearsQualification.Web.Models.Content; + +public class FilterModel +{ + public string Country { get; init; } = string.Empty; + + public string StartDate { get; set; } = string.Empty; + + public string Level { get; set; } = "Any level"; + + public string AwardingOrganisation { get; set; } = "Any organisation"; +} \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationDetailsModel.cs b/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationDetailsModel.cs index 938f2155..812af847 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationDetailsModel.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationDetailsModel.cs @@ -2,13 +2,8 @@ namespace Dfe.EarlyYearsQualification.Web.Models.Content; -public class QualificationDetailsModel +public class QualificationDetailsModel : BasicQualificationModel { - public string QualificationId { get; init; } = string.Empty; - public string QualificationName { get; init; } = string.Empty; - public string AwardingOrganisationTitle { get; init; } = string.Empty; - public int QualificationLevel { get; init; } - public string? FromWhichYear { get; init; } public string? ToWhichYear { get; init; } public string? QualificationNumber { get; init; } diff --git a/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationListModel.cs b/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationListModel.cs index 28acd14d..39d87fb4 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationListModel.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Models/Content/QualificationListModel.cs @@ -6,7 +6,27 @@ public class QualificationListModel { public string Header { get; init; } = string.Empty; - public UserJourneyModel? Filters { get; init; } + public FilterModel Filters { get; init; } = new(); public NavigationLink? BackButton { get; init; } + + public string SingleQualificationFoundText { get; init; } = string.Empty; + + public string MultipleQualificationsFoundText { get; init; } = string.Empty; + + public string PreSearchBoxContent { get; init; } = string.Empty; + + public string SearchButtonText { get; init; } = string.Empty; + + public string LevelHeading { get; init; } = string.Empty; + + public string AwardingOrganisationHeading { get; init; } = string.Empty; + + public string PostQualificationListContent { get; init; } = string.Empty; + + public string SearchCriteriaHeading { get; init; } = string.Empty; + + public string PostSearchCriteriaContent { get; init; } = string.Empty; + + public List Qualifications { get; init; } = []; } \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/IUserJourneyCookieService.cs b/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/IUserJourneyCookieService.cs index 69a01146..2d3d0209 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/IUserJourneyCookieService.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/IUserJourneyCookieService.cs @@ -10,4 +10,9 @@ public interface IUserJourneyCookieService public void SetAwardingOrganisation(string awardingOrganisation); public UserJourneyModel GetUserJourneyModelFromCookie(); public void ResetUserJourneyCookie(); + + public string? GetWhereWasQualificationAwarded(); + public (int? startMonth, int? startYear) GetWhenWasQualificationAwarded(); + public int? GetLevelOfQualification(); + public string? GetAwardingOrganisation(); } \ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/UserJourneyCookieService.cs b/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/UserJourneyCookieService.cs index a20ee2b7..3a85696d 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/UserJourneyCookieService.cs +++ b/src/Dfe.EarlyYearsQualification.Web/Services/UserJourneyCookieService/UserJourneyCookieService.cs @@ -1,3 +1,4 @@ +using System.Globalization; using System.Text.Json; using Dfe.EarlyYearsQualification.Web.Constants; using Dfe.EarlyYearsQualification.Web.Models; @@ -77,6 +78,60 @@ public void ResetUserJourneyCookie() SetJourneyCookie(new UserJourneyModel()); } + public string? GetWhereWasQualificationAwarded() + { + var cookie = GetUserJourneyModelFromCookie(); + string? awardingCountry = null; + if (!string.IsNullOrEmpty(cookie.WhereWasQualificationAwarded)) + { + awardingCountry = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(cookie.WhereWasQualificationAwarded); + } + + return awardingCountry; + } + + public (int? startMonth, int? startYear) GetWhenWasQualificationAwarded() + { + var cookie = GetUserJourneyModelFromCookie(); + + int? startDateMonth = null; + int? startDateYear = null; + var qualificationAwardedDateSplit = cookie.WhenWasQualificationAwarded.Split('/'); + if (qualificationAwardedDateSplit.Length == 2 + && int.TryParse(qualificationAwardedDateSplit[0], out var parsedStartMonth) + && int.TryParse(qualificationAwardedDateSplit[1], out var parsedStartYear)) + { + startDateMonth = parsedStartMonth; + startDateYear = parsedStartYear; + } + + return (startDateMonth, startDateYear); + } + + public int? GetLevelOfQualification() + { + var cookie = GetUserJourneyModelFromCookie(); + int? level = null; + if (int.TryParse(cookie.LevelOfQualification, out var parsedLevel)) + { + level = parsedLevel; + } + + return level; + } + + public string? GetAwardingOrganisation() + { + var cookie = GetUserJourneyModelFromCookie(); + string? awardingOrganisation = null; + if (!string.IsNullOrEmpty(cookie.WhatIsTheAwardingOrganisation)) + { + awardingOrganisation = cookie.WhatIsTheAwardingOrganisation; + } + + return awardingOrganisation; + } + private void SetJourneyCookie(UserJourneyModel model) { var serializedCookie = JsonSerializer.Serialize(model); diff --git a/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Get.cshtml b/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Get.cshtml index dcdb9f72..58bb2740 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Get.cshtml +++ b/src/Dfe.EarlyYearsQualification.Web/Views/QualificationDetails/Get.cshtml @@ -2,7 +2,6 @@ @{ ViewData["Title"] = "Qualifications"; - string[] qualifications = ["eyq-140", "eyq-150", "eyq-160", "eyq-170", "eyq-180", "eyq-220", "eyq-240"]; } @{ @@ -11,51 +10,59 @@
-

- -

+

+ +

    - @if (!string.IsNullOrEmpty(Model.Filters?.WhereWasQualificationAwarded)) - { -
  • @Model.Filters!.WhereWasQualificationAwarded
  • - } - - @if (!string.IsNullOrEmpty(Model.Filters?.WhenWasQualificationAwarded)) - { -
  • @Model.Filters!.WhenWasQualificationAwarded
  • - } - - @if (!string.IsNullOrEmpty(Model.Filters?.LevelOfQualification)) - { -
  • @Model.Filters!.LevelOfQualification
  • - } - - @if (!string.IsNullOrEmpty(Model.Filters?.WhatIsTheAwardingOrganisation)) - { -
  • @Model.Filters!.WhatIsTheAwardingOrganisation
  • - } +
  • @Model.Filters.Country
  • +
  • @Model.Filters.StartDate
  • +
  • @Model.Filters.Level
  • +
  • @Model.Filters.AwardingOrganisation
-

- Change my search -

+
@Html.Raw(Model.PostSearchCriteriaContent)
-

@Model.Header

- - - - - - - - @foreach (var qualification in qualifications) +

@Model.Header

+

+ + @Model.Qualifications.Count @(Model.Qualifications.Count == 1 ? Model.SingleQualificationFoundText : Model.MultipleQualificationsFoundText) + +

+
@Html.Raw(Model.PreSearchBoxContent)
+
+ + +
+ @foreach (var qualification in Model.Qualifications) { - - - +
+ + @qualification.QualificationName + +
+
+
+ @Model.LevelHeading +
+
+ @qualification.QualificationLevel +
+
+
+
+ @Model.AwardingOrganisationHeading +
+
+ @qualification.AwardingOrganisationTitle +
+
+
+
+
} - -
Qualification link
@Html.ActionLink(qualification, "Index", "ConfirmQualification", new { qualificationId = qualification })
+
@Html.Raw(Model.PostQualificationListContent)
\ No newline at end of file diff --git a/src/Dfe.EarlyYearsQualification.Web/Views/Shared/_Header.cshtml b/src/Dfe.EarlyYearsQualification.Web/Views/Shared/_Header.cshtml index 8def25c7..2c728725 100644 --- a/src/Dfe.EarlyYearsQualification.Web/Views/Shared/_Header.cshtml +++ b/src/Dfe.EarlyYearsQualification.Web/Views/Shared/_Header.cshtml @@ -17,6 +17,11 @@ +
diff --git a/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css b/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css index 8a64b27f..8b823353 100644 --- a/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css +++ b/src/Dfe.EarlyYearsQualification.Web/wwwroot/css/site.css @@ -24,4 +24,33 @@ body { /* GovUK style overrides */ .govuk-radios__input { z-index: 1; +} + +.chevron-card__wrapper { + padding: 19px 0 4px; + position: relative; +} + +.chevron-card__link:after { + border-right: 3px solid #1d70b8; + border-top: 3px solid #1d70b8; + content: ""; + display: block; + height: 14px; + position: absolute; + right: 5px; + top: 50%; + margin-top: 5px; + -webkit-transform: translateY(0) rotate(45deg) scale(1); + -ms-transform: translateY(0) rotate(45deg) scale(1); + transform: translateY(0) rotate(45deg) scale(1); + width: 14px; +} + +.chevron-card__link:hover::after { + border-color: #003078; +} + +.chevron-card__link:visited::after { + border-color: #4C2C92; } \ No newline at end of file diff --git a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/back-button-spec.cy.js b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/back-button-spec.cy.js index 43f1289f..ace8daab 100644 --- a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/back-button-spec.cy.js +++ b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/back-button-spec.cy.js @@ -47,11 +47,11 @@ describe('A spec used to test the main back button route through the journey', ( expect(loc.pathname).to.eq('/qualifications'); }) - cy.get('a[href="/confirm-qualification/eyq-240"]').click(); + cy.get('a[href="/confirm-qualification/EYQ-102"]').click(); // confirm qualification page cy.location().should((loc) => { - expect(loc.pathname).to.eq('/confirm-qualification/eyq-240'); + expect(loc.pathname).to.eq('/confirm-qualification/EYQ-102'); }) cy.get('#yes').click(); diff --git a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/journey-spec.cy.js b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/journey-spec.cy.js index 363a3e68..421b7da2 100644 --- a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/journey-spec.cy.js +++ b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/journey/journey-spec.cy.js @@ -65,11 +65,11 @@ describe('A spec used to test the various routes through the journey', () => { expect(loc.pathname).to.eq('/qualifications'); }) - cy.get('a[href="/confirm-qualification/eyq-240"]').click(); + cy.get('a[href="/confirm-qualification/EYQ-102"]').click(); // confirm qualification page cy.location().should((loc) => { - expect(loc.pathname).to.eq('/confirm-qualification/eyq-240'); + expect(loc.pathname).to.eq('/confirm-qualification/EYQ-102'); }) cy.get('#yes').click(); diff --git a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-list-spec.cy.js b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-list-spec.cy.js new file mode 100644 index 00000000..faa2f7fd --- /dev/null +++ b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/pages/qualification-list-spec.cy.js @@ -0,0 +1,29 @@ +describe("A spec used to test the qualification list page", () => { + + beforeEach(() => { + cy.setCookie('auth-secret', Cypress.env('auth_secret')); + // Value is '{"WhereWasQualificationAwarded":"england","WhenWasQualificationAwarded":"6/2022","LevelOfQualification":"3","WhatIsTheAwardingOrganisation":"NCFE"}' encoded + cy.setCookie('user_journey', '%7B%22WhereWasQualificationAwarded%22%3A%22england%22%2C%22WhenWasQualificationAwarded%22%3A%226%2F2022%22%2C%22LevelOfQualification%22%3A%223%22%2C%22WhatIsTheAwardingOrganisation%22%3A%22NCFE%22%7D'); + }) + + // Mock details found in Dfe.EarlyYearsQualification.Mock.Content.MockContentfulService. + it("Checks the details are showing on the page", () => { + cy.visit("/qualifications"); + + cy.get("#your-search-header").should("contain.text", "Your search"); + cy.get("#filter-country").should("contain.text", "England"); + cy.get("#filter-start-date").should("contain.text", "June 2022"); + cy.get("#filter-level").should("contain.text", "Level 3"); + cy.get("#filter-org").should("contain.text", "NCFE"); + + cy.get("#heading").should("contain.text", "Test Header"); + cy.get("#found-heading").should("contain.text", "2 qualifications found"); + + cy.get("#pre-search-content").should("contain.text", "Pre search box content"); + cy.get("#post-list-content").should("contain.text", "Post qualification list content"); + cy.get("#post-filter-content").should("contain.text", "Post search criteria content"); + + cy.get(".level").first().should("contain.text", "Level"); + cy.get(".awarding-org").first().should("contain.text", "Awarding organisation"); + }) +}) \ No newline at end of file diff --git a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/urls-to-check.js b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/urls-to-check.js index 2c583d59..94d957d1 100644 --- a/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/urls-to-check.js +++ b/tests/Dfe.EarlyYearsQualification.E2ETests/cypress/e2e/shared/urls-to-check.js @@ -8,7 +8,7 @@ export const pages = [ "/questions/when-was-the-qualification-started", "/questions/what-level-is-the-qualification", "/qualifications", - "/qualifications/qualification-details/eyq-240" + "/qualifications/qualification-details/EYQ-240" ]; export const pagesWithForms = [ @@ -24,5 +24,5 @@ export const pagesWithoutForms = [ "/advice/qualification-outside-the-united-kingdom", "/advice/level-2-qualifications-started-between-1-sept-2014-and-31-aug-2019", "/qualifications", - "/qualifications/qualification-details/eyq-240" + "/qualifications/qualification-details/EYQ-240" ] \ No newline at end of file diff --git a/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QualificationDetailsControllerTests.cs b/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QualificationDetailsControllerTests.cs index af43be91..05ff4c39 100644 --- a/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QualificationDetailsControllerTests.cs +++ b/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QualificationDetailsControllerTests.cs @@ -3,6 +3,7 @@ using Dfe.EarlyYearsQualification.Content.Services; using Dfe.EarlyYearsQualification.UnitTests.Extensions; using Dfe.EarlyYearsQualification.Web.Controllers; +using Dfe.EarlyYearsQualification.Web.Models; using Dfe.EarlyYearsQualification.Web.Models.Content; using Dfe.EarlyYearsQualification.Web.Services.UserJourneyCookieService; using FluentAssertions; @@ -21,12 +22,14 @@ public async Task Index_PassInNullQualificationId_ReturnsBadRequest() { var mockLogger = new Mock>(); var mockContentService = new Mock(); - var mockRenderer = new Mock(); + var mockContentFilterService = new Mock(); + var mockInsetTextRenderer = new Mock(); + var mockHtmlRenderer = new Mock(); var mockUserJourneyCookieService = new Mock(); var controller = - new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, - mockUserJourneyCookieService.Object) + new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockContentFilterService.Object, mockInsetTextRenderer.Object, + mockHtmlRenderer.Object, mockUserJourneyCookieService.Object) { ControllerContext = new ControllerContext { @@ -49,12 +52,14 @@ public async Task Index_ContentServiceReturnsNullDetailsPage_RedirectsToHomeErro { var mockLogger = new Mock>(); var mockContentService = new Mock(); - var mockRenderer = new Mock(); + var mockContentFilterService = new Mock(); + var mockInsetTextRenderer = new Mock(); + var mockHtmlRenderer = new Mock(); var mockUserJourneyCookieService = new Mock(); var controller = - new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, - mockUserJourneyCookieService.Object) + new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockContentFilterService.Object, mockInsetTextRenderer.Object, + mockHtmlRenderer.Object, mockUserJourneyCookieService.Object) { ControllerContext = new ControllerContext { @@ -82,12 +87,14 @@ public async Task Index_ContentServiceReturnsNoQualification_RedirectsToErrorPag { var mockLogger = new Mock>(); var mockContentService = new Mock(); - var mockRenderer = new Mock(); + var mockContentFilterService = new Mock(); + var mockInsetTextRenderer = new Mock(); + var mockHtmlRenderer = new Mock(); var mockUserJourneyCookieService = new Mock(); var controller = - new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, - mockUserJourneyCookieService.Object) + new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockContentFilterService.Object, mockInsetTextRenderer.Object, + mockHtmlRenderer.Object, mockUserJourneyCookieService.Object) { ControllerContext = new ControllerContext { @@ -115,12 +122,14 @@ public async Task Index_ContentServiceReturnsQualification_ReturnsQualificationD { var mockLogger = new Mock>(); var mockContentService = new Mock(); - var mockRenderer = new Mock(); + var mockContentFilterService = new Mock(); + var mockInsetTextRenderer = new Mock(); + var mockHtmlRenderer = new Mock(); var mockUserJourneyCookieService = new Mock(); var controller = - new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, - mockUserJourneyCookieService.Object) + new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockContentFilterService.Object, mockInsetTextRenderer.Object, + mockHtmlRenderer.Object, mockUserJourneyCookieService.Object) { ControllerContext = new ControllerContext { @@ -158,9 +167,27 @@ public async Task Get_ReturnsView() { var mockLogger = new Mock>(); var mockContentService = new Mock(); - var mockRenderer = new Mock(); + var mockContentFilterService = new Mock(); + var mockInsetTextRenderer = new Mock(); + var mockHtmlRenderer = new Mock(); var mockUserJourneyCookieService = new Mock(); + mockContentFilterService + .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())).ReturnsAsync(new List()); + + mockUserJourneyCookieService.Setup(x => x.GetUserJourneyModelFromCookie()).Returns(new UserJourneyModel()); + + var controller = + new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockContentFilterService.Object, mockInsetTextRenderer.Object, + mockHtmlRenderer.Object, mockUserJourneyCookieService.Object) + { + ControllerContext = new ControllerContext + { + HttpContext = new DefaultHttpContext() + } + }; + mockContentService.Setup(x => x.GetQualificationListPage()).ReturnsAsync(new QualificationListPage { BackButton = new NavigationLink @@ -171,17 +198,7 @@ public async Task Get_ReturnsView() }, Header = "TEST" }); - - var controller = - new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, - mockUserJourneyCookieService.Object) - { - ControllerContext = new ControllerContext - { - HttpContext = new DefaultHttpContext() - } - }; - + var result = await controller.Get(); result.Should().NotBeNull(); @@ -193,14 +210,14 @@ public async Task Get_NoContent_LogsAndRedirectsToError() { var mockLogger = new Mock>(); var mockContentService = new Mock(); - var mockRenderer = new Mock(); + var mockContentFilterService = new Mock(); + var mockInsetTextRenderer = new Mock(); + var mockHtmlRenderer = new Mock(); var mockUserJourneyCookieService = new Mock(); - mockContentService.Setup(x => x.GetQualificationListPage()).ReturnsAsync(default(QualificationListPage)); - var controller = - new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, - mockUserJourneyCookieService.Object) + new QualificationDetailsController(mockLogger.Object, mockContentService.Object, mockContentFilterService.Object, mockInsetTextRenderer.Object, + mockHtmlRenderer.Object, mockUserJourneyCookieService.Object) { ControllerContext = new ControllerContext { @@ -208,6 +225,8 @@ public async Task Get_NoContent_LogsAndRedirectsToError() } }; + mockContentService.Setup(x => x.GetQualificationListPage()).ReturnsAsync(default(QualificationListPage)); + var result = await controller.Get(); result.Should().BeOfType(); diff --git a/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QuestionsControllerTests.cs b/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QuestionsControllerTests.cs index 830f342d..c8f2f82b 100644 --- a/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QuestionsControllerTests.cs +++ b/tests/Dfe.EarlyYearsQualification.UnitTests/Controllers/QuestionsControllerTests.cs @@ -515,10 +515,10 @@ public async Task Post_WhatLevelIsTheQualification_ReturnsRedirectResponse() resultType.Should().NotBeNull(); resultType!.ActionName.Should().Be("WhatIsTheAwardingOrganisation"); - + mockUserJourneyCookieService.Verify(x => x.SetLevelOfQualification("3"), Times.Once); } - + [TestMethod] public async Task Post_WhatLevelIsTheQualification_Level2WithInDate_ReturnsRedirectResponse() { @@ -528,9 +528,10 @@ public async Task Post_WhatLevelIsTheQualification_Level2WithInDate_ReturnsRedir var mockUserJourneyCookieService = new Mock(); var mockContentFilterService = new Mock(); - mockUserJourneyCookieService.Setup(x => x.GetUserJourneyModelFromCookie()) - .Returns(new UserJourneyModel() { WhenWasQualificationAwarded = "06/2015" }); - var controller = new QuestionsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, mockUserJourneyCookieService.Object, mockContentFilterService.Object); + mockUserJourneyCookieService.Setup(x => x.GetWhenWasQualificationAwarded()) + .Returns((6, 2015)); + var controller = new QuestionsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, + mockUserJourneyCookieService.Object, mockContentFilterService.Object); var result = await controller.WhatLevelIsTheQualification(new RadioQuestionModel { @@ -543,7 +544,7 @@ public async Task Post_WhatLevelIsTheQualification_Level2WithInDate_ReturnsRedir resultType.Should().NotBeNull(); resultType!.ActionName.Should().Be("QualificationsStartedBetweenSept2014AndAug2019"); - resultType!.ControllerName.Should().Be("Advice"); + resultType.ControllerName.Should().Be("Advice"); } [TestMethod] @@ -600,7 +601,11 @@ public async Task WhatIsTheAwardingOrganisation_ContentServiceReturnsQuestionPag mockUserJourneyCookieService.Setup(x => x.GetUserJourneyModelFromCookie()).Returns(new UserJourneyModel()); mockContentFilterService - .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.GetFilteredQualifications( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) .ReturnsAsync([]); var controller = new QuestionsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, @@ -666,7 +671,8 @@ public async Task mockUserJourneyCookieService.Setup(x => x.GetUserJourneyModelFromCookie()).Returns(new UserJourneyModel()); mockContentFilterService - .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())) .ReturnsAsync(listOfQualifications); var controller = new QuestionsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, @@ -731,7 +737,8 @@ public async Task mockUserJourneyCookieService.Setup(x => x.GetUserJourneyModelFromCookie()).Returns(new UserJourneyModel()); mockContentFilterService - .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())) .ReturnsAsync(listOfQualifications); var controller = new QuestionsController(mockLogger.Object, mockContentService.Object, mockRenderer.Object, @@ -781,7 +788,8 @@ public async Task Post_WhatIsTheAwardingOrganisation_InvalidModel_ReturnsQuestio mockUserJourneyCookieService.Setup(x => x.GetUserJourneyModelFromCookie()).Returns(new UserJourneyModel()); mockContentFilterService - .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny())) + .Setup(x => x.GetFilteredQualifications(It.IsAny(), It.IsAny(), It.IsAny(), + It.IsAny())) .ReturnsAsync([]); controller.ModelState.AddModelError("option", "test error"); diff --git a/tests/Dfe.EarlyYearsQualification.UnitTests/Mocks/MockContentfulFilterServiceTests.cs b/tests/Dfe.EarlyYearsQualification.UnitTests/Mocks/MockContentfulFilterServiceTests.cs index a042f0c9..cd161eec 100644 --- a/tests/Dfe.EarlyYearsQualification.UnitTests/Mocks/MockContentfulFilterServiceTests.cs +++ b/tests/Dfe.EarlyYearsQualification.UnitTests/Mocks/MockContentfulFilterServiceTests.cs @@ -22,7 +22,7 @@ public async Task GetFilteredQualifications_PassInLevel_ReturnsQualifications( int level, string[] expectedQualifications) { var mockContentFilterService = new MockContentfulFilterService(); - var results = await mockContentFilterService.GetFilteredQualifications(level, null, null); + var results = await mockContentFilterService.GetFilteredQualifications(level, null, null, null); results.Count.Should().Be(2); results[0].QualificationId.Should().Be(expectedQualifications[0]); diff --git a/tests/Dfe.EarlyYearsQualification.UnitTests/Services/ContentfulContentFilterServiceTests.cs b/tests/Dfe.EarlyYearsQualification.UnitTests/Services/ContentfulContentFilterServiceTests.cs index d27c45c9..b302cba1 100644 --- a/tests/Dfe.EarlyYearsQualification.UnitTests/Services/ContentfulContentFilterServiceTests.cs +++ b/tests/Dfe.EarlyYearsQualification.UnitTests/Services/ContentfulContentFilterServiceTests.cs @@ -53,7 +53,7 @@ public async Task GetFilteredQualifications_PassInNullParameters_ReturnsAllQuali QueryBuilder = mockQueryBuilder }; - var filteredQualifications = await filterService.GetFilteredQualifications(null, null, null); + var filteredQualifications = await filterService.GetFilteredQualifications(null, null, null, null); filteredQualifications.Should().NotBeNull(); filteredQualifications.Count.Should().Be(2); @@ -94,13 +94,53 @@ public async Task GetFilteredQualifications_PassInLevel_ClientContainsLevelInQue QueryBuilder = mockQueryBuilder }; - await filterService.GetFilteredQualifications(4, null, null); + await filterService.GetFilteredQualifications(4, null, null, null); var queryString = mockQueryBuilder.GetQueryString(); queryString.Count.Should().Be(2); queryString.Should().Contain("content_type", "Qualification"); queryString.Should().Contain("fields.qualificationLevel", "4"); } + + [TestMethod] + public async Task GetFilteredQualifications_PassInAwardingOrganisation_ClientContainsAwardingOrganisationInQuery() + { + var results = new ContentfulCollection + { + Items = new[] + { + new Qualification( + "EYQ-123", + "test", + "NCFE", + 4, + "Apr-15", + "Aug-19", + "abc/123/987", + "requirements") + } + }; + + var mockContentfulClient = new Mock(); + mockContentfulClient.Setup(x => x.GetEntries( + It.IsAny>(), + It.IsAny())) + .ReturnsAsync(results); + + var mockQueryBuilder = new MockQueryBuilder(); + var mockLogger = new Mock>(); + var filterService = new ContentfulContentFilterService(mockContentfulClient.Object, mockLogger.Object) + { + QueryBuilder = mockQueryBuilder + }; + + await filterService.GetFilteredQualifications(null, null, null, "NCFE"); + + var queryString = mockQueryBuilder.GetQueryString(); + queryString.Count.Should().Be(2); + queryString.Should().Contain("content_type", "Qualification"); + queryString.Should().Contain("fields.awardingOrganisationTitle", "NCFE"); + } [TestMethod] public async Task GetFilteredQualifications_PassInLevelMonthAndNullParameters_ReturnsAllQualifications() @@ -151,7 +191,7 @@ public async Task GetFilteredQualifications_PassInLevelMonthAndNullParameters_Re QueryBuilder = mockQueryBuilder }; - var filteredQualifications = await filterService.GetFilteredQualifications(4, 9, null); + var filteredQualifications = await filterService.GetFilteredQualifications(4, 9, null, null); filteredQualifications.Should().NotBeNull(); filteredQualifications.Count.Should().Be(3); @@ -209,7 +249,7 @@ public async Task GetFilteredQualifications_PassInLevelNullAndYearParameters_Ret QueryBuilder = mockQueryBuilder }; - var filteredQualifications = await filterService.GetFilteredQualifications(4, null, 2014); + var filteredQualifications = await filterService.GetFilteredQualifications(4, null, 2014, null); filteredQualifications.Should().NotBeNull(); filteredQualifications.Count.Should().Be(3); @@ -276,7 +316,7 @@ public async Task GetFilteredQualifications_FilterOnDates_ReturnsFilteredQualifi QueryBuilder = mockQueryBuilder }; - var filteredQualifications = await filterService.GetFilteredQualifications(4, 5, 2016); + var filteredQualifications = await filterService.GetFilteredQualifications(4, 5, 2016, null); filteredQualifications.Should().NotBeNull(); filteredQualifications.Count.Should().Be(3); @@ -343,7 +383,7 @@ public async Task GetFilteredQualifications_FilterOnDates_MonthIsCaseInsensitive QueryBuilder = mockQueryBuilder }; - var filteredQualifications = await filterService.GetFilteredQualifications(4, 5, 2016); + var filteredQualifications = await filterService.GetFilteredQualifications(4, 5, 2016, null); filteredQualifications.Should().NotBeNull(); filteredQualifications.Count.Should().Be(3); @@ -364,7 +404,7 @@ public async Task GetFilteredQualifications_ContentfulClientThrowsException_Retu var mockLogger = new Mock>(); var filterService = new ContentfulContentFilterService(mockContentfulClient.Object, mockLogger.Object); - var filteredQualifications = await filterService.GetFilteredQualifications(4, 5, 2016); + var filteredQualifications = await filterService.GetFilteredQualifications(4, 5, 2016, null); filteredQualifications.Should().NotBeNull(); filteredQualifications.Should().BeEmpty(); @@ -402,7 +442,7 @@ public async Task GetFilteredQualifications_DataContainsInvalidDateFormat_LogsEr QueryBuilder = mockQueryBuilder }; - await filterService.GetFilteredQualifications(4, 5, 2016); + await filterService.GetFilteredQualifications(4, 5, 2016, null); mockLogger.VerifyError("Qualification date Sep15 has unexpected format"); } @@ -439,7 +479,7 @@ public async Task GetFilteredQualifications_DataContainsInvalidMonth_LogsError() QueryBuilder = mockQueryBuilder }; - await filterService.GetFilteredQualifications(4, 5, 2016); + await filterService.GetFilteredQualifications(4, 5, 2016, null); mockLogger.VerifyError("Qualification date Sept-15 contains unexpected month value"); } @@ -476,7 +516,7 @@ public async Task GetFilteredQualifications_DataContainsInvalidYear_LogsError() QueryBuilder = mockQueryBuilder }; - await filterService.GetFilteredQualifications(4, 5, 2016); + await filterService.GetFilteredQualifications(4, 5, 2016, null); mockLogger.VerifyError("Qualification date Aug-1a contains unexpected year value"); } diff --git a/tests/Dfe.EarlyYearsQualification.UnitTests/Services/UserJourneyCookieServiceTests.cs b/tests/Dfe.EarlyYearsQualification.UnitTests/Services/UserJourneyCookieServiceTests.cs index 3cec549c..541b1c6e 100644 --- a/tests/Dfe.EarlyYearsQualification.UnitTests/Services/UserJourneyCookieServiceTests.cs +++ b/tests/Dfe.EarlyYearsQualification.UnitTests/Services/UserJourneyCookieServiceTests.cs @@ -178,6 +178,162 @@ public void ResetUserJourneyCookie_FullModelAsCookieExists_AddsBaseModelAsCookie var serialisedModelToCheck = JsonSerializer.Serialize(new UserJourneyModel()); CheckSerializedModelWasSet(mockHttpContextAccessor, serialisedModelToCheck); } + + [TestMethod] + public void GetWhereWasQualificationAwarded_CookieValueIsEmpty_ReturnsNull() + { + var existingModel = new UserJourneyModel + { + WhereWasQualificationAwarded = string.Empty + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + var model = service.GetWhereWasQualificationAwarded(); + + model.Should().BeNull(); + } + + [TestMethod] + public void GetWhereWasQualificationAwarded_CookieHasValue_ReturnsValueWithUpperCaseFirstLetter() + { + var existingModel = new UserJourneyModel + { + WhereWasQualificationAwarded = "england" + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + var model = service.GetWhereWasQualificationAwarded(); + + model.Should().Be("England"); + } + + [TestMethod] + public void GetAwardingOrganisation_CookieValueIsEmpty_ReturnsNull() + { + var existingModel = new UserJourneyModel + { + WhatIsTheAwardingOrganisation = string.Empty + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + var model = service.GetAwardingOrganisation(); + + model.Should().BeNull(); + } + + [TestMethod] + public void GetAwardingOrganisation_CookieHasValue_ReturnsValue() + { + var existingModel = new UserJourneyModel + { + WhatIsTheAwardingOrganisation = "NCFE" + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + var model = service.GetAwardingOrganisation(); + + model.Should().Be("NCFE"); + } + + [TestMethod] + public void GetLevelOfQualification_CookieValueIsEmpty_ReturnsNull() + { + var existingModel = new UserJourneyModel + { + LevelOfQualification = string.Empty + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + var model = service.GetLevelOfQualification(); + + model.Should().BeNull(); + } + + [TestMethod] + public void GetLevelOfQualification_CookieHasValue_ReturnsValue() + { + var existingModel = new UserJourneyModel + { + LevelOfQualification = "4" + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + var model = service.GetLevelOfQualification(); + + model.Should().Be(4); + } + + [TestMethod] + public void GetWhenWasQualificationAwarded_CookieValueIsEmpty_ReturnsNull() + { + var existingModel = new UserJourneyModel + { + WhenWasQualificationAwarded = string.Empty + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + (int? startMonth, int? startYear) = service.GetWhenWasQualificationAwarded(); + + startMonth.Should().BeNull(); + startYear.Should().BeNull(); + } + + [TestMethod] + public void GetWhenWasQualificationAwarded_CookieHasInvalidValue_ReturnsNull() + { + var existingModel = new UserJourneyModel + { + WhenWasQualificationAwarded = "4" + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + (int? startMonth, int? startYear) = service.GetWhenWasQualificationAwarded(); + + startMonth.Should().BeNull(); + startYear.Should().BeNull(); + } + + [TestMethod] + public void GetWhenWasQualificationAwarded_CookieHasValidValue_ReturnsValue() + { + var existingModel = new UserJourneyModel + { + WhenWasQualificationAwarded = "4/2015" + }; + var mockHttpContextAccessor = SetHttpContextWithExistingCookie(existingModel); + var mockLogger = new Mock>(); + + var service = new UserJourneyCookieService(mockHttpContextAccessor.Object, mockLogger.Object); + + (int? startMonth, int? startYear) = service.GetWhenWasQualificationAwarded(); + + startMonth.Should().Be(4); + startYear.Should().Be(2015); + } private static Mock SetHttpContextWithExistingCookie(object? model) {