2017-05-05 17:59:41 +00:00
|
|
|
import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
|
|
|
|
import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error';
|
2017-06-20 08:05:55 +00:00
|
|
|
import RecentSearchesRoot from '~/filtered_search/recent_searches_root';
|
2018-08-29 12:14:54 +00:00
|
|
|
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
|
2017-05-16 21:01:51 +00:00
|
|
|
import '~/lib/utils/common_utils';
|
2018-02-21 20:22:56 +00:00
|
|
|
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';
|
2017-05-16 21:01:51 +00:00
|
|
|
import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper';
|
2020-04-15 18:09:36 +00:00
|
|
|
import { BACKSPACE_KEY_CODE, DELETE_KEY_CODE } from '~/lib/utils/keycodes';
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
describe('Filtered Search Manager', function() {
|
2017-04-17 07:01:11 +00:00
|
|
|
let input;
|
|
|
|
let manager;
|
|
|
|
let tokensContainer;
|
2018-02-04 19:26:13 +00:00
|
|
|
const page = 'issues';
|
2017-04-17 07:01:11 +00:00
|
|
|
const placeholder = 'Search or filter results...';
|
|
|
|
|
|
|
|
function dispatchBackspaceEvent(element, eventType) {
|
|
|
|
const event = new Event(eventType);
|
2020-04-15 18:09:36 +00:00
|
|
|
event.keyCode = BACKSPACE_KEY_CODE;
|
2017-04-17 07:01:11 +00:00
|
|
|
element.dispatchEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
function dispatchDeleteEvent(element, eventType) {
|
|
|
|
const event = new Event(eventType);
|
2020-04-15 18:09:36 +00:00
|
|
|
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;
|
2017-04-17 07:01:11 +00:00
|
|
|
element.dispatchEvent(event);
|
|
|
|
}
|
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
function getVisualTokens() {
|
|
|
|
return tokensContainer.querySelectorAll('.js-visual-token');
|
|
|
|
}
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
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>
|
|
|
|
`);
|
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {});
|
2017-06-23 09:28:19 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
const initializeManager = () => {
|
|
|
|
/* eslint-disable jasmine/no-unsafe-spy */
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {});
|
|
|
|
spyOn(FilteredSearchManager.prototype, 'tokenChange').and.callFake(() => {});
|
|
|
|
spyOn(FilteredSearchDropdownManager.prototype, 'updateDropdownOffset').and.callFake(() => {});
|
2017-04-17 07:01:11 +00:00
|
|
|
spyOn(gl.utils, 'getParameterByName').and.returnValue(null);
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchVisualTokens, 'unselectTokens').and.callThrough();
|
2017-06-23 09:28:19 +00:00
|
|
|
/* eslint-enable jasmine/no-unsafe-spy */
|
2017-04-17 07:01:11 +00:00
|
|
|
|
|
|
|
input = document.querySelector('.filtered-search');
|
|
|
|
tokensContainer = document.querySelector('.tokens-container');
|
2018-02-21 20:22:56 +00:00
|
|
|
manager = new FilteredSearchManager({ page });
|
2017-05-22 19:58:23 +00:00
|
|
|
manager.setup();
|
2017-06-23 09:28:19 +00:00
|
|
|
};
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
afterEach(() => {
|
|
|
|
manager.cleanup();
|
|
|
|
});
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2017-05-05 17:59:41 +00:00
|
|
|
describe('class constructor', () => {
|
|
|
|
const isLocalStorageAvailable = 'isLocalStorageAvailable';
|
2018-04-13 22:19:24 +00:00
|
|
|
let RecentSearchesStoreSpy;
|
2017-05-05 17:59:41 +00:00
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
spyOn(RecentSearchesService, 'isAvailable').and.returnValue(isLocalStorageAvailable);
|
2017-06-20 08:05:55 +00:00
|
|
|
spyOn(RecentSearchesRoot.prototype, 'render');
|
2018-04-13 22:19:24 +00:00
|
|
|
RecentSearchesStoreSpy = spyOnDependency(FilteredSearchManager, 'RecentSearchesStore');
|
2017-05-05 17:59:41 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should instantiate RecentSearchesStore with isLocalStorageAvailable', () => {
|
2018-02-21 20:22:56 +00:00
|
|
|
manager = new FilteredSearchManager({ page });
|
2017-06-23 09:28:19 +00:00
|
|
|
|
2017-05-05 17:59:41 +00:00
|
|
|
expect(RecentSearchesService.isAvailable).toHaveBeenCalled();
|
2018-04-13 22:19:24 +00:00
|
|
|
expect(RecentSearchesStoreSpy).toHaveBeenCalledWith({
|
2017-05-05 17:59:41 +00:00
|
|
|
isLocalStorageAvailable,
|
2018-08-29 12:14:54 +00:00
|
|
|
allowedKeys: IssuableFilteredSearchTokenKeys.getKeys(),
|
2017-05-05 17:59:41 +00:00
|
|
|
});
|
|
|
|
});
|
2017-06-23 09:28:19 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('setup', () => {
|
|
|
|
beforeEach(() => {
|
2018-02-21 20:22:56 +00:00
|
|
|
manager = new FilteredSearchManager({ page });
|
2017-06-23 09:28:19 +00:00
|
|
|
});
|
2017-05-05 17:59:41 +00:00
|
|
|
|
|
|
|
it('should not instantiate Flash if an RecentSearchesServiceError is caught', () => {
|
2018-10-17 07:13:26 +00:00
|
|
|
spyOn(RecentSearchesService.prototype, 'fetch').and.callFake(() =>
|
|
|
|
Promise.reject(new RecentSearchesServiceError()),
|
|
|
|
);
|
2017-05-05 17:59:41 +00:00
|
|
|
spyOn(window, 'Flash');
|
|
|
|
|
2017-06-23 09:28:19 +00:00
|
|
|
manager.setup();
|
2017-05-05 17:59:41 +00:00
|
|
|
|
|
|
|
expect(window.Flash).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-06-06 23:18:31 +00:00
|
|
|
describe('searchState', () => {
|
|
|
|
beforeEach(() => {
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchManager.prototype, 'search').and.callFake(() => {});
|
2017-06-23 09:28:19 +00:00
|
|
|
initializeManager();
|
2017-06-06 23:18:31 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should blur button', () => {
|
|
|
|
const e = {
|
2017-06-19 18:59:17 +00:00
|
|
|
preventDefault: () => {},
|
2017-06-06 23:18:31 +00:00
|
|
|
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 = {
|
2017-06-19 18:59:17 +00:00
|
|
|
preventDefault: () => {},
|
2017-06-06 23:18:31 +00:00
|
|
|
currentTarget: {
|
|
|
|
blur: () => {},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
manager.searchState(e);
|
2018-10-09 18:03:09 +00:00
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(FilteredSearchManager.prototype.search).not.toHaveBeenCalled();
|
2017-06-06 23:18:31 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should call search when there is state', () => {
|
|
|
|
const e = {
|
2017-06-19 18:59:17 +00:00
|
|
|
preventDefault: () => {},
|
2017-06-06 23:18:31 +00:00
|
|
|
currentTarget: {
|
|
|
|
blur: () => {},
|
2017-06-07 15:54:54 +00:00
|
|
|
dataset: {
|
|
|
|
state: 'opened',
|
|
|
|
},
|
2017-06-06 23:18:31 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
manager.searchState(e);
|
2018-10-09 18:03:09 +00:00
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(FilteredSearchManager.prototype.search).toHaveBeenCalledWith('opened');
|
2017-06-06 23:18:31 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
describe('search', () => {
|
|
|
|
const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened';
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2017-06-23 09:28:19 +00:00
|
|
|
beforeEach(() => {
|
|
|
|
initializeManager();
|
|
|
|
});
|
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
it('should search with a single word', done => {
|
2017-04-17 07:01:11 +00:00
|
|
|
input.value = 'searchTerm';
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => {
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(url).toEqual(`${defaultParams}&search=searchTerm`);
|
|
|
|
done();
|
|
|
|
});
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
manager.search();
|
2017-03-13 21:48:32 +00:00
|
|
|
});
|
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
it('should search with multiple words', done => {
|
2017-04-17 07:01:11 +00:00
|
|
|
input.value = 'awesome search terms';
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => {
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`);
|
|
|
|
done();
|
2017-01-24 17:57:39 +00:00
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
manager.search();
|
|
|
|
});
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
it('should search with special characters', done => {
|
2017-04-17 07:01:11 +00:00
|
|
|
input.value = '~!@#$%^&*()_+{}:<>,.?/';
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
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`,
|
|
|
|
);
|
2017-04-17 07:01:11 +00:00
|
|
|
done();
|
2017-01-24 17:57:39 +00:00
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
manager.search();
|
|
|
|
});
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
it('removes duplicated tokens', done => {
|
2017-04-17 07:01:11 +00:00
|
|
|
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
|
2020-01-02 13:03:23 +00:00
|
|
|
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
|
|
|
|
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
|
2017-04-17 07:01:11 +00:00
|
|
|
`);
|
2017-01-24 17:57:39 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
spyOnDependency(FilteredSearchManager, 'visitUrl').and.callFake(url => {
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(url).toEqual(`${defaultParams}&label_name[]=bug`);
|
|
|
|
done();
|
2017-01-24 17:57:39 +00:00
|
|
|
});
|
2017-03-28 23:34:39 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
manager.search();
|
|
|
|
});
|
|
|
|
});
|
2017-03-28 23:34:39 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
describe('handleInputPlaceholder', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
beforeEach(() => {
|
|
|
|
initializeManager();
|
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('should render placeholder when there is no input', () => {
|
|
|
|
expect(input.placeholder).toEqual(placeholder);
|
2017-01-24 17:57:39 +00:00
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('should not render placeholder when there is input', () => {
|
|
|
|
input.value = 'test words';
|
|
|
|
|
|
|
|
const event = new Event('input');
|
|
|
|
input.dispatchEvent(event);
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(input.placeholder).toEqual('');
|
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('should not render placeholder when there are tokens and no input', () => {
|
|
|
|
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
|
2020-01-02 13:03:23 +00:00
|
|
|
FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'),
|
2017-04-17 07:01:11 +00:00
|
|
|
);
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
const event = new Event('input');
|
|
|
|
input.dispatchEvent(event);
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(input.placeholder).toEqual('');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('checkForBackspace', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
beforeEach(() => {
|
|
|
|
initializeManager();
|
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
describe('tokens and no input', () => {
|
|
|
|
beforeEach(() => {
|
2017-01-30 22:53:18 +00:00
|
|
|
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
|
2020-01-02 13:03:23 +00:00
|
|
|
FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug'),
|
2017-01-30 22:53:18 +00:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('removes last token', () => {
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough();
|
2017-04-17 07:01:11 +00:00
|
|
|
dispatchBackspaceEvent(input, 'keyup');
|
2018-01-02 13:12:54 +00:00
|
|
|
dispatchBackspaceEvent(input, 'keyup');
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(FilteredSearchVisualTokens.removeLastTokenPartial).toHaveBeenCalled();
|
2017-01-30 22:53:18 +00:00
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('sets the input', () => {
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough();
|
2017-01-30 22:53:18 +00:00
|
|
|
dispatchDeleteEvent(input, 'keyup');
|
2018-01-02 13:12:54 +00:00
|
|
|
dispatchDeleteEvent(input, 'keyup');
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(FilteredSearchVisualTokens.getLastTokenPartial).toHaveBeenCalled();
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(input.value).toEqual('~bug');
|
2017-01-30 22:53:18 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('does not remove token or change input when there is existing input', () => {
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough();
|
|
|
|
spyOn(FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough();
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
input.value = 'text';
|
|
|
|
dispatchDeleteEvent(input, 'keyup');
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(FilteredSearchVisualTokens.removeLastTokenPartial).not.toHaveBeenCalled();
|
|
|
|
expect(FilteredSearchVisualTokens.getLastTokenPartial).not.toHaveBeenCalled();
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(input.value).toEqual('text');
|
|
|
|
});
|
2018-01-02 13:12:54 +00:00
|
|
|
|
|
|
|
it('does not remove previous token on single backspace press', () => {
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchVisualTokens, 'removeLastTokenPartial').and.callThrough();
|
|
|
|
spyOn(FilteredSearchVisualTokens, 'getLastTokenPartial').and.callThrough();
|
2018-01-02 13:12:54 +00:00
|
|
|
|
|
|
|
input.value = 't';
|
|
|
|
dispatchDeleteEvent(input, 'keyup');
|
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(FilteredSearchVisualTokens.removeLastTokenPartial).not.toHaveBeenCalled();
|
|
|
|
expect(FilteredSearchVisualTokens.getLastTokenPartial).not.toHaveBeenCalled();
|
2018-01-02 13:12:54 +00:00
|
|
|
expect(input.value).toEqual('t');
|
|
|
|
});
|
2017-04-17 07:01:11 +00:00
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2020-04-15 18:09:36 +00:00
|
|
|
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('');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
describe('removeToken', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
beforeEach(() => {
|
|
|
|
initializeManager();
|
|
|
|
});
|
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
it('removes token even when it is already selected', () => {
|
|
|
|
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
|
2020-01-02 13:03:23 +00:00
|
|
|
FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true),
|
2017-04-26 20:12:33 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
tokensContainer.querySelector('.js-visual-token .remove-token').click();
|
2018-10-09 18:03:09 +00:00
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
expect(tokensContainer.querySelector('.js-visual-token')).toEqual(null);
|
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
describe('unselected token', () => {
|
|
|
|
beforeEach(() => {
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchManager.prototype, 'removeSelectedToken').and.callThrough();
|
2017-04-26 20:12:33 +00:00
|
|
|
|
|
|
|
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
|
2020-01-02 13:03:23 +00:00
|
|
|
FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none'),
|
2017-04-26 20:12:33 +00:00
|
|
|
);
|
|
|
|
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', () => {
|
2017-04-17 07:01:11 +00:00
|
|
|
beforeEach(() => {
|
2017-06-23 09:28:19 +00:00
|
|
|
initializeManager();
|
2017-04-17 07:01:11 +00:00
|
|
|
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
|
2020-01-02 13:03:23 +00:00
|
|
|
FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', 'none', true),
|
2017-04-17 07:01:11 +00:00
|
|
|
);
|
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('removes selected token when the backspace key is pressed', () => {
|
|
|
|
expect(getVisualTokens().length).toEqual(1);
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
dispatchBackspaceEvent(document, 'keydown');
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(getVisualTokens().length).toEqual(0);
|
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('removes selected token when the delete key is pressed', () => {
|
|
|
|
expect(getVisualTokens().length).toEqual(1);
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
dispatchDeleteEvent(document, 'keydown');
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(getVisualTokens().length).toEqual(0);
|
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('updates the input placeholder after removal', () => {
|
|
|
|
manager.handleInputPlaceholder();
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(input.placeholder).toEqual('');
|
|
|
|
expect(getVisualTokens().length).toEqual(1);
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
dispatchBackspaceEvent(document, 'keydown');
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
expect(input.placeholder).not.toEqual('');
|
|
|
|
expect(getVisualTokens().length).toEqual(0);
|
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('updates the clear button after removal', () => {
|
|
|
|
manager.toggleClearSearchButton();
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
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);
|
2017-01-30 22:53:18 +00:00
|
|
|
});
|
2017-04-17 07:01:11 +00:00
|
|
|
});
|
2017-01-30 22:53:18 +00:00
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
describe('removeSelectedToken', () => {
|
|
|
|
beforeEach(() => {
|
2018-02-21 20:22:56 +00:00
|
|
|
spyOn(FilteredSearchVisualTokens, 'removeSelectedToken').and.callThrough();
|
|
|
|
spyOn(FilteredSearchManager.prototype, 'handleInputPlaceholder').and.callThrough();
|
|
|
|
spyOn(FilteredSearchManager.prototype, 'toggleClearSearchButton').and.callThrough();
|
2017-06-23 09:28:19 +00:00
|
|
|
initializeManager();
|
2017-04-26 20:12:33 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('calls FilteredSearchVisualTokens.removeSelectedToken', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
manager.removeSelectedToken();
|
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(FilteredSearchVisualTokens.removeSelectedToken).toHaveBeenCalled();
|
2017-04-26 20:12:33 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
it('calls handleInputPlaceholder', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
manager.removeSelectedToken();
|
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
expect(manager.handleInputPlaceholder).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('calls toggleClearSearchButton', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
manager.removeSelectedToken();
|
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
expect(manager.toggleClearSearchButton).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('calls update dropdown offset', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
manager.removeSelectedToken();
|
|
|
|
|
2017-04-26 20:12:33 +00:00
|
|
|
expect(manager.dropdownManager.updateDropdownOffset).toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-11-02 14:47:20 +00:00
|
|
|
describe('Clearing search', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
initializeManager();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Clicking the "x" clear button, clears the input', () => {
|
2020-01-02 13:03:23 +00:00
|
|
|
const inputValue = 'label:=~bug';
|
2017-11-02 14:47:20 +00:00
|
|
|
manager.filteredSearchInput.value = inputValue;
|
|
|
|
manager.filteredSearchInput.dispatchEvent(new Event('input'));
|
|
|
|
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(DropdownUtils.getSearchQuery()).toEqual(inputValue);
|
2017-11-02 14:47:20 +00:00
|
|
|
|
|
|
|
manager.clearSearchButton.click();
|
|
|
|
|
|
|
|
expect(manager.filteredSearchInput.value).toEqual('');
|
2018-02-21 20:22:56 +00:00
|
|
|
expect(DropdownUtils.getSearchQuery()).toEqual('');
|
2017-11-02 14:47:20 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
describe('toggleInputContainerFocus', () => {
|
2017-06-23 09:28:19 +00:00
|
|
|
beforeEach(() => {
|
|
|
|
initializeManager();
|
|
|
|
});
|
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('toggles on focus', () => {
|
|
|
|
input.focus();
|
2018-10-09 18:03:09 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
expect(document.querySelector('.filtered-search-box').classList.contains('focus')).toEqual(
|
|
|
|
true,
|
|
|
|
);
|
2017-04-17 07:01:11 +00:00
|
|
|
});
|
2017-03-10 22:30:42 +00:00
|
|
|
|
2017-04-17 07:01:11 +00:00
|
|
|
it('toggles on blur', () => {
|
|
|
|
input.blur();
|
2018-10-09 18:03:09 +00:00
|
|
|
|
2018-10-17 07:13:26 +00:00
|
|
|
expect(document.querySelector('.filtered-search-box').classList.contains('focus')).toEqual(
|
|
|
|
false,
|
|
|
|
);
|
2017-03-10 22:30:42 +00:00
|
|
|
});
|
2017-01-24 17:57:39 +00:00
|
|
|
});
|
2017-09-06 18:44:59 +00:00
|
|
|
|
|
|
|
describe('getAllParams', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
this.paramsArr = ['key=value', 'otherkey=othervalue'];
|
|
|
|
|
|
|
|
initializeManager();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('correctly modifies params when custom modifier is passed', () => {
|
2018-10-17 07:13:26 +00:00
|
|
|
const modifedParams = manager.getAllParams.call(
|
|
|
|
{
|
|
|
|
modifyUrlParams: paramsArr => paramsArr.reverse(),
|
|
|
|
},
|
|
|
|
[].concat(this.paramsArr),
|
|
|
|
);
|
2017-09-06 18:44:59 +00:00
|
|
|
|
|
|
|
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]);
|
|
|
|
});
|
|
|
|
});
|
2017-04-17 07:01:11 +00:00
|
|
|
});
|