2021-11-11 11:23:49 +05:30
import { GlSearchBoxByType } from '@gitlab/ui' ;
2022-04-04 11:22:00 +05:30
import Vue , { nextTick } from 'vue' ;
2021-11-11 11:23:49 +05:30
import Vuex from 'vuex' ;
import { shallowMountExtended } from 'helpers/vue_test_utils_helper' ;
import HeaderSearchApp from '~/header_search/components/app.vue' ;
2021-11-18 22:05:49 +05:30
import HeaderSearchAutocompleteItems from '~/header_search/components/header_search_autocomplete_items.vue' ;
2021-11-11 11:23:49 +05:30
import HeaderSearchDefaultItems from '~/header_search/components/header_search_default_items.vue' ;
import HeaderSearchScopedItems from '~/header_search/components/header_search_scoped_items.vue' ;
2022-01-26 12:08:38 +05:30
import { SEARCH _INPUT _DESCRIPTION , SEARCH _RESULTS _DESCRIPTION } from '~/header_search/constants' ;
import DropdownKeyboardNavigation from '~/vue_shared/components/dropdown_keyboard_navigation.vue' ;
import { ENTER _KEY } from '~/lib/utils/keys' ;
2021-11-11 11:23:49 +05:30
import { visitUrl } from '~/lib/utils/url_utility' ;
2022-01-26 12:08:38 +05:30
import {
MOCK _SEARCH ,
MOCK _SEARCH _QUERY ,
MOCK _USERNAME ,
MOCK _DEFAULT _SEARCH _OPTIONS ,
MOCK _SCOPED _SEARCH _OPTIONS ,
2022-06-21 17:19:12 +05:30
MOCK _SORTED _AUTOCOMPLETE _OPTIONS ,
2022-01-26 12:08:38 +05:30
} from '../mock_data' ;
2021-11-11 11:23:49 +05:30
Vue . use ( Vuex ) ;
jest . mock ( '~/lib/utils/url_utility' , ( ) => ( {
visitUrl : jest . fn ( ) ,
} ) ) ;
describe ( 'HeaderSearchApp' , ( ) => {
let wrapper ;
const actionSpies = {
setSearch : jest . fn ( ) ,
2021-11-18 22:05:49 +05:30
fetchAutocompleteOptions : jest . fn ( ) ,
2022-01-26 12:08:38 +05:30
clearAutocomplete : jest . fn ( ) ,
2021-11-11 11:23:49 +05:30
} ;
2022-01-26 12:08:38 +05:30
const createComponent = ( initialState , mockGetters ) => {
2021-11-11 11:23:49 +05:30
const store = new Vuex . Store ( {
state : {
... initialState ,
} ,
actions : actionSpies ,
getters : {
searchQuery : ( ) => MOCK _SEARCH _QUERY ,
2022-01-26 12:08:38 +05:30
searchOptions : ( ) => MOCK _DEFAULT _SEARCH _OPTIONS ,
... mockGetters ,
2021-11-11 11:23:49 +05:30
} ,
} ) ;
wrapper = shallowMountExtended ( HeaderSearchApp , {
store ,
} ) ;
} ;
afterEach ( ( ) => {
wrapper . destroy ( ) ;
} ) ;
const findHeaderSearchInput = ( ) => wrapper . findComponent ( GlSearchBoxByType ) ;
const findHeaderSearchDropdown = ( ) => wrapper . findByTestId ( 'header-search-dropdown-menu' ) ;
const findHeaderSearchDefaultItems = ( ) => wrapper . findComponent ( HeaderSearchDefaultItems ) ;
const findHeaderSearchScopedItems = ( ) => wrapper . findComponent ( HeaderSearchScopedItems ) ;
2021-11-18 22:05:49 +05:30
const findHeaderSearchAutocompleteItems = ( ) =>
wrapper . findComponent ( HeaderSearchAutocompleteItems ) ;
2022-01-26 12:08:38 +05:30
const findDropdownKeyboardNavigation = ( ) => wrapper . findComponent ( DropdownKeyboardNavigation ) ;
const findSearchInputDescription = ( ) => wrapper . find ( ` # ${ SEARCH _INPUT _DESCRIPTION } ` ) ;
const findSearchResultsDescription = ( ) => wrapper . findByTestId ( SEARCH _RESULTS _DESCRIPTION ) ;
2021-11-11 11:23:49 +05:30
describe ( 'template' , ( ) => {
2022-01-26 12:08:38 +05:30
describe ( 'always renders' , ( ) => {
beforeEach ( ( ) => {
createComponent ( ) ;
} ) ;
it ( 'Header Search Input' , ( ) => {
expect ( findHeaderSearchInput ( ) . exists ( ) ) . toBe ( true ) ;
} ) ;
it ( 'Search Input Description' , ( ) => {
expect ( findSearchInputDescription ( ) . exists ( ) ) . toBe ( true ) ;
} ) ;
it ( 'Search Results Description' , ( ) => {
expect ( findSearchResultsDescription ( ) . exists ( ) ) . toBe ( true ) ;
} ) ;
2021-11-11 11:23:49 +05:30
} ) ;
describe . each `
showDropdown | username | showSearchDropdown
$ { false } | $ { null } | $ { false }
$ { false } | $ { MOCK _USERNAME } | $ { false }
$ { true } | $ { null } | $ { false }
$ { true } | $ { MOCK _USERNAME } | $ { true }
` ('Header Search Dropdown', ({ showDropdown, username, showSearchDropdown }) => {
describe ( ` when showDropdown is ${ showDropdown } and current_username is ${ username } ` , ( ) => {
beforeEach ( ( ) => {
window . gon . current _username = username ;
2022-01-26 12:08:38 +05:30
createComponent ( ) ;
findHeaderSearchInput ( ) . vm . $emit ( showDropdown ? 'click' : '' ) ;
2021-11-11 11:23:49 +05:30
} ) ;
it ( ` should ${ showSearchDropdown ? '' : ' not' } render ` , ( ) => {
expect ( findHeaderSearchDropdown ( ) . exists ( ) ) . toBe ( showSearchDropdown ) ;
} ) ;
} ) ;
} ) ;
describe . each `
2022-01-26 12:08:38 +05:30
search | showDefault | showScoped | showAutocomplete | showDropdownNavigation
$ { null } | $ { true } | $ { false } | $ { false } | $ { true }
$ { '' } | $ { true } | $ { false } | $ { false } | $ { true }
2022-06-21 17:19:12 +05:30
$ { '1' } | $ { false } | $ { false } | $ { false } | $ { false }
$ { ')' } | $ { false } | $ { false } | $ { false } | $ { false }
$ { 't' } | $ { false } | $ { false } | $ { true } | $ { true }
$ { 'te' } | $ { false } | $ { true } | $ { true } | $ { true }
$ { 'tes' } | $ { false } | $ { true } | $ { true } | $ { true }
2022-01-26 12:08:38 +05:30
$ { MOCK _SEARCH } | $ { false } | $ { true } | $ { true } | $ { true }
` (
'Header Search Dropdown Items' ,
( { search , showDefault , showScoped , showAutocomplete , showDropdownNavigation } ) => {
describe ( ` when search is ${ search } ` , ( ) => {
beforeEach ( ( ) => {
window . gon . current _username = MOCK _USERNAME ;
2022-06-21 17:19:12 +05:30
createComponent (
{ search } ,
{
autocompleteGroupedSearchOptions : ( ) =>
search . match ( /^[A-Za-z]+$/g ) ? MOCK _SORTED _AUTOCOMPLETE _OPTIONS : [ ] ,
} ,
) ;
2022-01-26 12:08:38 +05:30
findHeaderSearchInput ( ) . vm . $emit ( 'click' ) ;
} ) ;
it ( ` should ${ showDefault ? '' : ' not' } render the Default Dropdown Items ` , ( ) => {
expect ( findHeaderSearchDefaultItems ( ) . exists ( ) ) . toBe ( showDefault ) ;
} ) ;
it ( ` should ${ showScoped ? '' : ' not' } render the Scoped Dropdown Items ` , ( ) => {
expect ( findHeaderSearchScopedItems ( ) . exists ( ) ) . toBe ( showScoped ) ;
} ) ;
it ( ` should ${
showAutocomplete ? '' : ' not'
} render the Autocomplete Dropdown Items ` , () => {
expect ( findHeaderSearchAutocompleteItems ( ) . exists ( ) ) . toBe ( showAutocomplete ) ;
} ) ;
it ( ` should ${
showDropdownNavigation ? '' : ' not'
} render the Dropdown Navigation Component ` , () => {
expect ( findDropdownKeyboardNavigation ( ) . exists ( ) ) . toBe ( showDropdownNavigation ) ;
} ) ;
2021-11-11 11:23:49 +05:30
} ) ;
2022-01-26 12:08:38 +05:30
} ,
) ;
2021-11-11 11:23:49 +05:30
2022-01-26 12:08:38 +05:30
describe . each `
username | showDropdown | expectedDesc
$ { null } | $ { false } | $ { HeaderSearchApp . i18n . searchInputDescribeByNoDropdown }
$ { null } | $ { true } | $ { HeaderSearchApp . i18n . searchInputDescribeByNoDropdown }
$ { MOCK _USERNAME } | $ { false } | $ { HeaderSearchApp . i18n . searchInputDescribeByWithDropdown }
$ { MOCK _USERNAME } | $ { true } | $ { HeaderSearchApp . i18n . searchInputDescribeByWithDropdown }
` ('Search Input Description', ({ username, showDropdown, expectedDesc }) => {
describe ( ` current_username is ${ username } and showDropdown is ${ showDropdown } ` , ( ) => {
beforeEach ( ( ) => {
window . gon . current _username = username ;
createComponent ( ) ;
findHeaderSearchInput ( ) . vm . $emit ( showDropdown ? 'click' : '' ) ;
2021-11-11 11:23:49 +05:30
} ) ;
2021-11-18 22:05:49 +05:30
2022-01-26 12:08:38 +05:30
it ( ` sets description to ${ expectedDesc } ` , ( ) => {
expect ( findSearchInputDescription ( ) . text ( ) ) . toBe ( expectedDesc ) ;
2021-11-18 22:05:49 +05:30
} ) ;
2021-11-11 11:23:49 +05:30
} ) ;
} ) ;
2022-01-26 12:08:38 +05:30
describe . each `
username | showDropdown | search | loading | searchOptions | expectedDesc
$ { null } | $ { true } | $ { '' } | $ { false } | $ { [ ] } | $ { '' }
$ { MOCK _USERNAME } | $ { false } | $ { '' } | $ { false } | $ { [ ] } | $ { '' }
$ { MOCK _USERNAME } | $ { true } | $ { '' } | $ { false } | $ { MOCK _DEFAULT _SEARCH _OPTIONS } | $ { ` ${ MOCK _DEFAULT _SEARCH _OPTIONS . length } default results provided. Use the up and down arrow keys to navigate search results list. ` }
$ { MOCK _USERNAME } | $ { true } | $ { '' } | $ { true } | $ { MOCK _DEFAULT _SEARCH _OPTIONS } | $ { ` ${ MOCK _DEFAULT _SEARCH _OPTIONS . length } default results provided. Use the up and down arrow keys to navigate search results list. ` }
$ { MOCK _USERNAME } | $ { true } | $ { MOCK _SEARCH } | $ { false } | $ { MOCK _SCOPED _SEARCH _OPTIONS } | $ { ` Results updated. ${ MOCK _SCOPED _SEARCH _OPTIONS . length } results available. Use the up and down arrow keys to navigate search results list, or ENTER to submit. ` }
$ { MOCK _USERNAME } | $ { true } | $ { MOCK _SEARCH } | $ { true } | $ { MOCK _SCOPED _SEARCH _OPTIONS } | $ { HeaderSearchApp . i18n . searchResultsLoading }
` (
'Search Results Description' ,
( { username , showDropdown , search , loading , searchOptions , expectedDesc } ) => {
describe ( ` search is ${ search } , loading is ${ loading } , and showSearchDropdown is ${
Boolean ( username ) && showDropdown
} ` , () => {
beforeEach ( ( ) => {
window . gon . current _username = username ;
createComponent ( { search , loading } , { searchOptions : ( ) => searchOptions } ) ;
findHeaderSearchInput ( ) . vm . $emit ( showDropdown ? 'click' : '' ) ;
} ) ;
it ( ` sets description to ${ expectedDesc } ` , ( ) => {
expect ( findSearchResultsDescription ( ) . text ( ) ) . toBe ( expectedDesc ) ;
} ) ;
} ) ;
} ,
) ;
2021-11-11 11:23:49 +05:30
} ) ;
describe ( 'events' , ( ) => {
beforeEach ( ( ) => {
createComponent ( ) ;
window . gon . current _username = MOCK _USERNAME ;
} ) ;
describe ( 'Header Search Input' , ( ) => {
describe ( 'when dropdown is closed' , ( ) => {
it ( 'onFocus opens dropdown' , async ( ) => {
expect ( findHeaderSearchDropdown ( ) . exists ( ) ) . toBe ( false ) ;
findHeaderSearchInput ( ) . vm . $emit ( 'focus' ) ;
2022-04-04 11:22:00 +05:30
await nextTick ( ) ;
2021-11-11 11:23:49 +05:30
expect ( findHeaderSearchDropdown ( ) . exists ( ) ) . toBe ( true ) ;
} ) ;
it ( 'onClick opens dropdown' , async ( ) => {
expect ( findHeaderSearchDropdown ( ) . exists ( ) ) . toBe ( false ) ;
findHeaderSearchInput ( ) . vm . $emit ( 'click' ) ;
2022-04-04 11:22:00 +05:30
await nextTick ( ) ;
2021-11-11 11:23:49 +05:30
expect ( findHeaderSearchDropdown ( ) . exists ( ) ) . toBe ( true ) ;
} ) ;
} ) ;
2022-01-26 12:08:38 +05:30
describe ( 'onInput' , ( ) => {
describe ( 'when search has text' , ( ) => {
beforeEach ( ( ) => {
findHeaderSearchInput ( ) . vm . $emit ( 'input' , MOCK _SEARCH ) ;
} ) ;
it ( 'calls setSearch with search term' , ( ) => {
expect ( actionSpies . setSearch ) . toHaveBeenCalledWith ( expect . any ( Object ) , MOCK _SEARCH ) ;
} ) ;
it ( 'calls fetchAutocompleteOptions' , ( ) => {
expect ( actionSpies . fetchAutocompleteOptions ) . toHaveBeenCalled ( ) ;
} ) ;
it ( 'does not call clearAutocomplete' , ( ) => {
expect ( actionSpies . clearAutocomplete ) . not . toHaveBeenCalled ( ) ;
} ) ;
2021-11-11 11:23:49 +05:30
} ) ;
2022-01-26 12:08:38 +05:30
describe ( 'when search is emptied' , ( ) => {
beforeEach ( ( ) => {
findHeaderSearchInput ( ) . vm . $emit ( 'input' , '' ) ;
} ) ;
2021-11-11 11:23:49 +05:30
2022-01-26 12:08:38 +05:30
it ( 'calls setSearch with empty term' , ( ) => {
expect ( actionSpies . setSearch ) . toHaveBeenCalledWith ( expect . any ( Object ) , '' ) ;
} ) ;
2021-11-11 11:23:49 +05:30
2022-01-26 12:08:38 +05:30
it ( 'does not call fetchAutocompleteOptions' , ( ) => {
expect ( actionSpies . fetchAutocompleteOptions ) . not . toHaveBeenCalled ( ) ;
} ) ;
it ( 'calls clearAutocomplete' , ( ) => {
expect ( actionSpies . clearAutocomplete ) . toHaveBeenCalled ( ) ;
} ) ;
2021-11-11 11:23:49 +05:30
} ) ;
} ) ;
2022-01-26 12:08:38 +05:30
} ) ;
2021-11-11 11:23:49 +05:30
2022-01-26 12:08:38 +05:30
describe ( 'Dropdown Keyboard Navigation' , ( ) => {
beforeEach ( ( ) => {
findHeaderSearchInput ( ) . vm . $emit ( 'click' ) ;
} ) ;
2021-11-11 11:23:49 +05:30
2022-01-26 12:08:38 +05:30
it ( 'closes dropdown when @tab is emitted' , async ( ) => {
expect ( findHeaderSearchDropdown ( ) . exists ( ) ) . toBe ( true ) ;
findDropdownKeyboardNavigation ( ) . vm . $emit ( 'tab' ) ;
2021-11-11 11:23:49 +05:30
2022-04-04 11:22:00 +05:30
await nextTick ( ) ;
2022-01-26 12:08:38 +05:30
expect ( findHeaderSearchDropdown ( ) . exists ( ) ) . toBe ( false ) ;
} ) ;
} ) ;
} ) ;
describe ( 'computed' , ( ) => {
describe ( 'currentFocusedOption' , ( ) => {
const MOCK _INDEX = 1 ;
beforeEach ( ( ) => {
createComponent ( ) ;
window . gon . current _username = MOCK _USERNAME ;
findHeaderSearchInput ( ) . vm . $emit ( 'click' ) ;
} ) ;
it ( ` when currentFocusIndex changes to ${ MOCK _INDEX } updates the data to searchOptions[ ${ MOCK _INDEX } ] ` , async ( ) => {
findDropdownKeyboardNavigation ( ) . vm . $emit ( 'change' , MOCK _INDEX ) ;
2022-04-04 11:22:00 +05:30
await nextTick ( ) ;
2022-01-26 12:08:38 +05:30
expect ( wrapper . vm . currentFocusedOption ) . toBe ( MOCK _DEFAULT _SEARCH _OPTIONS [ MOCK _INDEX ] ) ;
2021-11-11 11:23:49 +05:30
} ) ;
2022-01-26 12:08:38 +05:30
} ) ;
} ) ;
2021-11-11 11:23:49 +05:30
2022-01-26 12:08:38 +05:30
describe ( 'Submitting a search' , ( ) => {
describe ( 'with no currentFocusedOption' , ( ) => {
beforeEach ( ( ) => {
createComponent ( ) ;
} ) ;
it ( 'onKey-enter submits a search' , async ( ) => {
2021-11-11 11:23:49 +05:30
findHeaderSearchInput ( ) . vm . $emit ( 'keydown' , new KeyboardEvent ( { key : ENTER _KEY } ) ) ;
2022-04-04 11:22:00 +05:30
await nextTick ( ) ;
2021-11-11 11:23:49 +05:30
expect ( visitUrl ) . toHaveBeenCalledWith ( MOCK _SEARCH _QUERY ) ;
} ) ;
} ) ;
2022-01-26 12:08:38 +05:30
describe ( 'with currentFocusedOption' , ( ) => {
const MOCK _INDEX = 1 ;
beforeEach ( ( ) => {
createComponent ( ) ;
window . gon . current _username = MOCK _USERNAME ;
findHeaderSearchInput ( ) . vm . $emit ( 'click' ) ;
} ) ;
it ( 'onKey-enter clicks the selected dropdown item rather than submitting a search' , async ( ) => {
findDropdownKeyboardNavigation ( ) . vm . $emit ( 'change' , MOCK _INDEX ) ;
2022-04-04 11:22:00 +05:30
await nextTick ( ) ;
2022-01-26 12:08:38 +05:30
findHeaderSearchInput ( ) . vm . $emit ( 'keydown' , new KeyboardEvent ( { key : ENTER _KEY } ) ) ;
expect ( visitUrl ) . toHaveBeenCalledWith ( MOCK _DEFAULT _SEARCH _OPTIONS [ MOCK _INDEX ] . url ) ;
} ) ;
} ) ;
2021-11-11 11:23:49 +05:30
} ) ;
} ) ;