diff options
Diffstat (limited to 'spec/javascripts/filtered_search')
7 files changed, 0 insertions, 1831 deletions
diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js deleted file mode 100644 index 6eda4f391a4..00000000000 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js +++ /dev/null @@ -1,374 +0,0 @@ -import DropdownUtils from '~/filtered_search/dropdown_utils'; -import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager'; -import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; -import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper'; - -describe('Dropdown Utils', () => { - const issueListFixture = 'issues/issue_list.html'; - preloadFixtures(issueListFixture); - - describe('getEscapedText', () => { - it('should return same word when it has no space', () => { - const escaped = DropdownUtils.getEscapedText('textWithoutSpace'); - - expect(escaped).toBe('textWithoutSpace'); - }); - - it('should escape with double quotes', () => { - let escaped = DropdownUtils.getEscapedText('text with space'); - - expect(escaped).toBe('"text with space"'); - - escaped = DropdownUtils.getEscapedText("won't fix"); - - expect(escaped).toBe('"won\'t fix"'); - }); - - it('should escape with single quotes', () => { - const escaped = DropdownUtils.getEscapedText('won"t fix'); - - expect(escaped).toBe("'won\"t fix'"); - }); - - it('should escape with single quotes by default', () => { - const escaped = DropdownUtils.getEscapedText('won"t\' fix'); - - expect(escaped).toBe("'won\"t' fix'"); - }); - }); - - describe('filterWithSymbol', () => { - let input; - const item = { - title: '@root', - }; - - beforeEach(() => { - setFixtures(` - <input type="text" id="test" /> - `); - - input = document.getElementById('test'); - }); - - it('should filter without symbol', () => { - input.value = 'roo'; - - const updatedItem = DropdownUtils.filterWithSymbol('@', input, item); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with symbol', () => { - input.value = '@roo'; - - const updatedItem = DropdownUtils.filterWithSymbol('@', input, item); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - describe('filters multiple word title', () => { - const multipleWordItem = { - title: 'Community Contributions', - }; - - it('should filter with double quote', () => { - input.value = '"'; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with double quote and symbol', () => { - input.value = '~"'; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with double quote and multiple words', () => { - input.value = '"community con'; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with double quote, symbol and multiple words', () => { - input.value = '~"community con'; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with single quote', () => { - input.value = "'"; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with single quote and symbol', () => { - input.value = "~'"; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with single quote and multiple words', () => { - input.value = "'community con"; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should filter with single quote, symbol and multiple words', () => { - input.value = "~'community con"; - - const updatedItem = DropdownUtils.filterWithSymbol('~', input, multipleWordItem); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - }); - }); - - describe('filterHint', () => { - let input; - let allowedKeys; - - beforeEach(() => { - setFixtures(` - <ul class="tokens-container"> - <li class="input-token"> - <input class="filtered-search" type="text" id="test" /> - </li> - </ul> - `); - - input = document.getElementById('test'); - allowedKeys = IssuableFilteredSearchTokenKeys.getKeys(); - }); - - function config() { - return { - input, - allowedKeys, - }; - } - - it('should filter', () => { - input.value = 'l'; - let updatedItem = DropdownUtils.filterHint(config(), { - hint: 'label', - }); - - expect(updatedItem.droplab_hidden).toBe(false); - - input.value = 'o'; - updatedItem = DropdownUtils.filterHint(config(), { - hint: 'label', - }); - - expect(updatedItem.droplab_hidden).toBe(true); - }); - - it('should return droplab_hidden false when item has no hint', () => { - const updatedItem = DropdownUtils.filterHint(config(), {}, ''); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should allow multiple if item.type is array', () => { - input.value = 'label:~first la'; - const updatedItem = DropdownUtils.filterHint(config(), { - hint: 'label', - type: 'array', - }); - - expect(updatedItem.droplab_hidden).toBe(false); - }); - - it('should prevent multiple if item.type is not array', () => { - input.value = 'milestone:~first mile'; - let updatedItem = DropdownUtils.filterHint(config(), { - hint: 'milestone', - }); - - expect(updatedItem.droplab_hidden).toBe(true); - - updatedItem = DropdownUtils.filterHint(config(), { - hint: 'milestone', - type: 'string', - }); - - expect(updatedItem.droplab_hidden).toBe(true); - }); - }); - - describe('setDataValueIfSelected', () => { - beforeEach(() => { - spyOn(FilteredSearchDropdownManager, 'addWordToInput').and.callFake(() => {}); - }); - - it('calls addWordToInput when dataValue exists', () => { - const selected = { - getAttribute: () => 'value', - hasAttribute: () => false, - }; - - DropdownUtils.setDataValueIfSelected(null, '=', selected); - - expect(FilteredSearchDropdownManager.addWordToInput.calls.count()).toEqual(1); - }); - - it('returns true when dataValue exists', () => { - const selected = { - getAttribute: () => 'value', - hasAttribute: () => false, - }; - - const result = DropdownUtils.setDataValueIfSelected(null, '=', selected); - const result2 = DropdownUtils.setDataValueIfSelected(null, '!=', selected); - - expect(result).toBe(true); - expect(result2).toBe(true); - }); - - it('returns false when dataValue does not exist', () => { - const selected = { - getAttribute: () => null, - }; - - const result = DropdownUtils.setDataValueIfSelected(null, '=', selected); - const result2 = DropdownUtils.setDataValueIfSelected(null, '!=', selected); - - expect(result).toBe(false); - expect(result2).toBe(false); - }); - }); - - describe('getInputSelectionPosition', () => { - describe('word with trailing spaces', () => { - const value = 'label:none '; - - it('should return selectionStart when cursor is at the trailing space', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 11, - value, - }); - - expect(left).toBe(11); - expect(right).toBe(11); - }); - - it('should return input when cursor is at the start of input', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 0, - value, - }); - - expect(left).toBe(0); - expect(right).toBe(10); - }); - - it('should return input when cursor is at the middle of input', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 7, - value, - }); - - expect(left).toBe(0); - expect(right).toBe(10); - }); - - it('should return input when cursor is at the end of input', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 10, - value, - }); - - expect(left).toBe(0); - expect(right).toBe(10); - }); - }); - - describe('multiple words', () => { - const value = 'label:~"Community Contribution"'; - - it('should return input when cursor is after the first word', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 17, - value, - }); - - expect(left).toBe(0); - expect(right).toBe(31); - }); - - it('should return input when cursor is before the second word', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 18, - value, - }); - - expect(left).toBe(0); - expect(right).toBe(31); - }); - }); - - describe('incomplete multiple words', () => { - const value = 'label:~"Community Contribution'; - - it('should return entire input when cursor is at the start of input', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 0, - value, - }); - - expect(left).toBe(0); - expect(right).toBe(30); - }); - - it('should return entire input when cursor is at the end of input', () => { - const { left, right } = DropdownUtils.getInputSelectionPosition({ - selectionStart: 30, - value, - }); - - expect(left).toBe(0); - expect(right).toBe(30); - }); - }); - }); - - describe('getSearchQuery', () => { - let authorToken; - - beforeEach(() => { - loadFixtures(issueListFixture); - - authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '=', '@user'); - const searchTermToken = FilteredSearchSpecHelper.createSearchVisualToken('search term'); - - const tokensContainer = document.querySelector('.tokens-container'); - tokensContainer.appendChild(searchTermToken); - tokensContainer.appendChild(authorToken); - }); - - it('uses original value if present', () => { - const originalValue = 'original dance'; - const valueContainer = authorToken.querySelector('.value-container'); - valueContainer.dataset.originalValue = originalValue; - - const searchQuery = DropdownUtils.getSearchQuery(); - - expect(searchQuery).toBe(' search term author:=original dance'); - }); - }); -}); diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_manager_spec.js deleted file mode 100644 index d0b54a16747..00000000000 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js +++ /dev/null @@ -1,580 +0,0 @@ -import RecentSearchesService from '~/filtered_search/services/recent_searches_service'; -import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error'; -import RecentSearchesRoot from '~/filtered_search/recent_searches_root'; -import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; -import '~/lib/utils/common_utils'; -import DropdownUtils from '~/filtered_search/dropdown_utils'; -import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens'; -import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager'; -import FilteredSearchManager from '~/filtered_search/filtered_search_manager'; -import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper'; -import { BACKSPACE_KEY_CODE, DELETE_KEY_CODE } from '~/lib/utils/keycodes'; - -describe('Filtered Search Manager', function() { - let input; - let manager; - let tokensContainer; - const page = 'issues'; - const placeholder = 'Search or filter results...'; - - function dispatchBackspaceEvent(element, eventType) { - const event = new Event(eventType); - event.keyCode = BACKSPACE_KEY_CODE; - element.dispatchEvent(event); - } - - function dispatchDeleteEvent(element, eventType) { - const event = new Event(eventType); - event.keyCode = DELETE_KEY_CODE; - element.dispatchEvent(event); - } - - function dispatchAltBackspaceEvent(element, eventType) { - const event = new Event(eventType); - event.altKey = true; - event.keyCode = BACKSPACE_KEY_CODE; - element.dispatchEvent(event); - } - - function dispatchCtrlBackspaceEvent(element, eventType) { - const event = new Event(eventType); - event.ctrlKey = true; - event.keyCode = BACKSPACE_KEY_CODE; - element.dispatchEvent(event); - } - - function dispatchMetaBackspaceEvent(element, eventType) { - const event = new Event(eventType); - event.metaKey = true; - event.keyCode = BACKSPACE_KEY_CODE; - element.dispatchEvent(event); - } - - function getVisualTokens() { - return tokensContainer.querySelectorAll('.js-visual-token'); - } - - beforeEach(() => { - setFixtures(` - <div class="filtered-search-box"> - <form> - <ul class="tokens-container list-unstyled"> - ${FilteredSearchSpecHelper.createInputHTML(placeholder)} - </ul> - <button class="clear-search" type="button"> - <i class="fa fa-times"></i> - </button> - </form> - </div> - `); - - spyOn(FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {}); - }); - - const initializeManager = () => { - /* eslint-disable jasmine/no-unsafe-spy */ - spyOn(FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {}); - spyOn(FilteredSearchManager.prototype, 'tokenChange').and.callFake(() => {}); - spyOn(FilteredSearchDropdownManager.prototype, 'updateDropdownOffset').and.callFake(() => {}); - spyOn(gl.utils, 'getParameterByName').and.returnValue(null); - spyOn(FilteredSearchVisualTokens, 'unselectTokens').and.callThrough(); - /* eslint-enable jasmine/no-unsafe-spy */ - - input = document.querySelector('.filtered-search'); - tokensContainer = document.querySelector('.tokens-container'); - manager = new FilteredSearchManager({ page }); - manager.setup(); - }; - - afterEach(() => { - manager.cleanup(); - }); - - describe('class constructor', () => { - const isLocalStorageAvailable = 'isLocalStorageAvailable'; - let RecentSearchesStoreSpy; - - beforeEach(() => { - spyOn(RecentSearchesService, 'isAvailable').and.returnValue(isLocalStorageAvailable); - spyOn(RecentSearchesRoot.prototype, 'render'); - RecentSearchesStoreSpy = spyOnDependency(FilteredSearchManager, 'RecentSearchesStore'); - }); - - it('should instantiate RecentSearchesStore with isLocalStorageAvailable', () => { - manager = new FilteredSearchManager({ page }); - - expect(RecentSearchesService.isAvailable).toHaveBeenCalled(); - expect(RecentSearchesStoreSpy).toHaveBeenCalledWith({ - isLocalStorageAvailable, - allowedKeys: IssuableFilteredSearchTokenKeys.getKeys(), - }); - }); - }); - - describe('setup', () => { - beforeEach(() => { - manager = new FilteredSearchManager({ page }); - }); - - it('should not instantiate Flash if an RecentSearchesServiceError is caught', () => { - spyOn(RecentSearchesService.prototype, 'fetch').and.callFake(() => - Promise.reject(new RecentSearchesServiceError()), - ); - spyOn(window, 'Flash'); - - manager.setup(); - - expect(window.Flash).not.toHaveBeenCalled(); - }); - }); - - describe('searchState', () => { - beforeEach(() => { - spyOn(FilteredSearchManager.prototype, 'search').and.callFake(() => {}); - initializeManager(); - }); - - it('should blur button', () => { - const e = { - preventDefault: () => {}, - currentTarget: { - blur: () => {}, - }, - }; - spyOn(e.currentTarget, 'blur').and.callThrough(); - manager.searchState(e); - - expect(e.currentTarget.blur).toHaveBeenCalled(); - }); - - it('should not call search if there is no state', () => { - const e = { - preventDefault: () => {}, - currentTarget: { - blur: () => {}, - }, - }; - - manager.searchState(e); - - expect(FilteredSearchManager.prototype.search).not.toHaveBeenCalled(); - }); - - it('should call search when there is state', () => { - const e = { - preventDefault: () => {}, - currentTarget: { - blur: () => {}, - dataset: { - state: 'opened', - }, - }, - }; - - manager.searchState(e); - - expect(FilteredSearchManager.prototype.search).toHaveBeenCalledWith('opened'); - }); - }); - - describe('search', () => { - const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened'; - - beforeEach(() => { - initializeManager(); - }); - - it('should search with a single word', done => { - input.value = 'searchTerm'; - - spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => { - expect(url).toEqual(`${defaultParams}&search=searchTerm`); - done(); - }); - - manager.search(); - }); - - it('should search with multiple words', done => { - input.value = 'awesome search terms'; - - spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => { - expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`); - done(); - }); - - manager.search(); - }); - - it('should search with special characters', done => { - input.value = '~!@#$%^&*()_+{}:<>,.?/'; - - spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => { - expect(url).toEqual( - `${defaultParams}&search=~!%40%23%24%25%5E%26*()_%2B%7B%7D%3A%3C%3E%2C.%3F%2F`, - ); - done(); - }); - - manager.search(); - }); - - it('removes duplicated tokens', done => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(` - ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')} - ${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')} - `); - - spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => { - expect(url).toEqual(`${defaultParams}&label_name[]=bug`); - done(); - }); - - manager.search(); - }); - }); - - describe('handleInputPlaceholder', () => { - beforeEach(() => { - initializeManager(); - }); - - it('should render placeholder when there is no input', () => { - expect(input.placeholder).toEqual(placeholder); - }); - - it('should not render placeholder when there is input', () => { - input.value = 'test words'; - - const event = new Event('input'); - input.dispatchEvent(event); - - expect(input.placeholder).toEqual(''); - }); - - it('should not render placeholder when there are tokens and no input', () => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'), - ); - - const event = new Event('input'); - input.dispatchEvent(event); - - expect(input.placeholder).toEqual(''); - }); - }); - - describe('checkForBackspace', () => { - beforeEach(() => { - initializeManager(); - }); - - describe('tokens and no input', () => { - beforeEach(() => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'), - ); - }); - - it('removes last token', () => { - spyOn(FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough(); - dispatchBackspaceEvent(input, 'keyup'); - dispatchBackspaceEvent(input, 'keyup'); - - expect(FilteredSearchVisualTokens.removeLastTokenPartial).toHaveBeenCalled(); - }); - - it('sets the input', () => { - spyOn(FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough(); - dispatchDeleteEvent(input, 'keyup'); - dispatchDeleteEvent(input, 'keyup'); - - expect(FilteredSearchVisualTokens.getLastTokenPartial).toHaveBeenCalled(); - expect(input.value).toEqual('~bug'); - }); - }); - - it('does not remove token or change input when there is existing input', () => { - spyOn(FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough(); - spyOn(FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough(); - - input.value = 'text'; - dispatchDeleteEvent(input, 'keyup'); - - expect(FilteredSearchVisualTokens.removeLastTokenPartial).not.toHaveBeenCalled(); - expect(FilteredSearchVisualTokens.getLastTokenPartial).not.toHaveBeenCalled(); - expect(input.value).toEqual('text'); - }); - - it('does not remove previous token on single backspace press', () => { - spyOn(FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough(); - spyOn(FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough(); - - input.value = 't'; - dispatchDeleteEvent(input, 'keyup'); - - expect(FilteredSearchVisualTokens.removeLastTokenPartial).not.toHaveBeenCalled(); - expect(FilteredSearchVisualTokens.getLastTokenPartial).not.toHaveBeenCalled(); - expect(input.value).toEqual('t'); - }); - }); - - describe('checkForAltOrCtrlBackspace', () => { - beforeEach(() => { - initializeManager(); - spyOn(FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough(); - }); - - describe('tokens and no input', () => { - beforeEach(() => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'), - ); - }); - - it('removes last token via alt-backspace', () => { - dispatchAltBackspaceEvent(input, 'keydown'); - - expect(FilteredSearchVisualTokens.removeLastTokenPartial).toHaveBeenCalled(); - }); - - it('removes last token via ctrl-backspace', () => { - dispatchCtrlBackspaceEvent(input, 'keydown'); - - expect(FilteredSearchVisualTokens.removeLastTokenPartial).toHaveBeenCalled(); - }); - }); - - describe('tokens and input', () => { - beforeEach(() => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'), - ); - }); - - it('does not remove token or change input via alt-backspace when there is existing input', () => { - input = manager.filteredSearchInput; - input.value = 'text'; - dispatchAltBackspaceEvent(input, 'keydown'); - - expect(FilteredSearchVisualTokens.removeLastTokenPartial).not.toHaveBeenCalled(); - expect(input.value).toEqual('text'); - }); - - it('does not remove token or change input via ctrl-backspace when there is existing input', () => { - input = manager.filteredSearchInput; - input.value = 'text'; - dispatchCtrlBackspaceEvent(input, 'keydown'); - - expect(FilteredSearchVisualTokens.removeLastTokenPartial).not.toHaveBeenCalled(); - expect(input.value).toEqual('text'); - }); - }); - }); - - describe('checkForMetaBackspace', () => { - beforeEach(() => { - initializeManager(); - }); - - beforeEach(() => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'), - ); - }); - - it('removes all tokens and input', () => { - spyOn(FilteredSearchManager.prototype, 'clearSearch').and.callThrough(); - dispatchMetaBackspaceEvent(input, 'keydown'); - - expect(manager.clearSearch).toHaveBeenCalled(); - expect(manager.filteredSearchInput.value).toEqual(''); - expect(DropdownUtils.getSearchQuery()).toEqual(''); - }); - }); - - describe('removeToken', () => { - beforeEach(() => { - initializeManager(); - }); - - it('removes token even when it is already selected', () => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true), - ); - - tokensContainer.querySelector('.js-visual-token .remove-token').click(); - - expect(tokensContainer.querySelector('.js-visual-token')).toEqual(null); - }); - - describe('unselected token', () => { - beforeEach(() => { - spyOn(FilteredSearchManager.prototype, 'removeSelectedToken').and.callThrough(); - - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none'), - ); - tokensContainer.querySelector('.js-visual-token .remove-token').click(); - }); - - it('removes token when remove button is selected', () => { - expect(tokensContainer.querySelector('.js-visual-token')).toEqual(null); - }); - - it('calls removeSelectedToken', () => { - expect(manager.removeSelectedToken).toHaveBeenCalled(); - }); - }); - }); - - describe('removeSelectedTokenKeydown', () => { - beforeEach(() => { - initializeManager(); - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML( - FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true), - ); - }); - - it('removes selected token when the backspace key is pressed', () => { - expect(getVisualTokens().length).toEqual(1); - - dispatchBackspaceEvent(document, 'keydown'); - - expect(getVisualTokens().length).toEqual(0); - }); - - it('removes selected token when the delete key is pressed', () => { - expect(getVisualTokens().length).toEqual(1); - - dispatchDeleteEvent(document, 'keydown'); - - expect(getVisualTokens().length).toEqual(0); - }); - - it('updates the input placeholder after removal', () => { - manager.handleInputPlaceholder(); - - expect(input.placeholder).toEqual(''); - expect(getVisualTokens().length).toEqual(1); - - dispatchBackspaceEvent(document, 'keydown'); - - expect(input.placeholder).not.toEqual(''); - expect(getVisualTokens().length).toEqual(0); - }); - - it('updates the clear button after removal', () => { - manager.toggleClearSearchButton(); - - const clearButton = document.querySelector('.clear-search'); - - expect(clearButton.classList.contains('hidden')).toEqual(false); - expect(getVisualTokens().length).toEqual(1); - - dispatchBackspaceEvent(document, 'keydown'); - - expect(clearButton.classList.contains('hidden')).toEqual(true); - expect(getVisualTokens().length).toEqual(0); - }); - }); - - describe('removeSelectedToken', () => { - beforeEach(() => { - spyOn(FilteredSearchVisualTokens, 'removeSelectedToken').and.callThrough(); - spyOn(FilteredSearchManager.prototype, 'handleInputPlaceholder').and.callThrough(); - spyOn(FilteredSearchManager.prototype, 'toggleClearSearchButton').and.callThrough(); - initializeManager(); - }); - - it('calls FilteredSearchVisualTokens.removeSelectedToken', () => { - manager.removeSelectedToken(); - - expect(FilteredSearchVisualTokens.removeSelectedToken).toHaveBeenCalled(); - }); - - it('calls handleInputPlaceholder', () => { - manager.removeSelectedToken(); - - expect(manager.handleInputPlaceholder).toHaveBeenCalled(); - }); - - it('calls toggleClearSearchButton', () => { - manager.removeSelectedToken(); - - expect(manager.toggleClearSearchButton).toHaveBeenCalled(); - }); - - it('calls update dropdown offset', () => { - manager.removeSelectedToken(); - - expect(manager.dropdownManager.updateDropdownOffset).toHaveBeenCalled(); - }); - }); - - describe('Clearing search', () => { - beforeEach(() => { - initializeManager(); - }); - - it('Clicking the "x" clear button, clears the input', () => { - const inputValue = 'label:=~bug'; - manager.filteredSearchInput.value = inputValue; - manager.filteredSearchInput.dispatchEvent(new Event('input')); - - expect(DropdownUtils.getSearchQuery()).toEqual(inputValue); - - manager.clearSearchButton.click(); - - expect(manager.filteredSearchInput.value).toEqual(''); - expect(DropdownUtils.getSearchQuery()).toEqual(''); - }); - }); - - describe('toggleInputContainerFocus', () => { - beforeEach(() => { - initializeManager(); - }); - - it('toggles on focus', () => { - input.focus(); - - expect(document.querySelector('.filtered-search-box').classList.contains('focus')).toEqual( - true, - ); - }); - - it('toggles on blur', () => { - input.blur(); - - expect(document.querySelector('.filtered-search-box').classList.contains('focus')).toEqual( - false, - ); - }); - }); - - describe('getAllParams', () => { - beforeEach(() => { - this.paramsArr = ['key=value', 'otherkey=othervalue']; - - initializeManager(); - }); - - it('correctly modifies params when custom modifier is passed', () => { - const modifedParams = manager.getAllParams.call( - { - modifyUrlParams: paramsArr => paramsArr.reverse(), - }, - [].concat(this.paramsArr), - ); - - expect(modifedParams[0]).toBe(this.paramsArr[1]); - }); - - it('does not modify params when no custom modifier is passed', () => { - const modifedParams = manager.getAllParams.call({}, this.paramsArr); - - expect(modifedParams[1]).toBe(this.paramsArr[1]); - }); - }); -}); diff --git a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js deleted file mode 100644 index dec03e5ab93..00000000000 --- a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js +++ /dev/null @@ -1,152 +0,0 @@ -import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; -import FilteredSearchTokenizer from '~/filtered_search/filtered_search_tokenizer'; - -describe('Filtered Search Tokenizer', () => { - const allowedKeys = IssuableFilteredSearchTokenKeys.getKeys(); - - describe('processTokens', () => { - it('returns for input containing only search value', () => { - const results = FilteredSearchTokenizer.processTokens('searchTerm', allowedKeys); - - expect(results.searchToken).toBe('searchTerm'); - expect(results.tokens.length).toBe(0); - expect(results.lastToken).toBe(results.searchToken); - }); - - it('returns for input containing only tokens', () => { - const results = FilteredSearchTokenizer.processTokens( - 'author:@root label:~"Very Important" milestone:%v1.0 assignee:none', - allowedKeys, - ); - - expect(results.searchToken).toBe(''); - expect(results.tokens.length).toBe(4); - expect(results.tokens[3]).toBe(results.lastToken); - - expect(results.tokens[0].key).toBe('author'); - expect(results.tokens[0].value).toBe('root'); - expect(results.tokens[0].symbol).toBe('@'); - - expect(results.tokens[1].key).toBe('label'); - expect(results.tokens[1].value).toBe('"Very Important"'); - expect(results.tokens[1].symbol).toBe('~'); - - expect(results.tokens[2].key).toBe('milestone'); - expect(results.tokens[2].value).toBe('v1.0'); - expect(results.tokens[2].symbol).toBe('%'); - - expect(results.tokens[3].key).toBe('assignee'); - expect(results.tokens[3].value).toBe('none'); - expect(results.tokens[3].symbol).toBe(''); - }); - - it('returns for input starting with search value and ending with tokens', () => { - const results = FilteredSearchTokenizer.processTokens( - 'searchTerm anotherSearchTerm milestone:none', - allowedKeys, - ); - - expect(results.searchToken).toBe('searchTerm anotherSearchTerm'); - expect(results.tokens.length).toBe(1); - expect(results.tokens[0]).toBe(results.lastToken); - expect(results.tokens[0].key).toBe('milestone'); - expect(results.tokens[0].value).toBe('none'); - expect(results.tokens[0].symbol).toBe(''); - }); - - it('returns for input starting with tokens and ending with search value', () => { - const results = FilteredSearchTokenizer.processTokens( - 'assignee:@user searchTerm', - allowedKeys, - ); - - expect(results.searchToken).toBe('searchTerm'); - expect(results.tokens.length).toBe(1); - expect(results.tokens[0].key).toBe('assignee'); - expect(results.tokens[0].value).toBe('user'); - expect(results.tokens[0].symbol).toBe('@'); - expect(results.lastToken).toBe(results.searchToken); - }); - - it('returns for input containing search value wrapped between tokens', () => { - const results = FilteredSearchTokenizer.processTokens( - 'author:@root label:~"Won\'t fix" searchTerm anotherSearchTerm milestone:none', - allowedKeys, - ); - - expect(results.searchToken).toBe('searchTerm anotherSearchTerm'); - expect(results.tokens.length).toBe(3); - expect(results.tokens[2]).toBe(results.lastToken); - - expect(results.tokens[0].key).toBe('author'); - expect(results.tokens[0].value).toBe('root'); - expect(results.tokens[0].symbol).toBe('@'); - - expect(results.tokens[1].key).toBe('label'); - expect(results.tokens[1].value).toBe('"Won\'t fix"'); - expect(results.tokens[1].symbol).toBe('~'); - - expect(results.tokens[2].key).toBe('milestone'); - expect(results.tokens[2].value).toBe('none'); - expect(results.tokens[2].symbol).toBe(''); - }); - - it('returns for input containing search value in between tokens', () => { - const results = FilteredSearchTokenizer.processTokens( - 'author:@root searchTerm assignee:none anotherSearchTerm label:~Doing', - allowedKeys, - ); - - expect(results.searchToken).toBe('searchTerm anotherSearchTerm'); - expect(results.tokens.length).toBe(3); - expect(results.tokens[2]).toBe(results.lastToken); - - expect(results.tokens[0].key).toBe('author'); - expect(results.tokens[0].value).toBe('root'); - expect(results.tokens[0].symbol).toBe('@'); - - expect(results.tokens[1].key).toBe('assignee'); - expect(results.tokens[1].value).toBe('none'); - expect(results.tokens[1].symbol).toBe(''); - - expect(results.tokens[2].key).toBe('label'); - expect(results.tokens[2].value).toBe('Doing'); - expect(results.tokens[2].symbol).toBe('~'); - }); - - it('returns search value for invalid tokens', () => { - const results = FilteredSearchTokenizer.processTokens('fake:token', allowedKeys); - - expect(results.lastToken).toBe('fake:token'); - expect(results.searchToken).toBe('fake:token'); - expect(results.tokens.length).toEqual(0); - }); - - it('returns search value and token for mix of valid and invalid tokens', () => { - const results = FilteredSearchTokenizer.processTokens('label:real fake:token', allowedKeys); - - expect(results.tokens.length).toEqual(1); - expect(results.tokens[0].key).toBe('label'); - expect(results.tokens[0].value).toBe('real'); - expect(results.tokens[0].symbol).toBe(''); - expect(results.lastToken).toBe('fake:token'); - expect(results.searchToken).toBe('fake:token'); - }); - - it('returns search value for invalid symbols', () => { - const results = FilteredSearchTokenizer.processTokens('std::includes', allowedKeys); - - expect(results.lastToken).toBe('std::includes'); - expect(results.searchToken).toBe('std::includes'); - }); - - it('removes duplicated values', () => { - const results = FilteredSearchTokenizer.processTokens('label:~foo label:~foo', allowedKeys); - - expect(results.tokens.length).toBe(1); - expect(results.tokens[0].key).toBe('label'); - expect(results.tokens[0].value).toBe('foo'); - expect(results.tokens[0].symbol).toBe('~'); - }); - }); -}); diff --git a/spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js b/spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js deleted file mode 100644 index c7be900ba2c..00000000000 --- a/spec/javascripts/filtered_search/issues_filtered_search_token_keys_spec.js +++ /dev/null @@ -1,148 +0,0 @@ -import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; - -describe('Issues Filtered Search Token Keys', () => { - describe('get', () => { - let tokenKeys; - - beforeEach(() => { - tokenKeys = IssuableFilteredSearchTokenKeys.get(); - }); - - it('should return tokenKeys', () => { - expect(tokenKeys).not.toBeNull(); - }); - - it('should return tokenKeys as an array', () => { - expect(tokenKeys instanceof Array).toBe(true); - }); - - it('should always return the same array', () => { - const tokenKeys2 = IssuableFilteredSearchTokenKeys.get(); - - expect(tokenKeys).toEqual(tokenKeys2); - }); - - it('should return assignee as a string', () => { - const assignee = tokenKeys.find(tokenKey => tokenKey.key === 'assignee'); - - expect(assignee.type).toEqual('string'); - }); - }); - - describe('getKeys', () => { - it('should return keys', () => { - const getKeys = IssuableFilteredSearchTokenKeys.getKeys(); - const keys = IssuableFilteredSearchTokenKeys.get().map(i => i.key); - - keys.forEach((key, i) => { - expect(key).toEqual(getKeys[i]); - }); - }); - }); - - describe('getConditions', () => { - let conditions; - - beforeEach(() => { - conditions = IssuableFilteredSearchTokenKeys.getConditions(); - }); - - it('should return conditions', () => { - expect(conditions).not.toBeNull(); - }); - - it('should return conditions as an array', () => { - expect(conditions instanceof Array).toBe(true); - }); - }); - - describe('searchByKey', () => { - it('should return null when key not found', () => { - const tokenKey = IssuableFilteredSearchTokenKeys.searchByKey('notakey'); - - expect(tokenKey).toBeNull(); - }); - - it('should return tokenKey when found by key', () => { - const tokenKeys = IssuableFilteredSearchTokenKeys.get(); - const result = IssuableFilteredSearchTokenKeys.searchByKey(tokenKeys[0].key); - - expect(result).toEqual(tokenKeys[0]); - }); - }); - - describe('searchBySymbol', () => { - it('should return null when symbol not found', () => { - const tokenKey = IssuableFilteredSearchTokenKeys.searchBySymbol('notasymbol'); - - expect(tokenKey).toBeNull(); - }); - - it('should return tokenKey when found by symbol', () => { - const tokenKeys = IssuableFilteredSearchTokenKeys.get(); - const result = IssuableFilteredSearchTokenKeys.searchBySymbol(tokenKeys[0].symbol); - - expect(result).toEqual(tokenKeys[0]); - }); - }); - - describe('searchByKeyParam', () => { - it('should return null when key param not found', () => { - const tokenKey = IssuableFilteredSearchTokenKeys.searchByKeyParam('notakeyparam'); - - expect(tokenKey).toBeNull(); - }); - - it('should return tokenKey when found by key param', () => { - const tokenKeys = IssuableFilteredSearchTokenKeys.get(); - const result = IssuableFilteredSearchTokenKeys.searchByKeyParam( - `${tokenKeys[0].key}_${tokenKeys[0].param}`, - ); - - expect(result).toEqual(tokenKeys[0]); - }); - - it('should return alternative tokenKey when found by key param', () => { - const tokenKeys = IssuableFilteredSearchTokenKeys.getAlternatives(); - const result = IssuableFilteredSearchTokenKeys.searchByKeyParam( - `${tokenKeys[0].key}_${tokenKeys[0].param}`, - ); - - expect(result).toEqual(tokenKeys[0]); - }); - }); - - describe('searchByConditionUrl', () => { - it('should return null when condition url not found', () => { - const condition = IssuableFilteredSearchTokenKeys.searchByConditionUrl(null); - - expect(condition).toBeNull(); - }); - - it('should return condition when found by url', () => { - const conditions = IssuableFilteredSearchTokenKeys.getConditions(); - const result = IssuableFilteredSearchTokenKeys.searchByConditionUrl(conditions[0].url); - - expect(result).toBe(conditions[0]); - }); - }); - - describe('searchByConditionKeyValue', () => { - it('should return null when condition tokenKey and value not found', () => { - const condition = IssuableFilteredSearchTokenKeys.searchByConditionKeyValue(null, null); - - expect(condition).toBeNull(); - }); - - it('should return condition when found by tokenKey and value', () => { - const conditions = IssuableFilteredSearchTokenKeys.getConditions(); - const result = IssuableFilteredSearchTokenKeys.searchByConditionKeyValue( - conditions[0].tokenKey, - conditions[0].operator, - conditions[0].value, - ); - - expect(result).toEqual(conditions[0]); - }); - }); -}); diff --git a/spec/javascripts/filtered_search/recent_searches_root_spec.js b/spec/javascripts/filtered_search/recent_searches_root_spec.js deleted file mode 100644 index 70dd4e9570d..00000000000 --- a/spec/javascripts/filtered_search/recent_searches_root_spec.js +++ /dev/null @@ -1,30 +0,0 @@ -import RecentSearchesRoot from '~/filtered_search/recent_searches_root'; - -describe('RecentSearchesRoot', () => { - describe('render', () => { - let recentSearchesRoot; - let data; - let template; - let VueSpy; - - beforeEach(() => { - recentSearchesRoot = { - store: { - state: 'state', - }, - }; - - VueSpy = spyOnDependency(RecentSearchesRoot, 'Vue').and.callFake(options => { - ({ data, template } = options); - }); - - RecentSearchesRoot.prototype.render.call(recentSearchesRoot); - }); - - it('should instantiate Vue', () => { - expect(VueSpy).toHaveBeenCalled(); - expect(data()).toBe(recentSearchesRoot.store.state); - expect(template).toContain(':is-local-storage-available="isLocalStorageAvailable"'); - }); - }); -}); diff --git a/spec/javascripts/filtered_search/services/recent_searches_service_spec.js b/spec/javascripts/filtered_search/services/recent_searches_service_spec.js deleted file mode 100644 index 188f83eca16..00000000000 --- a/spec/javascripts/filtered_search/services/recent_searches_service_spec.js +++ /dev/null @@ -1,158 +0,0 @@ -import RecentSearchesService from '~/filtered_search/services/recent_searches_service'; -import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error'; -import AccessorUtilities from '~/lib/utils/accessor'; - -describe('RecentSearchesService', () => { - let service; - - beforeEach(() => { - service = new RecentSearchesService(); - window.localStorage.removeItem(service.localStorageKey); - }); - - describe('fetch', () => { - beforeEach(() => { - spyOn(RecentSearchesService, 'isAvailable').and.returnValue(true); - }); - - it('should default to empty array', done => { - const fetchItemsPromise = service.fetch(); - - fetchItemsPromise - .then(items => { - expect(items).toEqual([]); - }) - .then(done) - .catch(done.fail); - }); - - it('should reject when unable to parse', done => { - window.localStorage.setItem(service.localStorageKey, 'fail'); - const fetchItemsPromise = service.fetch(); - - fetchItemsPromise - .then(done.fail) - .catch(error => { - expect(error).toEqual(jasmine.any(SyntaxError)); - }) - .then(done) - .catch(done.fail); - }); - - it('should reject when service is unavailable', done => { - RecentSearchesService.isAvailable.and.returnValue(false); - - service - .fetch() - .then(done.fail) - .catch(error => { - expect(error).toEqual(jasmine.any(Error)); - }) - .then(done) - .catch(done.fail); - }); - - it('should return items from localStorage', done => { - window.localStorage.setItem(service.localStorageKey, '["foo", "bar"]'); - const fetchItemsPromise = service.fetch(); - - fetchItemsPromise - .then(items => { - expect(items).toEqual(['foo', 'bar']); - }) - .then(done) - .catch(done.fail); - }); - - describe('if .isAvailable returns `false`', () => { - beforeEach(() => { - RecentSearchesService.isAvailable.and.returnValue(false); - - spyOn(window.localStorage, 'getItem'); - }); - - it('should not call .getItem', done => { - RecentSearchesService.prototype - .fetch() - .then(done.fail) - .catch(err => { - expect(err).toEqual(new RecentSearchesServiceError()); - expect(window.localStorage.getItem).not.toHaveBeenCalled(); - }) - .then(done) - .catch(done.fail); - }); - }); - }); - - describe('setRecentSearches', () => { - beforeEach(() => { - spyOn(RecentSearchesService, 'isAvailable').and.returnValue(true); - }); - - it('should save things in localStorage', () => { - const items = ['foo', 'bar']; - service.save(items); - const newLocalStorageValue = window.localStorage.getItem(service.localStorageKey); - - expect(JSON.parse(newLocalStorageValue)).toEqual(items); - }); - }); - - describe('save', () => { - beforeEach(() => { - spyOn(window.localStorage, 'setItem'); - spyOn(RecentSearchesService, 'isAvailable'); - }); - - describe('if .isAvailable returns `true`', () => { - const searchesString = 'searchesString'; - const localStorageKey = 'localStorageKey'; - const recentSearchesService = { - localStorageKey, - }; - - beforeEach(() => { - RecentSearchesService.isAvailable.and.returnValue(true); - - spyOn(JSON, 'stringify').and.returnValue(searchesString); - }); - - it('should call .setItem', () => { - RecentSearchesService.prototype.save.call(recentSearchesService); - - expect(window.localStorage.setItem).toHaveBeenCalledWith(localStorageKey, searchesString); - }); - }); - - describe('if .isAvailable returns `false`', () => { - beforeEach(() => { - RecentSearchesService.isAvailable.and.returnValue(false); - }); - - it('should not call .setItem', () => { - RecentSearchesService.prototype.save(); - - expect(window.localStorage.setItem).not.toHaveBeenCalled(); - }); - }); - }); - - describe('isAvailable', () => { - let isAvailable; - - beforeEach(() => { - spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.callThrough(); - - isAvailable = RecentSearchesService.isAvailable(); - }); - - it('should call .isLocalStorageAccessSafe', () => { - expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled(); - }); - - it('should return a boolean', () => { - expect(typeof isAvailable).toBe('boolean'); - }); - }); -}); diff --git a/spec/javascripts/filtered_search/visual_token_value_spec.js b/spec/javascripts/filtered_search/visual_token_value_spec.js deleted file mode 100644 index 4469ade1874..00000000000 --- a/spec/javascripts/filtered_search/visual_token_value_spec.js +++ /dev/null @@ -1,389 +0,0 @@ -import { escape as esc } from 'lodash'; -import VisualTokenValue from '~/filtered_search/visual_token_value'; -import AjaxCache from '~/lib/utils/ajax_cache'; -import UsersCache from '~/lib/utils/users_cache'; -import DropdownUtils from '~/filtered_search//dropdown_utils'; -import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper'; - -describe('Filtered Search Visual Tokens', () => { - const findElements = tokenElement => { - const tokenNameElement = tokenElement.querySelector('.name'); - const tokenValueContainer = tokenElement.querySelector('.value-container'); - const tokenValueElement = tokenValueContainer.querySelector('.value'); - const tokenOperatorElement = tokenElement.querySelector('.operator'); - const tokenType = tokenNameElement.innerText.toLowerCase(); - const tokenValue = tokenValueElement.innerText; - const tokenOperator = tokenOperatorElement.innerText; - const subject = new VisualTokenValue(tokenValue, tokenType, tokenOperator); - return { subject, tokenValueContainer, tokenValueElement }; - }; - - let tokensContainer; - let authorToken; - let bugLabelToken; - - beforeEach(() => { - setFixtures(` - <ul class="tokens-container"> - ${FilteredSearchSpecHelper.createInputHTML()} - </ul> - `); - tokensContainer = document.querySelector('.tokens-container'); - - authorToken = FilteredSearchSpecHelper.createFilterVisualToken('author', '=', '@user'); - bugLabelToken = FilteredSearchSpecHelper.createFilterVisualToken('label', '=', '~bug'); - }); - - describe('updateUserTokenAppearance', () => { - let usersCacheSpy; - - beforeEach(() => { - spyOn(UsersCache, 'retrieve').and.callFake(username => usersCacheSpy(username)); - }); - - it('ignores error if UsersCache throws', done => { - spyOn(window, 'Flash'); - const dummyError = new Error('Earth rotated backwards'); - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - const tokenValue = tokenValueElement.innerText; - usersCacheSpy = username => { - expect(`@${username}`).toBe(tokenValue); - return Promise.reject(dummyError); - }; - - subject - .updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue) - .then(() => { - expect(window.Flash.calls.count()).toBe(0); - }) - .then(done) - .catch(done.fail); - }); - - it('does nothing if user cannot be found', done => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - const tokenValue = tokenValueElement.innerText; - usersCacheSpy = username => { - expect(`@${username}`).toBe(tokenValue); - return Promise.resolve(undefined); - }; - - subject - .updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue) - .then(() => { - expect(tokenValueElement.innerText).toBe(tokenValue); - }) - .then(done) - .catch(done.fail); - }); - - it('replaces author token with avatar and display name', done => { - const dummyUser = { - name: 'Important Person', - avatar_url: 'https://host.invalid/mypics/avatar.png', - }; - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - const tokenValue = tokenValueElement.innerText; - usersCacheSpy = username => { - expect(`@${username}`).toBe(tokenValue); - return Promise.resolve(dummyUser); - }; - - subject - .updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue) - .then(() => { - expect(tokenValueContainer.dataset.originalValue).toBe(tokenValue); - expect(tokenValueElement.innerText.trim()).toBe(dummyUser.name); - const avatar = tokenValueElement.querySelector('img.avatar'); - - expect(avatar.src).toBe(dummyUser.avatar_url); - expect(avatar.alt).toBe(''); - }) - .then(done) - .catch(done.fail); - }); - - it('escapes user name when creating token', done => { - const dummyUser = { - name: '<script>', - avatar_url: `${gl.TEST_HOST}/mypics/avatar.png`, - }; - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - const tokenValue = tokenValueElement.innerText; - usersCacheSpy = username => { - expect(`@${username}`).toBe(tokenValue); - return Promise.resolve(dummyUser); - }; - - subject - .updateUserTokenAppearance(tokenValueContainer, tokenValueElement, tokenValue) - .then(() => { - expect(tokenValueElement.innerText.trim()).toBe(dummyUser.name); - tokenValueElement.querySelector('.avatar').remove(); - - expect(tokenValueElement.innerHTML.trim()).toBe(esc(dummyUser.name)); - }) - .then(done) - .catch(done.fail); - }); - }); - - describe('updateLabelTokenColor', () => { - const jsonFixtureName = 'labels/project_labels.json'; - const dummyEndpoint = '/dummy/endpoint'; - - preloadFixtures(jsonFixtureName); - - let labelData; - - beforeAll(() => { - labelData = getJSONFixture(jsonFixtureName); - }); - - const missingLabelToken = FilteredSearchSpecHelper.createFilterVisualToken( - 'label', - '=', - '~doesnotexist', - ); - const spaceLabelToken = FilteredSearchSpecHelper.createFilterVisualToken( - 'label', - '=', - '~"some space"', - ); - - beforeEach(() => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(` - ${bugLabelToken.outerHTML} - ${missingLabelToken.outerHTML} - ${spaceLabelToken.outerHTML} - `); - - const filteredSearchInput = document.querySelector('.filtered-search'); - filteredSearchInput.dataset.runnerTagsEndpoint = `${dummyEndpoint}/admin/runners/tag_list`; - filteredSearchInput.dataset.labelsEndpoint = `${dummyEndpoint}/-/labels`; - filteredSearchInput.dataset.milestonesEndpoint = `${dummyEndpoint}/-/milestones`; - - AjaxCache.internalStorage = {}; - AjaxCache.internalStorage[`${filteredSearchInput.dataset.labelsEndpoint}.json`] = labelData; - }); - - const parseColor = color => { - const dummyElement = document.createElement('div'); - dummyElement.style.color = color; - return dummyElement.style.color; - }; - - const expectValueContainerStyle = (tokenValueContainer, label) => { - expect(tokenValueContainer.getAttribute('style')).not.toBe(null); - expect(tokenValueContainer.style.backgroundColor).toBe(parseColor(label.color)); - expect(tokenValueContainer.style.color).toBe(parseColor(label.text_color)); - }; - - const findLabel = tokenValue => - labelData.find(label => tokenValue === `~${DropdownUtils.getEscapedText(label.title)}`); - - it('updates the color of a label token', done => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(bugLabelToken); - const tokenValue = tokenValueElement.innerText; - const matchingLabel = findLabel(tokenValue); - - subject - .updateLabelTokenColor(tokenValueContainer, tokenValue) - .then(() => { - expectValueContainerStyle(tokenValueContainer, matchingLabel); - }) - .then(done) - .catch(done.fail); - }); - - it('updates the color of a label token with spaces', done => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(spaceLabelToken); - const tokenValue = tokenValueElement.innerText; - const matchingLabel = findLabel(tokenValue); - - subject - .updateLabelTokenColor(tokenValueContainer, tokenValue) - .then(() => { - expectValueContainerStyle(tokenValueContainer, matchingLabel); - }) - .then(done) - .catch(done.fail); - }); - - it('does not change color of a missing label', done => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(missingLabelToken); - const tokenValue = tokenValueElement.innerText; - const matchingLabel = findLabel(tokenValue); - - expect(matchingLabel).toBe(undefined); - - subject - .updateLabelTokenColor(tokenValueContainer, tokenValue) - .then(() => { - expect(tokenValueContainer.getAttribute('style')).toBe(null); - }) - .then(done) - .catch(done.fail); - }); - }); - - describe('setTokenStyle', () => { - let originalTextColor; - - beforeEach(() => { - originalTextColor = bugLabelToken.style.color; - }); - - it('should set backgroundColor', () => { - const originalBackgroundColor = bugLabelToken.style.backgroundColor; - const token = VisualTokenValue.setTokenStyle(bugLabelToken, 'blue', 'white'); - - expect(token.style.backgroundColor).toEqual('blue'); - expect(token.style.backgroundColor).not.toEqual(originalBackgroundColor); - }); - - it('should set textColor', () => { - const token = VisualTokenValue.setTokenStyle(bugLabelToken, 'white', 'black'); - - expect(token.style.color).toEqual('black'); - expect(token.style.color).not.toEqual(originalTextColor); - }); - - it('should add inverted class when textColor is #FFFFFF', () => { - const token = VisualTokenValue.setTokenStyle(bugLabelToken, 'black', '#FFFFFF'); - - expect(token.style.color).toEqual('rgb(255, 255, 255)'); - expect(token.style.color).not.toEqual(originalTextColor); - expect(token.querySelector('.remove-token').classList.contains('inverted')).toEqual(true); - }); - }); - - describe('render', () => { - const setupSpies = subject => { - spyOn(subject, 'updateLabelTokenColor'); // eslint-disable-line jasmine/no-unsafe-spy - const updateLabelTokenColorSpy = subject.updateLabelTokenColor; - - spyOn(subject, 'updateUserTokenAppearance'); // eslint-disable-line jasmine/no-unsafe-spy - const updateUserTokenAppearanceSpy = subject.updateUserTokenAppearance; - - return { updateLabelTokenColorSpy, updateUserTokenAppearanceSpy }; - }; - - const keywordToken = FilteredSearchSpecHelper.createFilterVisualToken('search'); - const milestoneToken = FilteredSearchSpecHelper.createFilterVisualToken( - 'milestone', - 'upcoming', - ); - - beforeEach(() => { - tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(` - ${authorToken.outerHTML} - ${bugLabelToken.outerHTML} - ${keywordToken.outerHTML} - ${milestoneToken.outerHTML} - `); - }); - - it('renders a author token value element', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - - const { updateLabelTokenColorSpy, updateUserTokenAppearanceSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateUserTokenAppearanceSpy.calls.count()).toBe(1); - const expectedArgs = [tokenValueContainer, tokenValueElement]; - - expect(updateUserTokenAppearanceSpy.calls.argsFor(0)).toEqual(expectedArgs); - expect(updateLabelTokenColorSpy.calls.count()).toBe(0); - }); - - it('renders a label token value element', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(bugLabelToken); - - const { updateLabelTokenColorSpy, updateUserTokenAppearanceSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateLabelTokenColorSpy.calls.count()).toBe(1); - const expectedArgs = [tokenValueContainer]; - - expect(updateLabelTokenColorSpy.calls.argsFor(0)).toEqual(expectedArgs); - expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); - }); - - it('renders a milestone token value element', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(milestoneToken); - - const { updateLabelTokenColorSpy, updateUserTokenAppearanceSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateLabelTokenColorSpy.calls.count()).toBe(0); - expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); - }); - - it('does not update user token appearance for `none` filter', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - - subject.tokenValue = 'none'; - - const { updateUserTokenAppearanceSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); - }); - - it('does not update user token appearance for `None` filter', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - - subject.tokenValue = 'None'; - - const { updateUserTokenAppearanceSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); - }); - - it('does not update user token appearance for `any` filter', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(authorToken); - - subject.tokenValue = 'any'; - - const { updateUserTokenAppearanceSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateUserTokenAppearanceSpy.calls.count()).toBe(0); - }); - - it('does not update label token color for `None` filter', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(bugLabelToken); - - subject.tokenValue = 'None'; - - const { updateLabelTokenColorSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateLabelTokenColorSpy.calls.count()).toBe(0); - }); - - it('does not update label token color for `none` filter', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(bugLabelToken); - - subject.tokenValue = 'none'; - - const { updateLabelTokenColorSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateLabelTokenColorSpy.calls.count()).toBe(0); - }); - - it('does not update label token color for `any` filter', () => { - const { subject, tokenValueContainer, tokenValueElement } = findElements(bugLabelToken); - - subject.tokenValue = 'any'; - - const { updateLabelTokenColorSpy } = setupSpies(subject); - subject.render(tokenValueContainer, tokenValueElement); - - expect(updateLabelTokenColorSpy.calls.count()).toBe(0); - }); - }); -}); |