public void DFC5229ForSearchResultsShowingComputedSearchTerm(bool showComputedSearchTerm, bool useRawSearchTerm)
        {
            // Arrange
            var searchView = new _MVC_Views_JobProfileSearchBox_SearchResult_cshtml();

            var model = new JobProfileSearchResultViewModel
            {
                SearchResults      = new List <JobProfileSearchResultItemViewModel>(),
                ShowSearchedTerm   = showComputedSearchTerm,
                ComputedSearchTerm = useRawSearchTerm ? " plumbing" : " plumbing /.*plumb.*/ plumb~"
            };

            // Act
            var htmlDom = searchView.RenderAsHtml(model);

            // Asserts
            if (showComputedSearchTerm)
            {
                GetSearchComputedTermParagraph(htmlDom).Should().Be($"ComputedSearchTerm: {model.ComputedSearchTerm}");
            }
            else
            {
                GetSearchComputedTermParagraph(htmlDom).Should().BeNullOrEmpty();
            }
        }
예제 #2
0
        private void SetTotalResultsMessage(JobProfileSearchResultViewModel resultModel)
        {
            var totalFound = resultModel.Count;

            resultModel.TotalResultCount    = totalFound;
            resultModel.TotalResultsMessage = totalFound == 0 ? NoResultsMessage : $"{totalFound} result{(totalFound == 1 ? string.Empty : "s")} found";
        }
        public void DFC1494ForSearchResultsDidYouMeanTerm(string correctedSearchTerm, bool validSpellcheckResult)
        {
            // Arrange
            var searchView = new _MVC_Views_JobProfileSearchBox_SearchResult_cshtml();

            var model = new JobProfileSearchResultViewModel
            {
                DidYouMeanUrl  = new Uri(validSpellcheckResult ? $"{nameof(JobProfileSearchBoxController.SearchResultsPage)}?searchTerm={HttpUtility.UrlEncode(correctedSearchTerm)}" : string.Empty, UriKind.RelativeOrAbsolute),
                DidYouMeanTerm = validSpellcheckResult ? correctedSearchTerm : string.Empty,
                SearchResults  = new List <JobProfileSearchResultItemViewModel>()
            };

            // Act
            var htmlDom = searchView.RenderAsHtml(model);

            // Asserts
            if (validSpellcheckResult)
            {
                GetDidYouMeanText(htmlDom).Should().Be(model.DidYouMeanTerm);
                GetDidYouMeanUrl(htmlDom).Should().Be(model.DidYouMeanUrl.OriginalString);
            }
            else
            {
                GetDidYouMeanText(htmlDom).Should().BeNullOrEmpty();
            }
        }
        private async Task <ActionResult> DisplaySearchResultsAsync(string searchTerm, int page)
        {
            var resultModel = new JobProfileSearchResultViewModel
            {
                PlaceholderText = PlaceholderText,
                SearchTerm      = searchTerm,
                AutoCompleteMinimumCharacters       = AutoCompleteMinimumCharacters,
                AutoCompleteMaximumCharacters       = AutoCompleteMaximumCharacters,
                MaximumNumberOfDisplayedSuggestions = MaximumNumberOfDisplayedSuggestions,
                UseFuzzyAutoCompleteMatching        = UseFuzzyAutoCompleteMatching,
                JobProfileCategoryPage = JobProfileCategoryPage,
                SalaryBlankText        = SalaryBlankText,
                ShowSearchedTerm       = ShowComputedSearchTerm
            };

            if (!string.IsNullOrWhiteSpace(searchTerm))
            {
                var pageNumber = page > 0 ? page : 1;
                var searchTask = searchQueryService.SearchAsync(searchTerm, new SearchProperties {
                    Page = pageNumber, Count = this.PageSize, UseRawSearchTerm = UseRawSearchTerm
                });
                var spellCheckTask = spellcheckService.CheckSpellingAsync(searchTerm);

                await Task.WhenAll(searchTask, spellCheckTask);

                var results = searchTask.Result;
                resultModel.Count              = results.Count;
                resultModel.Coverage           = results.Coverage;
                resultModel.ComputedSearchTerm = results.ComputedSearchTerm;
                resultModel.PageNumber         = pageNumber;
                resultModel.SearchResults      = mapper.Map <IEnumerable <JobProfileSearchResultItemViewModel> >(results.Results);
                foreach (var resultItem in resultModel.SearchResults)
                {
                    resultItem.ResultItemUrlName = $"{JobProfileDetailsPage}{resultItem.ResultItemUrlName}";
                }

                SetTotalResultsMessage(resultModel);
                SetupPagination(searchTerm, resultModel);

                var spellCheckResult = spellCheckTask.Result;
                if (spellCheckResult.HasCorrected)
                {
                    resultModel.DidYouMeanUrl  = GetSearchResultsPageUrl(spellCheckResult.CorrectedTerm);
                    resultModel.DidYouMeanTerm = spellCheckResult.CorrectedTerm;
                }
            }

            return(View("SearchResult", resultModel));
        }
