import Vue from 'vue'; import eventHub from '~/filtered_search/event_hub'; import RecentSearchesDropdownContent from '~/filtered_search/components/recent_searches_dropdown_content.vue'; import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; const createComponent = propsData => { const Component = Vue.extend(RecentSearchesDropdownContent); return new Component({ el: document.createElement('div'), propsData, }); }; // Remove all the newlines and whitespace from the formatted markup const trimMarkupWhitespace = text => text.replace(/(\n|\s)+/gm, ' ').trim(); describe('RecentSearchesDropdownContent', () => { const propsDataWithoutItems = { items: [], allowedKeys: IssuableFilteredSearchTokenKeys.getKeys(), }; const propsDataWithItems = { items: ['foo', 'author:@root label:~foo bar'], allowedKeys: IssuableFilteredSearchTokenKeys.getKeys(), }; let vm; afterEach(() => { if (vm) { vm.$destroy(); } }); describe('with no items', () => { let el; beforeEach(() => { vm = createComponent(propsDataWithoutItems); el = vm.$el; }); it('should render empty state', () => { expect(el.querySelector('.dropdown-info-note')).toBeDefined(); const items = el.querySelectorAll('.filtered-search-history-dropdown-item'); expect(items.length).toEqual(propsDataWithoutItems.items.length); }); }); describe('with items', () => { let el; beforeEach(() => { vm = createComponent(propsDataWithItems); el = vm.$el; }); it('should render clear recent searches button', () => { expect(el.querySelector('.filtered-search-history-clear-button')).toBeDefined(); }); it('should render recent search items', () => { const items = el.querySelectorAll('.filtered-search-history-dropdown-item'); expect(items.length).toEqual(propsDataWithItems.items.length); expect( trimMarkupWhitespace( items[0].querySelector('.filtered-search-history-dropdown-search-token').textContent, ), ).toEqual('foo'); const item1Tokens = items[1].querySelectorAll('.filtered-search-history-dropdown-token'); expect(item1Tokens.length).toEqual(2); expect(item1Tokens[0].querySelector('.name').textContent).toEqual('author:'); expect(item1Tokens[0].querySelector('.value').textContent).toEqual('@root'); expect(item1Tokens[1].querySelector('.name').textContent).toEqual('label:'); expect(item1Tokens[1].querySelector('.value').textContent).toEqual('~foo'); expect( trimMarkupWhitespace( items[1].querySelector('.filtered-search-history-dropdown-search-token').textContent, ), ).toEqual('bar'); }); }); describe('if isLocalStorageAvailable is `false`', () => { let el; beforeEach(() => { const props = Object.assign({ isLocalStorageAvailable: false }, propsDataWithItems); vm = createComponent(props); el = vm.$el; }); it('should render an info note', () => { const note = el.querySelector('.dropdown-info-note'); const items = el.querySelectorAll('.filtered-search-history-dropdown-item'); expect(note).toBeDefined(); expect(note.innerText.trim()).toBe('This feature requires local storage to be enabled'); expect(items.length).toEqual(propsDataWithoutItems.items.length); }); }); describe('computed', () => { describe('processedItems', () => { it('with items', () => { vm = createComponent(propsDataWithItems); const { processedItems } = vm; expect(processedItems.length).toEqual(2); expect(processedItems[0].text).toEqual(propsDataWithItems.items[0]); expect(processedItems[0].tokens).toEqual([]); expect(processedItems[0].searchToken).toEqual('foo'); expect(processedItems[1].text).toEqual(propsDataWithItems.items[1]); expect(processedItems[1].tokens.length).toEqual(2); expect(processedItems[1].tokens[0].prefix).toEqual('author:'); expect(processedItems[1].tokens[0].suffix).toEqual('@root'); expect(processedItems[1].tokens[1].prefix).toEqual('label:'); expect(processedItems[1].tokens[1].suffix).toEqual('~foo'); expect(processedItems[1].searchToken).toEqual('bar'); }); it('with no items', () => { vm = createComponent(propsDataWithoutItems); const { processedItems } = vm; expect(processedItems.length).toEqual(0); }); }); describe('hasItems', () => { it('with items', () => { vm = createComponent(propsDataWithItems); const { hasItems } = vm; expect(hasItems).toEqual(true); }); it('with no items', () => { vm = createComponent(propsDataWithoutItems); const { hasItems } = vm; expect(hasItems).toEqual(false); }); }); }); describe('methods', () => { describe('onItemActivated', () => { let onRecentSearchesItemSelectedSpy; beforeEach(() => { onRecentSearchesItemSelectedSpy = jasmine.createSpy('spy'); eventHub.$on('recentSearchesItemSelected', onRecentSearchesItemSelectedSpy); vm = createComponent(propsDataWithItems); }); afterEach(() => { eventHub.$off('recentSearchesItemSelected', onRecentSearchesItemSelectedSpy); }); it('emits event', () => { expect(onRecentSearchesItemSelectedSpy).not.toHaveBeenCalled(); vm.onItemActivated('something'); expect(onRecentSearchesItemSelectedSpy).toHaveBeenCalledWith('something'); }); }); describe('onRequestClearRecentSearches', () => { let onRequestClearRecentSearchesSpy; beforeEach(() => { onRequestClearRecentSearchesSpy = jasmine.createSpy('spy'); eventHub.$on('requestClearRecentSearches', onRequestClearRecentSearchesSpy); vm = createComponent(propsDataWithItems); }); afterEach(() => { eventHub.$off('requestClearRecentSearches', onRequestClearRecentSearchesSpy); }); it('emits event', () => { expect(onRequestClearRecentSearchesSpy).not.toHaveBeenCalled(); vm.onRequestClearRecentSearches({ stopPropagation: () => {} }); expect(onRequestClearRecentSearchesSpy).toHaveBeenCalled(); }); }); }); });