public async Task WhenPostingVacancyReadyForReReviewMessage_ThenItShouldPostAMessageWithTheNewIconAndSuitableMessage() { var vacancyReference = 1000000001; var vacancyReview = new VacancyReview { VacancyReference = vacancyReference, SubmissionCount = 2 }; var mockSlackClient = new Mock <ISlackClient>(); mockSlackClient .Setup(c => c.Post( It.Is <SlackMessage>(s => s.Text.Contains("ready for review") && s.Text.Contains(" (2nd submission)") && s.Text.Contains(vacancyReference.ToString()) ), It.Is <Emojis>(e => e.Equals(Emojis.New)))) .Returns(Task.CompletedTask) .Verifiable(); var client = new SlackNotifyVacancyReviewUpdates(mockSlackClient.Object); await client.VacancyReviewCreated(vacancyReview); mockSlackClient.Verify(); }
public async Task WhenPostingVacancyApprovedFromFirstReviewMessage_ThenItShouldPostAMessageWithTheNewIconAndSuitableMessage() { var vacancyReference = 1000000001; var vacancyReview = new VacancyReview { VacancyReference = vacancyReference, SubmissionCount = 1, VacancySnapshot = new Vacancy { OwnerType = OwnerType.Employer } }; var mockSlackClient = new Mock <ISlackClient>(); mockSlackClient .Setup(c => c.PostAsync( It.Is <SlackMessage>(s => s.Text.Contains("has been approved") && !s.Text.Contains(" (1st review)") && s.Text.Contains(" (Employer)") && s.Text.Contains(vacancyReference.ToString())), It.Is <SlackVacancyNotificationType>(e => e.Equals(SlackVacancyNotificationType.Approved)))) .Returns(Task.CompletedTask) .Verifiable(); var client = new SlackNotifyVacancyReviewUpdates(mockSlackClient.Object, Options.Create(new SlackConfiguration())); await client.VacancyReviewApproved(vacancyReview); mockSlackClient.Verify(); }
private List <AutomatedQaResultViewModel> GetAutomatedQaResultViewModel(VacancyReview review) { var vm = new List <AutomatedQaResultViewModel>(); if (review.AutomatedQaOutcomeIndicators == null || review.AutomatedQaOutcome == null) { return(vm); } var referredOutcomes = review.AutomatedQaOutcomeIndicators .Where(i => i.IsReferred) .Select(i => i.RuleOutcomeId) .ToList(); foreach (var ruleOutcome in review.AutomatedQaOutcome.RuleOutcomes) { vm.AddRange( ruleOutcome.Details .Where(d => referredOutcomes.Contains(d.Id)) .Select(d => new AutomatedQaResultViewModel { OutcomeId = d.Id.ToString(), FieldId = d.Target, Checked = true, Text = _ruleTemplateRunner.ToText(ruleOutcome.RuleId, d.Data, FieldDisplayNameResolver.Resolve(d.Target)) })); } //sort by the order of the fields on the review page return(vm.OrderBy(v => ReviewFields.Keys.ToList().FindIndex(k => k == v.FieldId)).ToList()); }
public Task CreateAsync(VacancyReview vacancy) { var collection = GetCollection <VacancyReview>(); return(RetryPolicy.ExecuteAsync(_ => collection.InsertOneAsync(vacancy), new Context(nameof(CreateAsync)))); }
public Task UpdateAsync(VacancyReview review) { var filterBuilder = Builders <VacancyReview> .Filter; var filter = filterBuilder.Eq(v => v.Id, review.Id) & filterBuilder.Eq(v => v.VacancyReference, review.VacancyReference); var collection = GetCollection <VacancyReview>(); return(RetryPolicy.ExecuteAsync(context => collection.ReplaceOneAsync(filter, review), new Context(nameof(UpdateAsync)))); }
private Task ClosePendingReview(VacancyReview review) { _logger.LogInformation($"Closing pending review {review.Id} as the provider is blocked"); review.ManualOutcome = ManualQaOutcome.Blocked; review.Status = ReviewStatus.Closed; review.ClosedDate = _timeProvider.Now; return _vacancyReviewRepository.UpdateAsync(review); }
private async Task EnsureUserIsAssignedAsync(VacancyReview review, string userId) { var userReviews = await _vacancyClient.GetAssignedVacancyReviewsForUserAsync(userId); if (userReviews.Any(r => r.Id == review.Id) == false) { throw new UnassignedVacancyReviewException($"You have been unassigned from {review.VacancyReference}"); } }
private void Validate(VacancyReview review) { var validationResult = _vacancyReviewValidator.Validate(review); if (!validationResult.IsValid) { throw new ValidationException(validationResult.Errors); } }
private static void ValidateReviewStateForViewing(VacancyReview review) { if (review.Status != ReviewStatus.PendingReview && review.Status != ReviewStatus.UnderReview) { throw new InvalidStateException($"Review is not in a correct state for viewing. State: {review.Status}"); } if (review.VacancySnapshot == null) { throw new NotFoundException($"Vacancy snapshot is null for review with id: {review.Id}"); } }
public async Task WhenPostingVacancyReferredMessage_ThenItShouldPostAMessageWithTheNewIconAndSuitableMessage() { var vacancyReference = 1000000001; var manualQaFieldIndicators = new List <ManualQaFieldIndicator> { new ManualQaFieldIndicator { FieldIdentifier = "field1", IsChangeRequested = true }, new ManualQaFieldIndicator { FieldIdentifier = "field2", IsChangeRequested = false } }; var automatedQaOutcomeIndicators = new List <RuleOutcomeIndicator> { new RuleOutcomeIndicator { RuleOutcomeId = Guid.NewGuid(), IsReferred = true }, new RuleOutcomeIndicator { RuleOutcomeId = Guid.NewGuid(), IsReferred = false } }; var vacancyReview = new VacancyReview { VacancyReference = vacancyReference, ManualQaFieldIndicators = manualQaFieldIndicators, AutomatedQaOutcomeIndicators = automatedQaOutcomeIndicators, VacancySnapshot = new Vacancy { OwnerType = OwnerType.Employer } }; var mockSlackClient = new Mock <ISlackClient>(); mockSlackClient .Setup(c => c.PostAsync( It.Is <SlackMessage>(s => s.Text.Contains("has been referred") && s.Text.Contains(" (2 issues)") && s.Text.Contains(" (Employer)") && s.Text.Contains(vacancyReference.ToString())), It.Is <SlackVacancyNotificationType>(e => e.Equals(SlackVacancyNotificationType.Referred)))) .Returns(Task.CompletedTask) .Verifiable(); var client = new SlackNotifyVacancyReviewUpdates(mockSlackClient.Object, Options.Create(new SlackConfiguration())); await client.VacancyReviewReferred(vacancyReview); mockSlackClient.Verify(); }
public void ApplicationReviewShouldBeValid(string manualQaComment) { var m = new VacancyReview { ManualQaComment = manualQaComment }; var validator = new VacancyReviewValidator(); var result = validator.Validate(m); result.IsValid.Should().BeTrue(); }
public Task VacancyReviewCreated(VacancyReview vacancyReview) { var messageBody = $"Vacancy VAC{vacancyReview.VacancyReference} is ready for review"; if (vacancyReview.SubmissionCount > 1) { messageBody += $" ({GetNumericSuffix(vacancyReview.SubmissionCount)} submission)"; } var message = new SlackMessage { Text = messageBody }; return(_slackClient.Post(message, Emojis.New)); }
private async Task <ClosureReason?> TryGetReasonToCloseVacancy(VacancyReview review, Vacancy vacancy) { if (HasVacancyBeenTransferredSinceReviewWasCreated(review, vacancy)) { return(vacancy.TransferInfo.Reason == TransferReason.EmployerRevokedPermission ? ClosureReason.TransferredByEmployer : ClosureReason.TransferredByQa); } if (await HasProviderBeenBlockedSinceReviewWasCreatedAsync(vacancy)) { return(ClosureReason.BlockedByQa); } return(null); }
public Task VacancyReviewCreated(VacancyReview vacancyReview) { var messageBody = $"Vacancy VAC{vacancyReview.VacancyReference} is ready for review ({vacancyReview.VacancySnapshot.OwnerType.ToString()})"; if (vacancyReview.SubmissionCount > 1) { messageBody += $" ({GetNumericSuffix(vacancyReview.SubmissionCount)} submission)"; } var message = new SlackMessage { Text = messageBody }; return(_slackClient.PostAsync(message, SlackVacancyNotificationType.New)); }
public void ShouldValidateManaulQaComment(string manualQaComment, string expectedErrorMessage) { var m = new VacancyReview { ManualQaComment = manualQaComment }; var validator = new VacancyReviewValidator(); var result = validator.Validate(m); result.IsValid.Should().BeFalse(); result.Errors.Count.Should().Be(1); result.Errors[0].ErrorMessage.Should().Be(expectedErrorMessage); }
public Task VacancyReviewApproved(VacancyReview vacancyReview) { var messageBody = string.Format("Vacancy <{0}{1}|VAC{1}> has been approved ({2})", _findAnApprenticeshipDetailPrefixUrl, vacancyReview.VacancyReference, vacancyReview.VacancySnapshot.OwnerType.ToString()); if (vacancyReview.SubmissionCount > 1) { messageBody += $" ({GetNumericSuffix(vacancyReview.SubmissionCount)} review)"; } var message = new SlackMessage { Text = messageBody }; return(_slackClient.PostAsync(message, SlackVacancyNotificationType.Approved)); }
public Task VacancyReviewApproved(VacancyReview vacancyReview) { var messageBody = $"Vacancy VAC{vacancyReview.VacancyReference} has been approved"; if (vacancyReview.SubmissionCount > 1) { messageBody += $" ({GetNumericSuffix(vacancyReview.SubmissionCount)} review)"; } var message = new SlackMessage { Text = messageBody }; return(_slackClient.Post(message, Emojis.Approved)); }
private VacancyReview BuildNewReview(Vacancy vacancy, int previousReviewCount, DateTime slaDeadline, List <string> updatedFieldIdentifiers) { var review = new VacancyReview { VacancyReference = vacancy.VacancyReference.Value, Title = vacancy.Title, Status = ReviewStatus.New, CreatedDate = _time.Now, SubmittedByUser = vacancy.SubmittedByUser, SubmissionCount = previousReviewCount + 1, SlaDeadline = slaDeadline, VacancySnapshot = vacancy, UpdatedFieldIdentifiers = updatedFieldIdentifiers }; return(review); }
private ReviewSummaryViewModel ConvertToReviewSummaryViewModel( ReviewFieldMappingLookupsForPage reviewFieldIndicatorsForPage, VacancyReview review) { if (review != null) { var fieldIndicators = _fieldMappingsLookup.MapFromFieldIndicators(reviewFieldIndicatorsForPage, review).ToList(); return(new ReviewSummaryViewModel { HasBeenReviewed = true, ReviewerComments = review.ManualQaComment, FieldIndicators = fieldIndicators }); } return(new ReviewSummaryViewModel()); }
private VacancyReviewSearchResultViewModel MapToViewModel(VacancyReview vacancyReview, VacancyUser vacancyUser) { var isAvailableForReview = _vacancyClient.VacancyReviewCanBeAssigned(vacancyReview.Status, vacancyReview.ReviewedDate); return(new VacancyReviewSearchResultViewModel { IsAssignedToLoggedInUser = vacancyUser.UserId == vacancyReview.ReviewedByUser?.UserId, AssignedTo = vacancyReview.ReviewedByUser?.Name, AssignedTimeElapsed = vacancyReview.ReviewedDate.GetShortTimeElapsed(_timeProvider.Now), ClosingDate = vacancyReview.VacancySnapshot.ClosingDate.GetValueOrDefault(), EmployerName = vacancyReview.VacancySnapshot.EmployerName, VacancyReference = vacancyReview.VacancyReference.ToString(), VacancyTitle = vacancyReview.Title, ReviewId = vacancyReview.Id, IsClosed = vacancyReview.Status == ReviewStatus.Closed, SubmittedDate = vacancyReview.VacancySnapshot.SubmittedDate.GetValueOrDefault(), IsAvailableForReview = isAvailableForReview }); }
public Task VacancyReviewReferred(VacancyReview vacancyReview) { var messageBody = $"Vacancy VAC{vacancyReview.VacancyReference} has been referred ({vacancyReview.VacancySnapshot.OwnerType.ToString()})"; var issueCount = vacancyReview.ManualQaFieldIndicators.Count(i => i.IsChangeRequested) + vacancyReview.AutomatedQaOutcomeIndicators.Count(i => i.IsReferred); if (issueCount == 1) { messageBody += $" ({issueCount} issue)"; } if (issueCount > 1) { messageBody += $" ({issueCount} issues)"; } var message = new SlackMessage { Text = messageBody }; return(_slackClient.PostAsync(message, SlackVacancyNotificationType.Referred)); }
public Task VacancyReviewReferred(VacancyReview vacancyReview) { var messageBody = $"Vacancy VAC{vacancyReview.VacancyReference} has been referred"; var issueCount = vacancyReview.ManualQaFieldIndicators.Count(i => i.IsChangeRequested) + vacancyReview.AutomatedQaOutcomeIndicators.Count(i => i.IsReferred); if (issueCount == 1) { messageBody += $" ({issueCount} issue)"; } if (issueCount > 1) { messageBody += $" ({issueCount} issues)"; } var message = new SlackMessage { Text = messageBody }; return(_slackClient.Post(message, Emojis.Referred)); }
public async Task WhenPostingVacancyApprovedFromFirstReviewMessage_ThenItShouldPostAMessageWithTheNewIconAndSuitableMessage() { var vacancyReference = 1000000001; var vacancyReview = new VacancyReview { VacancyReference = vacancyReference, SubmissionCount = 1 }; var mockSlackClient = new Mock <ISlackClient>(); mockSlackClient .Setup(c => c.Post( It.Is <SlackMessage>(s => s.Text.Contains("has been approved") && !s.Text.Contains(" (1st review)") && s.Text.Contains(vacancyReference.ToString())), It.Is <Emojis>(e => e.Equals(Emojis.Approved)))) .Returns(Task.CompletedTask) .Verifiable(); var client = new SlackNotifyVacancyReviewUpdates(mockSlackClient.Object); await client.VacancyReviewApproved(vacancyReview); mockSlackClient.Verify(); }
public async Task <ReviewViewModel> Map(VacancyReview review) { var vacancy = review.VacancySnapshot; var currentVacancy = _vacancyClient.GetVacancyAsync(review.VacancyReference); var programmeTask = _vacancyClient.GetApprenticeshipProgrammeAsync(vacancy.ProgrammeId); var reviewHistoryTask = _vacancyClient.GetVacancyReviewHistoryAsync(review.VacancyReference); var approvedCountTask = _vacancyClient.GetApprovedCountAsync(vacancy.SubmittedByUser.UserId); var approvedFirstTimeCountTask = _vacancyClient.GetApprovedFirstTimeCountAsync(vacancy.SubmittedByUser.UserId); var reviewSummaryTask = _reviewSummaryService.GetReviewSummaryViewModelAsync(review.Id, ReviewFieldMappingLookups.GetPreviewReviewFieldIndicators()); var anonymousApprovedCountTask = vacancy.IsAnonymous ? _vacancyClient.GetAnonymousApprovedCountAsync(vacancy.LegalEntityId) : Task.FromResult(0); await Task.WhenAll( currentVacancy, programmeTask, approvedCountTask, approvedFirstTimeCountTask, reviewHistoryTask, reviewSummaryTask, anonymousApprovedCountTask); var programme = programmeTask.Result; var currentVacancyResult = currentVacancy.Result; var historiesVm = GetReviewHistoriesViewModel(reviewHistoryTask.Result); var vm = new ReviewViewModel(); vm.Review = reviewSummaryTask.Result; try { vm.SubmittedByName = vacancy.SubmittedByUser.Name; vm.SubmittedByEmail = vacancy.SubmittedByUser.Email; vm.ApplicationInstructions = vacancy.ApplicationInstructions; vm.ApplicationMethod = vacancy.ApplicationMethod.Value; vm.ApplicationUrl = vacancy.ApplicationUrl; vm.ClosingDate = vacancy.ClosingDate?.AsGdsDate(); vm.EducationLevelName = EducationLevelNumberHelper.GetEducationLevelNameOrDefault(programme.EducationLevelNumber, programme.Level); vm.EmployerContactName = vacancy.EmployerContact?.Name; vm.EmployerContactEmail = vacancy.EmployerContact?.Email; vm.EmployerContactTelephone = vacancy.EmployerContact?.Phone; vm.EmployerDescription = vacancy.EmployerDescription; vm.EmployerName = vacancy.EmployerName; vm.EmployerNameOption = vacancy.EmployerNameOption.Value; vm.AnonymousReason = vacancy.AnonymousReason; vm.AnonymousApprovedCount = anonymousApprovedCountTask.Result; vm.EmployerWebsiteUrl = vacancy.EmployerWebsiteUrl; vm.MapUrl = MapImageHelper.GetEmployerLocationMapUrl(vacancy, _mapService, MapImageWidth, MapImageHeight); vm.EmployerAddressElements = vacancy.EmployerAddressForDisplay(); vm.LegalEntityName = vacancy.LegalEntityName; vm.IsDisabilityConfident = vacancy.IsDisabilityConfident; vm.NumberOfPositionsCaption = $"{"position".ToQuantity(vacancy.NumberOfPositions.Value)} available"; vm.OutcomeDescription = vacancy.OutcomeDescription; vm.PossibleStartDate = vacancy.StartDate?.AsGdsDate(); vm.ProviderContactName = vacancy.ProviderContact?.Name; vm.ProviderContactEmail = vacancy.ProviderContact?.Email; vm.ProviderContactTelephone = vacancy.ProviderContact?.Phone; vm.ProviderName = vacancy.TrainingProvider.Name; vm.Qualifications = vacancy.Qualifications.SortQualifications(_qualifications.Value).AsText(); vm.ShortDescription = vacancy.ShortDescription; vm.Skills = vacancy.Skills ?? Enumerable.Empty <string>(); vm.OwnerType = vacancy.OwnerType; vm.ThingsToConsider = vacancy.ThingsToConsider; vm.Title = vacancy.Title; vm.TrainingDescription = vacancy.TrainingDescription; vm.VacancyDescription = vacancy.Description; vm.VacancyReferenceNumber = $"VAC{vacancy.VacancyReference}"; vm.TrainingTitle = programme.Title; vm.TrainingType = programme.ApprenticeshipType.GetDisplayName(); vm.TrainingLevel = programme.Level.GetDisplayName(); vm.Level = programme.Level; vm.ExpectedDuration = (vacancy.Wage.DurationUnit.HasValue && vacancy.Wage.Duration.HasValue) ? vacancy.Wage.DurationUnit.Value.GetDisplayName().ToQuantity(vacancy.Wage.Duration.Value) : null; vm.HoursPerWeek = $"{vacancy.Wage.WeeklyHours:0.##}"; vm.WageInfo = vacancy.Wage.WageAdditionalInformation; vm.WageText = vacancy.StartDate.HasValue ? vacancy.Wage.ToText(vacancy.StartDate) : null; vm.WorkingWeekDescription = vacancy.Wage.WorkingWeekDescription; vm.SubmittedDate = vacancy.SubmittedDate.Value; vm.VacancyReviewsApprovedCount = approvedCountTask.Result; vm.VacancyReviewsApprovedFirstTimeCount = approvedFirstTimeCountTask.Result; vm.FieldIdentifiers = await GetFieldIdentifiersViewModel(review); vm.ReviewerComment = review.ManualQaComment; vm.ReviewHistories = historiesVm; vm.IsResubmission = review.SubmissionCount > 1; vm.ReviewerName = review.ReviewedByUser.Name; vm.ReviewedDate = review.ReviewedDate.GetValueOrDefault(); vm.ManualOutcome = review.ManualOutcome; if (review.Status == ReviewStatus.Closed) { vm.PageTitle = GetPageTitle(historiesVm, review.Id, review.ManualOutcome, currentVacancyResult); } vm.AutomatedQaResults = GetAutomatedQaResultViewModel(review); vm.IsVacancyDeleted = currentVacancyResult.IsDeleted; } catch (NullReferenceException ex) { _logger.LogError(ex, "Unable to map vacancy to view model. Unexpected null fields."); throw; } return(vm); }
private async Task <IEnumerable <FieldIdentifierViewModel> > GetFieldIdentifiersViewModel(VacancyReview currentReview) { var vm = GetFieldIndicators(); if (currentReview.SubmissionCount <= 1) { return(vm); } var previousReview = await _vacancyClient.GetCurrentReferredVacancyReviewAsync(currentReview.VacancyReference); if (previousReview == null) { return(vm); } //translate field name to FieldIdentifier (a single field can have multiple field identifiers) var updatedFieldIdentifiers = currentReview.UpdatedFieldIdentifiers? .SelectMany(f => ReviewFields[f]) .Distinct() .ToList() ?? new List <string>(); foreach (var field in vm) { var hasChanged = updatedFieldIdentifiers.Contains(field.FieldIdentifier); var previouslyChecked = previousReview.ManualQaFieldIndicators.Any(m => m.FieldIdentifier == field.FieldIdentifier && m.IsChangeRequested); field.FieldValueHasChanged = hasChanged; field.Checked = previouslyChecked; } return(vm); }
public bool VacancyReviewCanBeAssigned(VacancyReview review) { return(VacancyReviewCanBeAssigned(review.Status, review.ReviewedDate)); }
private Task PublishVacancyReviewApprovedEventAsync(ApproveVacancyReviewCommand message, VacancyReview review) { return(_messaging.PublishEvent(new VacancyReviewApprovedEvent { ReviewId = message.ReviewId, VacancyReference = review.VacancyReference })); }
private bool HasVacancyBeenTransferredSinceReviewWasCreated(VacancyReview review, Vacancy vacancy) { return(review.VacancySnapshot.TransferInfo == null && vacancy.TransferInfo != null); }
public IEnumerable <ReviewFieldIndicatorViewModel> MapFromFieldIndicators(ReviewFieldMappingLookupsForPage pageMappings, VacancyReview review) { var manualQaFieldIdentifierNames = review.ManualQaFieldIndicators ?.Where(r => r.IsChangeRequested) .Select(r => r.FieldIdentifier) .ToList() ?? new List <string>(); var autoQaReferredOutcomeIds = review.AutomatedQaOutcomeIndicators ?.Where(i => i.IsReferred) .Select(i => i.RuleOutcomeId) .ToList() ?? new List <Guid>(); var autoQaReferredOutcomes = review.AutomatedQaOutcome?.RuleOutcomes .SelectMany(d => d.Details) .Where(x => autoQaReferredOutcomeIds.Contains(x.Id)) .ToList() ?? new List <RuleOutcome>(); var uniqueFieldIdentifierNames = manualQaFieldIdentifierNames.Union( autoQaReferredOutcomes.SelectMany(x => pageMappings.VacancyPropertyMappingsLookup.TryGetValue(x.Target, out var value) ? value : Enumerable.Empty <string>())); var indicatorsToDisplayLookup = pageMappings.FieldIdentifiersForPage .Where(r => uniqueFieldIdentifierNames.Contains(r.ReviewFieldIdentifier)) .ToDictionary(x => x.ReviewFieldIdentifier, y => y); foreach (var indicator in indicatorsToDisplayLookup) { if (manualQaFieldIdentifierNames.Contains(indicator.Key)) { indicator.Value.ManualQaText = ManualQaMessages[indicator.Key]; } var autoQaOutcomes = autoQaReferredOutcomes.Where(x => pageMappings.VacancyPropertyMappingsLookup.TryGetValue(x.Target, out var value) && value.Contains(indicator.Key)) .Select(x => _ruleTemplateRunner.ToText(x.RuleId, x.Data, FieldDisplayNameResolver.Resolve(x.Target))); indicator.Value.AutoQaTexts.AddRange(autoQaOutcomes); } return(indicatorsToDisplayLookup.Values); }
public void ShouldMap() { var shortDescriptionProfanityCheckRuleOutcome = new RuleOutcome( RuleId.ProfanityChecks, 100, "Profanity 'drat' found in 'ShortDescription'", "ShortDescription", new List <RuleOutcome>(), "{\"Profanity\" : \"drat\",\"Occurrences\" : 1}"); var titleProfanityCheckRuleOutcome = new RuleOutcome( RuleId.ProfanityChecks, 0, "No profanities found in 'Title'", "Title"); var profanityChecksRuleOutcome = new RuleOutcome( RuleId.ProfanityChecks, 100, "No profanities found in 'Title', Profanity 'drat' found in 'ShortDescription', etc", "", new List <RuleOutcome> { shortDescriptionProfanityCheckRuleOutcome, titleProfanityCheckRuleOutcome } ); var sut = new ReviewFieldIndicatorMapper(new RuleMessageTemplateRunner()); var review = new VacancyReview { ManualQaFieldIndicators = new List <ManualQaFieldIndicator> { new ManualQaFieldIndicator { IsChangeRequested = false, FieldIdentifier = FieldIdentifiers.Title }, new ManualQaFieldIndicator { IsChangeRequested = true, FieldIdentifier = FieldIdentifiers.ShortDescription } }, AutomatedQaOutcomeIndicators = new List <RuleOutcomeIndicator> { new RuleOutcomeIndicator { IsReferred = false, RuleOutcomeId = titleProfanityCheckRuleOutcome.Id }, new RuleOutcomeIndicator { IsReferred = true, RuleOutcomeId = shortDescriptionProfanityCheckRuleOutcome.Id } }, AutomatedQaOutcome = new RuleSetOutcome { RuleOutcomes = new List <RuleOutcome> { profanityChecksRuleOutcome } } }; var vm = sut.MapFromFieldIndicators(ReviewFieldMappingLookups.GetPreviewReviewFieldIndicators(), review).ToList(); vm.Count.Should().Be(1); var shortDescription = vm.Single(v => v.ReviewFieldIdentifier == FieldIdentifiers.ShortDescription); shortDescription.ManualQaText.Should().NotBeNullOrEmpty(); shortDescription.AutoQaTexts.Count.Should().Be(1); shortDescription.AutoQaTexts[0].Should().Be("Brief overview contains the phrase 'drat'"); }