예제 #5
0
        private void SetupPagination(JobProfileSearchResultViewModel resultModel)
        {
            resultModel.TotalPages = (int)Math.Ceiling((double)resultModel.Count / PageSize);

            if (resultModel.TotalPages > 1 && resultModel.TotalPages >= resultModel.PageNumber)
            {
                resultModel.NextPageUrl     = new Uri($"{PsfSearchResultsPage}?page={resultModel.PageNumber + 1}", UriKind.RelativeOrAbsolute);
                resultModel.NextPageUrlText = $"{resultModel.PageNumber + 1} of {resultModel.TotalPages}";

                if (resultModel.PageNumber > 1)
                {
                    resultModel.PreviousPageUrl     = new Uri($"{PsfSearchResultsPage}{(resultModel.PageNumber == 2 ? string.Empty : $"?page={resultModel.PageNumber - 1}")}", UriKind.RelativeOrAbsolute);
                    resultModel.PreviousPageUrlText = $"{resultModel.PageNumber - 1} of {resultModel.TotalPages}";
                }
            }
예제 #6
0
        private void SetMatchingSkillsCount(JobProfileSearchResultViewModel resultViewModel, PreSearchFiltersResultsModel preSearchFiltersResultsModel, SearchResult <JobProfileIndex> searchResult)
        {
            var fieldFilter = preSearchFiltersResultsModel.Sections?.FirstOrDefault(section =>
                                                                                    section.SectionDataTypes.Equals("Skills", StringComparison.InvariantCultureIgnoreCase));

            if (fieldFilter?.Options.Count > 0)
            {
                var selectedSkills = fieldFilter.Options.Where(opt => opt.IsSelected).Select(opt => opt.OptionKey);
                foreach (var viewItem in resultViewModel.SearchResults)
                {
                    var resultItem = searchResult.Results.Where(r => r.ResultItem.UrlName == viewItem.ResultItemUrlName).FirstOrDefault().ResultItem;
                    viewItem.MatchingSkillsCount = resultItem.Skills.Count(skill => selectedSkills.Contains(skill));
                }
            }
        }
        public ActionResult Search(string searchTerm, string jobProfileUrl)
        {
            if (!string.IsNullOrWhiteSpace(searchTerm))
            {
                return(Redirect($"{SearchResultsPage}?searchTerm={GetUrlEncodedString(searchTerm)}"));
            }

            switch (CurrentPageMode)
            {
            case SearchWidgetPageMode.SearchResults:
                var searchModel = new JobProfileSearchResultViewModel
                {
                    PlaceholderText = PlaceholderText,
                    AutoCompleteMinimumCharacters       = AutoCompleteMinimumCharacters,
                    AutoCompleteMaximumCharacters       = AutoCompleteMaximumCharacters,
                    MaximumNumberOfDisplayedSuggestions = MaximumNumberOfDisplayedSuggestions,
                    UseFuzzyAutoCompleteMatching        = UseFuzzyAutoCompleteMatching,
                    SalaryBlankText = SalaryBlankText
                };
                return(View("SearchResult", searchModel));

            case SearchWidgetPageMode.JobProfile:
                bool isValidUrl = this.webAppContext.IsValidAndFormattedUrl($"{JobProfileDetailsPage}{jobProfileUrl}/");
                return(isValidUrl
                            ? (ActionResult) new RedirectResult($"{JobProfileDetailsPage}{jobProfileUrl}")
                            : HttpNotFound());

            default:
                var model = new JobProfileSearchBoxViewModel
                {
                    PlaceholderText = PlaceholderText,
                    AutoCompleteMinimumCharacters       = AutoCompleteMinimumCharacters,
                    AutoCompleteMaximumCharacters       = AutoCompleteMaximumCharacters,
                    MaximumNumberOfDisplayedSuggestions = MaximumNumberOfDisplayedSuggestions,
                    UseFuzzyAutoCompleteMatching        = UseFuzzyAutoCompleteMatching
                };
                return(View("Index", model));
            }
        }
        public void SearchResultsPaginationViewModelTest(string searchTerm, SearchWidgetPageMode mode, int resultsCount, int page, int pageSize)
        {
            //Setup Fakes & dummies
            var queryServiceFake               = A.Fake <ISearchQueryService <JobProfileIndex> >(ops => ops.Strict());
            var loggerFake                     = A.Fake <IApplicationLogger>();
            var webAppContext                  = A.Fake <IWebAppContext>(ops => ops.Strict());
            var defaultJobProfilePage          = "/jobprofile-details/";
            var defaultSearchResultsPage       = "/search-result";
            var defaultJobProfileCateegoryPage = "/job-categories/";
            var expectedTotalMessage           = "0 results found - try again using a different job title";
            var placeholderText                = "Enter a job title or keywords";
            var salaryBlankText                = "Variable";
            var fakeSpellChecker               = A.Fake <ISpellcheckService>();
            var fakeAsyncHelper                = new AsyncHelper();
            var mapperCfg = new MapperConfiguration(cfg =>
            {
                cfg.AddProfile <JobProfilesAutoMapperProfile>();
            });

            var expectedSearchResultsViewModel = Enumerable.Empty <JobProfileSearchResultItemViewModel>();
            var dummySearchResult = A.Dummy <SearchResult <JobProfileIndex> >();
            var expectedViewModel = new JobProfileSearchResultViewModel
            {
                TotalPages      = (resultsCount + pageSize - 1) / pageSize,
                Count           = resultsCount,
                SearchTerm      = searchTerm,
                PlaceholderText = placeholderText,
                AutoCompleteMinimumCharacters       = 2,
                MaximumNumberOfDisplayedSuggestions = 5,
                UseFuzzyAutoCompleteMatching        = true,
                JobProfileCategoryPage        = defaultJobProfileCateegoryPage,
                SalaryBlankText               = salaryBlankText,
                AutoCompleteMaximumCharacters = 7
            };

            if (string.IsNullOrWhiteSpace(searchTerm))
            {
                dummySearchResult.Results = Enumerable.Empty <SearchResultItem <JobProfileIndex> >();
                dummySearchResult.Count   = 0;
            }
            else
            {
                var currentPage = page > 0 ? page : 1;
                var dummyIndex  = new JobProfileIndex
                {
                    Title                       = searchTerm,
                    AlternativeTitle            = new[] { "alt" },
                    SalaryStarter               = 10,
                    SalaryExperienced           = 10,
                    Overview                    = "overview",
                    UrlName                     = "dummy-url",
                    JobProfileCategoriesWithUrl = new[] { "CatOneURL|Cat One", "CatTwoURL|Cat Two" }
                };

                dummySearchResult.Count = resultsCount;
                expectedTotalMessage    = $"{resultsCount} result{(resultsCount == 1 ? string.Empty : "s")} found";
                expectedViewModel.TotalResultsMessage = expectedTotalMessage;
                if (expectedViewModel.TotalPages > 1)
                {
                    expectedViewModel.PageNumber      = currentPage;
                    expectedViewModel.NextPageUrl     = new Uri($"{defaultSearchResultsPage}?searchTerm={HttpUtility.UrlEncode(searchTerm)}&page={currentPage + 1}", UriKind.RelativeOrAbsolute);
                    expectedViewModel.NextPageUrlText = $"{currentPage + 1} of {expectedViewModel.TotalPages}";
                    if (currentPage > 1)
                    {
                        expectedViewModel.PreviousPageUrl     = new Uri($"{defaultSearchResultsPage}?searchTerm={HttpUtility.UrlEncode(searchTerm)}&page={currentPage - 1}", UriKind.RelativeOrAbsolute);
                        expectedViewModel.PreviousPageUrlText = $"{currentPage - 1} of {expectedViewModel.TotalPages}";
                    }
                }

                expectedViewModel.PageNumber = currentPage;
                dummySearchResult.Results    = A.CollectionOfDummy <SearchResultItem <JobProfileIndex> >(resultsCount);
                var rawResultItems = new List <SearchResultItem <JobProfileIndex> >();
                for (int i = 0; i < resultsCount; i++)
                {
                    rawResultItems.Add(new SearchResultItem <JobProfileIndex> {
                        ResultItem = dummyIndex
                    });
                }

                dummySearchResult.Results = rawResultItems;
                var expectedSearchResultsRawViewModel = new List <JobProfileSearchResultItemViewModel>();
                foreach (var dummyIndexItem in dummySearchResult.Results)
                {
                    expectedSearchResultsRawViewModel.Add(new JobProfileSearchResultItemViewModel
                    {
                        ResultItemTitle            = dummyIndexItem.ResultItem.Title,
                        ResultItemAlternativeTitle = string.Join(", ", dummyIndexItem.ResultItem.AlternativeTitle).Trim().TrimEnd(','),
                        ResultItemSalaryRange      = string.Format(new CultureInfo("en-GB", false), "{0:C0} to {1:C0}", dummyIndexItem.ResultItem.SalaryStarter, dummyIndexItem.ResultItem.SalaryExperienced),
                        ResultItemOverview         = dummyIndexItem.ResultItem.Overview,
                        ResultItemUrlName          = $"{defaultJobProfilePage}{dummyIndexItem.ResultItem.UrlName}",
                        Rank  = (int)dummyIndexItem.Rank,
                        Score = dummyIndexItem.Score,
                        JobProfileCategoriesWithUrl = dummyIndexItem.ResultItem.JobProfileCategoriesWithUrl
                    });
                }

                expectedSearchResultsViewModel  = expectedSearchResultsRawViewModel.AsEnumerable();
                expectedViewModel.SearchResults = expectedSearchResultsViewModel;
            }

            //Set-up calls
            A.CallTo(() => queryServiceFake.SearchAsync(A <string> ._, A <SearchProperties> ._)).Returns(dummySearchResult);

            //Instantiate
            var searchController = new JobProfileSearchBoxController(queryServiceFake, webAppContext, mapperCfg.CreateMapper(), loggerFake, fakeAsyncHelper, fakeSpellChecker)
            {
                CurrentPageMode       = mode,
                JobProfileDetailsPage = defaultJobProfilePage,
                PageSize          = pageSize,
                SearchResultsPage = defaultSearchResultsPage,
                PlaceholderText   = placeholderText
            };

            //Act
            var searchMethodCall = searchController.WithCallTo(c => c.Index(searchTerm, page));

            if (mode == SearchWidgetPageMode.SearchResults)
            {
                //Assert
                searchMethodCall
                .ShouldRenderView("SearchResult")
                .WithModel <JobProfileSearchResultViewModel>(vm =>
                {
                    vm.Should().BeEquivalentTo(expectedViewModel);
                })
                .AndNoModelErrors()
                ;

                A.CallTo(() => queryServiceFake.SearchAsync(A <string> ._, A <SearchProperties> .That.Matches(m => m.Page == page && m.Count == pageSize))).MustHaveHappened();
                A.CallTo(() => fakeSpellChecker.CheckSpellingAsync(A <string> ._)).MustHaveHappened();
            }
        }