Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-19 12:08:12 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-19 12:08:12 +0300
commit57d1bb82549c6713f87f87d5f35eec3d867c83db (patch)
tree22f708344121786e286fd318fbfbfda632200909 /spec/javascripts
parent4e81d9c050bfea4c866329155c17b929d7381340 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/javascripts')
-rw-r--r--spec/javascripts/filtered_search/filtered_search_manager_spec.js580
-rw-r--r--spec/javascripts/filtered_search/recent_searches_root_spec.js30
-rw-r--r--spec/javascripts/frequent_items/components/app_spec.js257
-rw-r--r--spec/javascripts/frequent_items/mock_data.js168
-rw-r--r--spec/javascripts/frequent_items/store/actions_spec.js228
-rw-r--r--spec/javascripts/frequent_items/store/mutations_spec.js117
-rw-r--r--spec/javascripts/frequent_items/utils_spec.js130
-rw-r--r--spec/javascripts/lib/utils/csrf_token_spec.js50
-rw-r--r--spec/javascripts/lib/utils/navigation_utility_spec.js23
-rw-r--r--spec/javascripts/lib/utils/poll_spec.js222
-rw-r--r--spec/javascripts/lib/utils/sticky_spec.js66
-rw-r--r--spec/javascripts/related_merge_requests/components/related_merge_requests_spec.js88
-rw-r--r--spec/javascripts/related_merge_requests/store/actions_spec.js110
-rw-r--r--spec/javascripts/related_merge_requests/store/mutations_spec.js49
-rw-r--r--spec/javascripts/sidebar/mock_data.js2
15 files changed, 1 insertions, 2119 deletions
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/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/frequent_items/components/app_spec.js b/spec/javascripts/frequent_items/components/app_spec.js
deleted file mode 100644
index b293ed541fd..00000000000
--- a/spec/javascripts/frequent_items/components/app_spec.js
+++ /dev/null
@@ -1,257 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import Vue from 'vue';
-import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
-import axios from '~/lib/utils/axios_utils';
-import appComponent from '~/frequent_items/components/app.vue';
-import eventHub from '~/frequent_items/event_hub';
-import store from '~/frequent_items/store';
-import { FREQUENT_ITEMS, HOUR_IN_MS } from '~/frequent_items/constants';
-import { getTopFrequentItems } from '~/frequent_items/utils';
-import { currentSession, mockFrequentProjects, mockSearchedProjects } from '../mock_data';
-
-let session;
-const createComponentWithStore = (namespace = 'projects') => {
- session = currentSession[namespace];
- gon.api_version = session.apiVersion;
- const Component = Vue.extend(appComponent);
-
- return mountComponentWithStore(Component, {
- store,
- props: {
- namespace,
- currentUserName: session.username,
- currentItem: session.project || session.group,
- },
- });
-};
-
-describe('Frequent Items App Component', () => {
- let vm;
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- vm = createComponentWithStore();
- });
-
- afterEach(() => {
- mock.restore();
- vm.$destroy();
- });
-
- describe('methods', () => {
- describe('dropdownOpenHandler', () => {
- it('should fetch frequent items when no search has been previously made on desktop', () => {
- spyOn(vm, 'fetchFrequentItems');
-
- vm.dropdownOpenHandler();
-
- expect(vm.fetchFrequentItems).toHaveBeenCalledWith();
- });
- });
-
- describe('logItemAccess', () => {
- let storage;
-
- beforeEach(() => {
- storage = {};
-
- spyOn(window.localStorage, 'setItem').and.callFake((storageKey, value) => {
- storage[storageKey] = value;
- });
-
- spyOn(window.localStorage, 'getItem').and.callFake(storageKey => {
- if (storage[storageKey]) {
- return storage[storageKey];
- }
-
- return null;
- });
- });
-
- it('should create a project store if it does not exist and adds a project', () => {
- vm.logItemAccess(session.storageKey, session.project);
-
- const projects = JSON.parse(storage[session.storageKey]);
-
- expect(projects.length).toBe(1);
- expect(projects[0].frequency).toBe(1);
- expect(projects[0].lastAccessedOn).toBeDefined();
- });
-
- it('should prevent inserting same report multiple times into store', () => {
- vm.logItemAccess(session.storageKey, session.project);
- vm.logItemAccess(session.storageKey, session.project);
-
- const projects = JSON.parse(storage[session.storageKey]);
-
- expect(projects.length).toBe(1);
- });
-
- it('should increase frequency of report if it was logged multiple times over the course of an hour', () => {
- let projects;
- const newTimestamp = Date.now() + HOUR_IN_MS + 1;
-
- vm.logItemAccess(session.storageKey, session.project);
- projects = JSON.parse(storage[session.storageKey]);
-
- expect(projects[0].frequency).toBe(1);
-
- vm.logItemAccess(session.storageKey, {
- ...session.project,
- lastAccessedOn: newTimestamp,
- });
- projects = JSON.parse(storage[session.storageKey]);
-
- expect(projects[0].frequency).toBe(2);
- expect(projects[0].lastAccessedOn).not.toBe(session.project.lastAccessedOn);
- });
-
- it('should always update project metadata', () => {
- let projects;
- const oldProject = {
- ...session.project,
- };
-
- const newProject = {
- ...session.project,
- name: 'New Name',
- avatarUrl: 'new/avatar.png',
- namespace: 'New / Namespace',
- webUrl: 'http://localhost/new/web/url',
- };
-
- vm.logItemAccess(session.storageKey, oldProject);
- projects = JSON.parse(storage[session.storageKey]);
-
- expect(projects[0].name).toBe(oldProject.name);
- expect(projects[0].avatarUrl).toBe(oldProject.avatarUrl);
- expect(projects[0].namespace).toBe(oldProject.namespace);
- expect(projects[0].webUrl).toBe(oldProject.webUrl);
-
- vm.logItemAccess(session.storageKey, newProject);
- projects = JSON.parse(storage[session.storageKey]);
-
- expect(projects[0].name).toBe(newProject.name);
- expect(projects[0].avatarUrl).toBe(newProject.avatarUrl);
- expect(projects[0].namespace).toBe(newProject.namespace);
- expect(projects[0].webUrl).toBe(newProject.webUrl);
- });
-
- it('should not add more than 20 projects in store', () => {
- for (let id = 0; id < FREQUENT_ITEMS.MAX_COUNT; id += 1) {
- const project = {
- ...session.project,
- id,
- };
- vm.logItemAccess(session.storageKey, project);
- }
-
- const projects = JSON.parse(storage[session.storageKey]);
-
- expect(projects.length).toBe(FREQUENT_ITEMS.MAX_COUNT);
- });
- });
- });
-
- describe('created', () => {
- it('should bind event listeners on eventHub', done => {
- spyOn(eventHub, '$on');
-
- createComponentWithStore().$mount();
-
- Vue.nextTick(() => {
- expect(eventHub.$on).toHaveBeenCalledWith('projects-dropdownOpen', jasmine.any(Function));
- done();
- });
- });
- });
-
- describe('beforeDestroy', () => {
- it('should unbind event listeners on eventHub', done => {
- spyOn(eventHub, '$off');
-
- vm.$mount();
- vm.$destroy();
-
- Vue.nextTick(() => {
- expect(eventHub.$off).toHaveBeenCalledWith('projects-dropdownOpen', jasmine.any(Function));
- done();
- });
- });
- });
-
- describe('template', () => {
- it('should render search input', () => {
- expect(vm.$el.querySelector('.search-input-container')).toBeDefined();
- });
-
- it('should render loading animation', done => {
- vm.$store.dispatch('fetchSearchedItems');
-
- Vue.nextTick(() => {
- const loadingEl = vm.$el.querySelector('.loading-animation');
-
- expect(loadingEl).toBeDefined();
- expect(loadingEl.classList.contains('prepend-top-20')).toBe(true);
- expect(loadingEl.querySelector('span').getAttribute('aria-label')).toBe('Loading projects');
- done();
- });
- });
-
- it('should render frequent projects list header', done => {
- Vue.nextTick(() => {
- const sectionHeaderEl = vm.$el.querySelector('.section-header');
-
- expect(sectionHeaderEl).toBeDefined();
- expect(sectionHeaderEl.innerText.trim()).toBe('Frequently visited');
- done();
- });
- });
-
- it('should render frequent projects list', done => {
- const expectedResult = getTopFrequentItems(mockFrequentProjects);
- spyOn(window.localStorage, 'getItem').and.callFake(() =>
- JSON.stringify(mockFrequentProjects),
- );
-
- expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(1);
-
- vm.fetchFrequentItems();
- Vue.nextTick(() => {
- expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(
- expectedResult.length,
- );
- done();
- });
- });
-
- it('should render searched projects list', done => {
- mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(200, mockSearchedProjects);
-
- expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(1);
-
- vm.$store.dispatch('setSearchQuery', 'gitlab');
- vm.$nextTick()
- .then(() => {
- expect(vm.$el.querySelector('.loading-animation')).toBeDefined();
- })
-
- // This test waits for multiple ticks in order to allow the responses to
- // propagate through each interceptor installed on the Axios instance.
- // This shouldn't be necessary; this test should be refactored to avoid this.
- // https://gitlab.com/gitlab-org/gitlab/issues/32479
- .then(vm.$nextTick)
- .then(vm.$nextTick)
- .then(vm.$nextTick)
-
- .then(() => {
- expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(
- mockSearchedProjects.data.length,
- );
- })
- .then(done)
- .catch(done.fail);
- });
- });
-});
diff --git a/spec/javascripts/frequent_items/mock_data.js b/spec/javascripts/frequent_items/mock_data.js
deleted file mode 100644
index 419f70e41af..00000000000
--- a/spec/javascripts/frequent_items/mock_data.js
+++ /dev/null
@@ -1,168 +0,0 @@
-export const currentSession = {
- groups: {
- username: 'root',
- storageKey: 'root/frequent-groups',
- apiVersion: 'v4',
- group: {
- id: 1,
- name: 'dummy-group',
- full_name: 'dummy-parent-group',
- webUrl: `${gl.TEST_HOST}/dummy-group`,
- avatarUrl: null,
- lastAccessedOn: Date.now(),
- },
- },
- projects: {
- username: 'root',
- storageKey: 'root/frequent-projects',
- apiVersion: 'v4',
- project: {
- id: 1,
- name: 'dummy-project',
- namespace: 'SampleGroup / Dummy-Project',
- webUrl: `${gl.TEST_HOST}/samplegroup/dummy-project`,
- avatarUrl: null,
- lastAccessedOn: Date.now(),
- },
- },
-};
-
-export const mockNamespace = 'projects';
-
-export const mockStorageKey = 'test-user/frequent-projects';
-
-export const mockGroup = {
- id: 1,
- name: 'Sub451',
- namespace: 'Commit451 / Sub451',
- webUrl: `${gl.TEST_HOST}/Commit451/Sub451`,
- avatarUrl: null,
-};
-
-export const mockRawGroup = {
- id: 1,
- name: 'Sub451',
- full_name: 'Commit451 / Sub451',
- web_url: `${gl.TEST_HOST}/Commit451/Sub451`,
- avatar_url: null,
-};
-
-export const mockFrequentGroups = [
- {
- id: 3,
- name: 'Subgroup451',
- full_name: 'Commit451 / Subgroup451',
- webUrl: '/Commit451/Subgroup451',
- avatarUrl: null,
- frequency: 7,
- lastAccessedOn: 1497979281815,
- },
- {
- id: 1,
- name: 'Commit451',
- full_name: 'Commit451',
- webUrl: '/Commit451',
- avatarUrl: null,
- frequency: 3,
- lastAccessedOn: 1497979281815,
- },
-];
-
-export const mockSearchedGroups = [mockRawGroup];
-export const mockProcessedSearchedGroups = [mockGroup];
-
-export const mockProject = {
- id: 1,
- name: 'GitLab Community Edition',
- namespace: 'gitlab-org / gitlab-ce',
- webUrl: `${gl.TEST_HOST}/gitlab-org/gitlab-foss`,
- avatarUrl: null,
-};
-
-export const mockRawProject = {
- id: 1,
- name: 'GitLab Community Edition',
- name_with_namespace: 'gitlab-org / gitlab-ce',
- web_url: `${gl.TEST_HOST}/gitlab-org/gitlab-foss`,
- avatar_url: null,
-};
-
-export const mockFrequentProjects = [
- {
- id: 1,
- name: 'GitLab Community Edition',
- namespace: 'gitlab-org / gitlab-ce',
- webUrl: `${gl.TEST_HOST}/gitlab-org/gitlab-foss`,
- avatarUrl: null,
- frequency: 1,
- lastAccessedOn: Date.now(),
- },
- {
- id: 2,
- name: 'GitLab CI',
- namespace: 'gitlab-org / gitlab-ci',
- webUrl: `${gl.TEST_HOST}/gitlab-org/gitlab-ci`,
- avatarUrl: null,
- frequency: 9,
- lastAccessedOn: Date.now(),
- },
- {
- id: 3,
- name: 'Typeahead.Js',
- namespace: 'twitter / typeahead-js',
- webUrl: `${gl.TEST_HOST}/twitter/typeahead-js`,
- avatarUrl: '/uploads/-/system/project/avatar/7/TWBS.png',
- frequency: 2,
- lastAccessedOn: Date.now(),
- },
- {
- id: 4,
- name: 'Intel',
- namespace: 'platform / hardware / bsp / intel',
- webUrl: `${gl.TEST_HOST}/platform/hardware/bsp/intel`,
- avatarUrl: null,
- frequency: 3,
- lastAccessedOn: Date.now(),
- },
- {
- id: 5,
- name: 'v4.4',
- namespace: 'platform / hardware / bsp / kernel / common / v4.4',
- webUrl: `${gl.TEST_HOST}/platform/hardware/bsp/kernel/common/v4.4`,
- avatarUrl: null,
- frequency: 8,
- lastAccessedOn: Date.now(),
- },
-];
-
-export const mockSearchedProjects = { data: [mockRawProject] };
-export const mockProcessedSearchedProjects = [mockProject];
-
-export const unsortedFrequentItems = [
- { id: 1, frequency: 12, lastAccessedOn: 1491400843391 },
- { id: 2, frequency: 14, lastAccessedOn: 1488240890738 },
- { id: 3, frequency: 44, lastAccessedOn: 1497675908472 },
- { id: 4, frequency: 8, lastAccessedOn: 1497979281815 },
- { id: 5, frequency: 34, lastAccessedOn: 1488089211943 },
- { id: 6, frequency: 14, lastAccessedOn: 1493517292488 },
- { id: 7, frequency: 42, lastAccessedOn: 1486815299875 },
- { id: 8, frequency: 33, lastAccessedOn: 1500762279114 },
- { id: 10, frequency: 46, lastAccessedOn: 1483251641543 },
-];
-
-/**
- * This const has a specific order which tests authenticity
- * of `getTopFrequentItems` method so
- * DO NOT change order of items in this const.
- */
-export const sortedFrequentItems = [
- { id: 10, frequency: 46, lastAccessedOn: 1483251641543 },
- { id: 3, frequency: 44, lastAccessedOn: 1497675908472 },
- { id: 7, frequency: 42, lastAccessedOn: 1486815299875 },
- { id: 5, frequency: 34, lastAccessedOn: 1488089211943 },
- { id: 8, frequency: 33, lastAccessedOn: 1500762279114 },
- { id: 6, frequency: 14, lastAccessedOn: 1493517292488 },
- { id: 2, frequency: 14, lastAccessedOn: 1488240890738 },
- { id: 1, frequency: 12, lastAccessedOn: 1491400843391 },
- { id: 4, frequency: 8, lastAccessedOn: 1497979281815 },
-];
diff --git a/spec/javascripts/frequent_items/store/actions_spec.js b/spec/javascripts/frequent_items/store/actions_spec.js
deleted file mode 100644
index 7b065b69cce..00000000000
--- a/spec/javascripts/frequent_items/store/actions_spec.js
+++ /dev/null
@@ -1,228 +0,0 @@
-import testAction from 'spec/helpers/vuex_action_helper';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import AccessorUtilities from '~/lib/utils/accessor';
-import * as actions from '~/frequent_items/store/actions';
-import * as types from '~/frequent_items/store/mutation_types';
-import state from '~/frequent_items/store/state';
-import {
- mockNamespace,
- mockStorageKey,
- mockFrequentProjects,
- mockSearchedProjects,
-} from '../mock_data';
-
-describe('Frequent Items Dropdown Store Actions', () => {
- let mockedState;
- let mock;
-
- beforeEach(() => {
- mockedState = state();
- mock = new MockAdapter(axios);
-
- mockedState.namespace = mockNamespace;
- mockedState.storageKey = mockStorageKey;
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('setNamespace', () => {
- it('should set namespace', done => {
- testAction(
- actions.setNamespace,
- mockNamespace,
- mockedState,
- [{ type: types.SET_NAMESPACE, payload: mockNamespace }],
- [],
- done,
- );
- });
- });
-
- describe('setStorageKey', () => {
- it('should set storage key', done => {
- testAction(
- actions.setStorageKey,
- mockStorageKey,
- mockedState,
- [{ type: types.SET_STORAGE_KEY, payload: mockStorageKey }],
- [],
- done,
- );
- });
- });
-
- describe('requestFrequentItems', () => {
- it('should request frequent items', done => {
- testAction(
- actions.requestFrequentItems,
- null,
- mockedState,
- [{ type: types.REQUEST_FREQUENT_ITEMS }],
- [],
- done,
- );
- });
- });
-
- describe('receiveFrequentItemsSuccess', () => {
- it('should set frequent items', done => {
- testAction(
- actions.receiveFrequentItemsSuccess,
- mockFrequentProjects,
- mockedState,
- [{ type: types.RECEIVE_FREQUENT_ITEMS_SUCCESS, payload: mockFrequentProjects }],
- [],
- done,
- );
- });
- });
-
- describe('receiveFrequentItemsError', () => {
- it('should set frequent items error state', done => {
- testAction(
- actions.receiveFrequentItemsError,
- null,
- mockedState,
- [{ type: types.RECEIVE_FREQUENT_ITEMS_ERROR }],
- [],
- done,
- );
- });
- });
-
- describe('fetchFrequentItems', () => {
- it('should dispatch `receiveFrequentItemsSuccess`', done => {
- mockedState.namespace = mockNamespace;
- mockedState.storageKey = mockStorageKey;
-
- testAction(
- actions.fetchFrequentItems,
- null,
- mockedState,
- [],
- [{ type: 'requestFrequentItems' }, { type: 'receiveFrequentItemsSuccess', payload: [] }],
- done,
- );
- });
-
- it('should dispatch `receiveFrequentItemsError`', done => {
- spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(false);
- mockedState.namespace = mockNamespace;
- mockedState.storageKey = mockStorageKey;
-
- testAction(
- actions.fetchFrequentItems,
- null,
- mockedState,
- [],
- [{ type: 'requestFrequentItems' }, { type: 'receiveFrequentItemsError' }],
- done,
- );
- });
- });
-
- describe('requestSearchedItems', () => {
- it('should request searched items', done => {
- testAction(
- actions.requestSearchedItems,
- null,
- mockedState,
- [{ type: types.REQUEST_SEARCHED_ITEMS }],
- [],
- done,
- );
- });
- });
-
- describe('receiveSearchedItemsSuccess', () => {
- it('should set searched items', done => {
- testAction(
- actions.receiveSearchedItemsSuccess,
- mockSearchedProjects,
- mockedState,
- [{ type: types.RECEIVE_SEARCHED_ITEMS_SUCCESS, payload: mockSearchedProjects }],
- [],
- done,
- );
- });
- });
-
- describe('receiveSearchedItemsError', () => {
- it('should set searched items error state', done => {
- testAction(
- actions.receiveSearchedItemsError,
- null,
- mockedState,
- [{ type: types.RECEIVE_SEARCHED_ITEMS_ERROR }],
- [],
- done,
- );
- });
- });
-
- describe('fetchSearchedItems', () => {
- beforeEach(() => {
- gon.api_version = 'v4';
- });
-
- it('should dispatch `receiveSearchedItemsSuccess`', done => {
- mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(200, mockSearchedProjects, {});
-
- testAction(
- actions.fetchSearchedItems,
- null,
- mockedState,
- [],
- [
- { type: 'requestSearchedItems' },
- {
- type: 'receiveSearchedItemsSuccess',
- payload: { data: mockSearchedProjects, headers: {} },
- },
- ],
- done,
- );
- });
-
- it('should dispatch `receiveSearchedItemsError`', done => {
- gon.api_version = 'v4';
- mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(500);
-
- testAction(
- actions.fetchSearchedItems,
- null,
- mockedState,
- [],
- [{ type: 'requestSearchedItems' }, { type: 'receiveSearchedItemsError' }],
- done,
- );
- });
- });
-
- describe('setSearchQuery', () => {
- it('should commit query and dispatch `fetchSearchedItems` when query is present', done => {
- testAction(
- actions.setSearchQuery,
- { query: 'test' },
- mockedState,
- [{ type: types.SET_SEARCH_QUERY, payload: { query: 'test' } }],
- [{ type: 'fetchSearchedItems', payload: { query: 'test' } }],
- done,
- );
- });
-
- it('should commit query and dispatch `fetchFrequentItems` when query is empty', done => {
- testAction(
- actions.setSearchQuery,
- null,
- mockedState,
- [{ type: types.SET_SEARCH_QUERY, payload: null }],
- [{ type: 'fetchFrequentItems' }],
- done,
- );
- });
- });
-});
diff --git a/spec/javascripts/frequent_items/store/mutations_spec.js b/spec/javascripts/frequent_items/store/mutations_spec.js
deleted file mode 100644
index d36964b2600..00000000000
--- a/spec/javascripts/frequent_items/store/mutations_spec.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import state from '~/frequent_items/store/state';
-import mutations from '~/frequent_items/store/mutations';
-import * as types from '~/frequent_items/store/mutation_types';
-import {
- mockNamespace,
- mockStorageKey,
- mockFrequentProjects,
- mockSearchedProjects,
- mockProcessedSearchedProjects,
- mockSearchedGroups,
- mockProcessedSearchedGroups,
-} from '../mock_data';
-
-describe('Frequent Items dropdown mutations', () => {
- let stateCopy;
-
- beforeEach(() => {
- stateCopy = state();
- });
-
- describe('SET_NAMESPACE', () => {
- it('should set namespace', () => {
- mutations[types.SET_NAMESPACE](stateCopy, mockNamespace);
-
- expect(stateCopy.namespace).toEqual(mockNamespace);
- });
- });
-
- describe('SET_STORAGE_KEY', () => {
- it('should set storage key', () => {
- mutations[types.SET_STORAGE_KEY](stateCopy, mockStorageKey);
-
- expect(stateCopy.storageKey).toEqual(mockStorageKey);
- });
- });
-
- describe('SET_SEARCH_QUERY', () => {
- it('should set search query', () => {
- const searchQuery = 'gitlab-ce';
-
- mutations[types.SET_SEARCH_QUERY](stateCopy, searchQuery);
-
- expect(stateCopy.searchQuery).toEqual(searchQuery);
- });
- });
-
- describe('REQUEST_FREQUENT_ITEMS', () => {
- it('should set view states when requesting frequent items', () => {
- mutations[types.REQUEST_FREQUENT_ITEMS](stateCopy);
-
- expect(stateCopy.isLoadingItems).toEqual(true);
- expect(stateCopy.hasSearchQuery).toEqual(false);
- });
- });
-
- describe('RECEIVE_FREQUENT_ITEMS_SUCCESS', () => {
- it('should set view states when receiving frequent items', () => {
- mutations[types.RECEIVE_FREQUENT_ITEMS_SUCCESS](stateCopy, mockFrequentProjects);
-
- expect(stateCopy.items).toEqual(mockFrequentProjects);
- expect(stateCopy.isLoadingItems).toEqual(false);
- expect(stateCopy.hasSearchQuery).toEqual(false);
- expect(stateCopy.isFetchFailed).toEqual(false);
- });
- });
-
- describe('RECEIVE_FREQUENT_ITEMS_ERROR', () => {
- it('should set items and view states when error occurs retrieving frequent items', () => {
- mutations[types.RECEIVE_FREQUENT_ITEMS_ERROR](stateCopy);
-
- expect(stateCopy.items).toEqual([]);
- expect(stateCopy.isLoadingItems).toEqual(false);
- expect(stateCopy.hasSearchQuery).toEqual(false);
- expect(stateCopy.isFetchFailed).toEqual(true);
- });
- });
-
- describe('REQUEST_SEARCHED_ITEMS', () => {
- it('should set view states when requesting searched items', () => {
- mutations[types.REQUEST_SEARCHED_ITEMS](stateCopy);
-
- expect(stateCopy.isLoadingItems).toEqual(true);
- expect(stateCopy.hasSearchQuery).toEqual(true);
- });
- });
-
- describe('RECEIVE_SEARCHED_ITEMS_SUCCESS', () => {
- it('should set items and view states when receiving searched items', () => {
- mutations[types.RECEIVE_SEARCHED_ITEMS_SUCCESS](stateCopy, mockSearchedProjects);
-
- expect(stateCopy.items).toEqual(mockProcessedSearchedProjects);
- expect(stateCopy.isLoadingItems).toEqual(false);
- expect(stateCopy.hasSearchQuery).toEqual(true);
- expect(stateCopy.isFetchFailed).toEqual(false);
- });
-
- it('should also handle the different `full_name` key for namespace in groups payload', () => {
- mutations[types.RECEIVE_SEARCHED_ITEMS_SUCCESS](stateCopy, mockSearchedGroups);
-
- expect(stateCopy.items).toEqual(mockProcessedSearchedGroups);
- expect(stateCopy.isLoadingItems).toEqual(false);
- expect(stateCopy.hasSearchQuery).toEqual(true);
- expect(stateCopy.isFetchFailed).toEqual(false);
- });
- });
-
- describe('RECEIVE_SEARCHED_ITEMS_ERROR', () => {
- it('should set view states when error occurs retrieving searched items', () => {
- mutations[types.RECEIVE_SEARCHED_ITEMS_ERROR](stateCopy);
-
- expect(stateCopy.items).toEqual([]);
- expect(stateCopy.isLoadingItems).toEqual(false);
- expect(stateCopy.hasSearchQuery).toEqual(true);
- expect(stateCopy.isFetchFailed).toEqual(true);
- });
- });
-});
diff --git a/spec/javascripts/frequent_items/utils_spec.js b/spec/javascripts/frequent_items/utils_spec.js
deleted file mode 100644
index 2939b46bc31..00000000000
--- a/spec/javascripts/frequent_items/utils_spec.js
+++ /dev/null
@@ -1,130 +0,0 @@
-import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
-import {
- isMobile,
- getTopFrequentItems,
- updateExistingFrequentItem,
- sanitizeItem,
-} from '~/frequent_items/utils';
-import { HOUR_IN_MS, FREQUENT_ITEMS } from '~/frequent_items/constants';
-import { mockProject, unsortedFrequentItems, sortedFrequentItems } from './mock_data';
-
-describe('Frequent Items utils spec', () => {
- describe('isMobile', () => {
- it('returns true when the screen is medium ', () => {
- spyOn(bp, 'getBreakpointSize').and.returnValue('md');
-
- expect(isMobile()).toBe(true);
- });
-
- it('returns true when the screen is small ', () => {
- spyOn(bp, 'getBreakpointSize').and.returnValue('sm');
-
- expect(isMobile()).toBe(true);
- });
-
- it('returns true when the screen is extra-small ', () => {
- spyOn(bp, 'getBreakpointSize').and.returnValue('xs');
-
- expect(isMobile()).toBe(true);
- });
-
- it('returns false when the screen is larger than medium ', () => {
- spyOn(bp, 'getBreakpointSize').and.returnValue('lg');
-
- expect(isMobile()).toBe(false);
- });
- });
-
- describe('getTopFrequentItems', () => {
- it('returns empty array if no items provided', () => {
- const result = getTopFrequentItems();
-
- expect(result.length).toBe(0);
- });
-
- it('returns correct amount of items for mobile', () => {
- spyOn(bp, 'getBreakpointSize').and.returnValue('md');
- const result = getTopFrequentItems(unsortedFrequentItems);
-
- expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_MOBILE);
- });
-
- it('returns correct amount of items for desktop', () => {
- spyOn(bp, 'getBreakpointSize').and.returnValue('xl');
- const result = getTopFrequentItems(unsortedFrequentItems);
-
- expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_DESKTOP);
- });
-
- it('sorts frequent items in order of frequency and lastAccessedOn', () => {
- spyOn(bp, 'getBreakpointSize').and.returnValue('xl');
- const result = getTopFrequentItems(unsortedFrequentItems);
- const expectedResult = sortedFrequentItems.slice(0, FREQUENT_ITEMS.LIST_COUNT_DESKTOP);
-
- expect(result).toEqual(expectedResult);
- });
- });
-
- describe('updateExistingFrequentItem', () => {
- let mockedProject;
-
- beforeEach(() => {
- mockedProject = {
- ...mockProject,
- frequency: 1,
- lastAccessedOn: 1497979281815,
- };
- });
-
- it('updates item if accessed over an hour ago', () => {
- const newTimestamp = Date.now() + HOUR_IN_MS + 1;
- const newItem = {
- ...mockedProject,
- lastAccessedOn: newTimestamp,
- };
- const result = updateExistingFrequentItem(mockedProject, newItem);
-
- expect(result.frequency).toBe(mockedProject.frequency + 1);
- });
-
- it('does not update item if accessed within the hour', () => {
- const newItem = {
- ...mockedProject,
- lastAccessedOn: mockedProject.lastAccessedOn + HOUR_IN_MS,
- };
- const result = updateExistingFrequentItem(mockedProject, newItem);
-
- expect(result.frequency).toBe(mockedProject.frequency);
- });
- });
-
- describe('sanitizeItem', () => {
- it('strips HTML tags for name and namespace', () => {
- const input = {
- name: '<br><b>test</b>',
- namespace: '<br>test',
- id: 1,
- };
-
- expect(sanitizeItem(input)).toEqual({ name: 'test', namespace: 'test', id: 1 });
- });
-
- it("skips `name` key if it doesn't exist on the item", () => {
- const input = {
- namespace: '<br>test',
- id: 1,
- };
-
- expect(sanitizeItem(input)).toEqual({ namespace: 'test', id: 1 });
- });
-
- it("skips `namespace` key if it doesn't exist on the item", () => {
- const input = {
- name: '<br><b>test</b>',
- id: 1,
- };
-
- expect(sanitizeItem(input)).toEqual({ name: 'test', id: 1 });
- });
- });
-});
diff --git a/spec/javascripts/lib/utils/csrf_token_spec.js b/spec/javascripts/lib/utils/csrf_token_spec.js
deleted file mode 100644
index 867bee34ee5..00000000000
--- a/spec/javascripts/lib/utils/csrf_token_spec.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import csrf from '~/lib/utils/csrf';
-
-describe('csrf', function() {
- beforeEach(() => {
- this.tokenKey = 'X-CSRF-Token';
- this.token =
- 'pH1cvjnP9grx2oKlhWEDvUZnJ8x2eXsIs1qzyHkF3DugSG5yTxR76CWeEZRhML2D1IeVB7NEW0t5l/axE4iJpQ==';
- });
-
- it('returns the correct headerKey', () => {
- expect(csrf.headerKey).toBe(this.tokenKey);
- });
-
- describe('when csrf token is in the DOM', () => {
- beforeEach(() => {
- setFixtures(`
- <meta name="csrf-token" content="${this.token}">
- `);
-
- csrf.init();
- });
-
- it('returns the csrf token', () => {
- expect(csrf.token).toBe(this.token);
- });
-
- it('returns the csrf headers object', () => {
- expect(csrf.headers[this.tokenKey]).toBe(this.token);
- });
- });
-
- describe('when csrf token is not in the DOM', () => {
- beforeEach(() => {
- setFixtures(`
- <meta name="some-other-token">
- `);
-
- csrf.init();
- });
-
- it('returns null for token', () => {
- expect(csrf.token).toBeNull();
- });
-
- it('returns empty object for headers', () => {
- expect(typeof csrf.headers).toBe('object');
- expect(Object.keys(csrf.headers).length).toBe(0);
- });
- });
-});
diff --git a/spec/javascripts/lib/utils/navigation_utility_spec.js b/spec/javascripts/lib/utils/navigation_utility_spec.js
deleted file mode 100644
index be620e4a27c..00000000000
--- a/spec/javascripts/lib/utils/navigation_utility_spec.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import findAndFollowLink from '~/lib/utils/navigation_utility';
-
-describe('findAndFollowLink', () => {
- it('visits a link when the selector exists', () => {
- const href = '/some/path';
- const visitUrl = spyOnDependency(findAndFollowLink, 'visitUrl');
-
- setFixtures(`<a class="my-shortcut" href="${href}">link</a>`);
-
- findAndFollowLink('.my-shortcut');
-
- expect(visitUrl).toHaveBeenCalledWith(href);
- });
-
- it('does not throw an exception when the selector does not exist', () => {
- const visitUrl = spyOnDependency(findAndFollowLink, 'visitUrl');
-
- // this should not throw an exception
- findAndFollowLink('.this-selector-does-not-exist');
-
- expect(visitUrl).not.toHaveBeenCalled();
- });
-});
diff --git a/spec/javascripts/lib/utils/poll_spec.js b/spec/javascripts/lib/utils/poll_spec.js
deleted file mode 100644
index 138041a349f..00000000000
--- a/spec/javascripts/lib/utils/poll_spec.js
+++ /dev/null
@@ -1,222 +0,0 @@
-/* eslint-disable jasmine/no-unsafe-spy */
-
-import Poll from '~/lib/utils/poll';
-import { successCodes } from '~/lib/utils/http_status';
-
-const waitForAllCallsToFinish = (service, waitForCount, successCallback) => {
- const timer = () => {
- setTimeout(() => {
- if (service.fetch.calls.count() === waitForCount) {
- successCallback();
- } else {
- timer();
- }
- }, 0);
- };
-
- timer();
-};
-
-function mockServiceCall(service, response, shouldFail = false) {
- const action = shouldFail ? Promise.reject : Promise.resolve;
- const responseObject = response;
-
- if (!responseObject.headers) responseObject.headers = {};
-
- service.fetch.and.callFake(action.bind(Promise, responseObject));
-}
-
-describe('Poll', () => {
- const service = jasmine.createSpyObj('service', ['fetch']);
- const callbacks = jasmine.createSpyObj('callbacks', ['success', 'error', 'notification']);
-
- function setup() {
- return new Poll({
- resource: service,
- method: 'fetch',
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- notificationCallback: callbacks.notification,
- }).makeRequest();
- }
-
- afterEach(() => {
- callbacks.success.calls.reset();
- callbacks.error.calls.reset();
- callbacks.notification.calls.reset();
- service.fetch.calls.reset();
- });
-
- it('calls the success callback when no header for interval is provided', done => {
- mockServiceCall(service, { status: 200 });
- setup();
-
- waitForAllCallsToFinish(service, 1, () => {
- expect(callbacks.success).toHaveBeenCalled();
- expect(callbacks.error).not.toHaveBeenCalled();
-
- done();
- });
- });
-
- it('calls the error callback when the http request returns an error', done => {
- mockServiceCall(service, { status: 500 }, true);
- setup();
-
- waitForAllCallsToFinish(service, 1, () => {
- expect(callbacks.success).not.toHaveBeenCalled();
- expect(callbacks.error).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('skips the error callback when request is aborted', done => {
- mockServiceCall(service, { status: 0 }, true);
- setup();
-
- waitForAllCallsToFinish(service, 1, () => {
- expect(callbacks.success).not.toHaveBeenCalled();
- expect(callbacks.error).not.toHaveBeenCalled();
- expect(callbacks.notification).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('should call the success callback when the interval header is -1', done => {
- mockServiceCall(service, { status: 200, headers: { 'poll-interval': -1 } });
- setup()
- .then(() => {
- expect(callbacks.success).toHaveBeenCalled();
- expect(callbacks.error).not.toHaveBeenCalled();
-
- done();
- })
- .catch(done.fail);
- });
-
- describe('for 2xx status code', () => {
- successCodes.forEach(httpCode => {
- it(`starts polling when http status is ${httpCode} and interval header is provided`, done => {
- mockServiceCall(service, { status: httpCode, headers: { 'poll-interval': 1 } });
-
- const Polling = new Poll({
- resource: service,
- method: 'fetch',
- data: { page: 1 },
- successCallback: callbacks.success,
- errorCallback: callbacks.error,
- });
-
- Polling.makeRequest();
-
- waitForAllCallsToFinish(service, 2, () => {
- Polling.stop();
-
- expect(service.fetch.calls.count()).toEqual(2);
- expect(service.fetch).toHaveBeenCalledWith({ page: 1 });
- expect(callbacks.success).toHaveBeenCalled();
- expect(callbacks.error).not.toHaveBeenCalled();
-
- done();
- });
- });
- });
- });
-
- describe('stop', () => {
- it('stops polling when method is called', done => {
- mockServiceCall(service, { status: 200, headers: { 'poll-interval': 1 } });
-
- const Polling = new Poll({
- resource: service,
- method: 'fetch',
- data: { page: 1 },
- successCallback: () => {
- Polling.stop();
- },
- errorCallback: callbacks.error,
- });
-
- spyOn(Polling, 'stop').and.callThrough();
-
- Polling.makeRequest();
-
- waitForAllCallsToFinish(service, 1, () => {
- expect(service.fetch.calls.count()).toEqual(1);
- expect(service.fetch).toHaveBeenCalledWith({ page: 1 });
- expect(Polling.stop).toHaveBeenCalled();
-
- done();
- });
- });
- });
-
- describe('enable', () => {
- it('should enable polling upon a response', done => {
- jasmine.clock().install();
-
- const Polling = new Poll({
- resource: service,
- method: 'fetch',
- data: { page: 1 },
- successCallback: () => {},
- });
-
- Polling.enable({
- data: { page: 4 },
- response: { status: 200, headers: { 'poll-interval': 1 } },
- });
-
- jasmine.clock().tick(1);
- jasmine.clock().uninstall();
-
- waitForAllCallsToFinish(service, 1, () => {
- Polling.stop();
-
- expect(service.fetch.calls.count()).toEqual(1);
- expect(service.fetch).toHaveBeenCalledWith({ page: 4 });
- expect(Polling.options.data).toEqual({ page: 4 });
- done();
- });
- });
- });
-
- describe('restart', () => {
- it('should restart polling when its called', done => {
- mockServiceCall(service, { status: 200, headers: { 'poll-interval': 1 } });
-
- const Polling = new Poll({
- resource: service,
- method: 'fetch',
- data: { page: 1 },
- successCallback: () => {
- Polling.stop();
- setTimeout(() => {
- Polling.restart({ data: { page: 4 } });
- }, 0);
- },
- errorCallback: callbacks.error,
- });
-
- spyOn(Polling, 'stop').and.callThrough();
- spyOn(Polling, 'enable').and.callThrough();
- spyOn(Polling, 'restart').and.callThrough();
-
- Polling.makeRequest();
-
- waitForAllCallsToFinish(service, 2, () => {
- Polling.stop();
-
- expect(service.fetch.calls.count()).toEqual(2);
- expect(service.fetch).toHaveBeenCalledWith({ page: 4 });
- expect(Polling.stop).toHaveBeenCalled();
- expect(Polling.enable).toHaveBeenCalled();
- expect(Polling.restart).toHaveBeenCalled();
- expect(Polling.options.data).toEqual({ page: 4 });
- done();
- });
- });
- });
-});
diff --git a/spec/javascripts/lib/utils/sticky_spec.js b/spec/javascripts/lib/utils/sticky_spec.js
deleted file mode 100644
index 1b1e7da1ed3..00000000000
--- a/spec/javascripts/lib/utils/sticky_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { isSticky } from '~/lib/utils/sticky';
-
-describe('sticky', () => {
- let el;
-
- beforeEach(() => {
- document.body.innerHTML += `
- <div class="parent">
- <div id="js-sticky"></div>
- </div>
- `;
-
- el = document.getElementById('js-sticky');
- });
-
- afterEach(() => {
- el.parentNode.remove();
- });
-
- describe('when stuck', () => {
- it('does not remove is-stuck class', () => {
- isSticky(el, 0, el.offsetTop);
- isSticky(el, 0, el.offsetTop);
-
- expect(el.classList.contains('is-stuck')).toBeTruthy();
- });
-
- it('adds is-stuck class', () => {
- isSticky(el, 0, el.offsetTop);
-
- expect(el.classList.contains('is-stuck')).toBeTruthy();
- });
-
- it('inserts placeholder element', () => {
- isSticky(el, 0, el.offsetTop, true);
-
- expect(document.querySelector('.sticky-placeholder')).not.toBeNull();
- });
- });
-
- describe('when not stuck', () => {
- it('removes is-stuck class', () => {
- spyOn(el.classList, 'remove').and.callThrough();
-
- isSticky(el, 0, el.offsetTop);
- isSticky(el, 0, 0);
-
- expect(el.classList.remove).toHaveBeenCalledWith('is-stuck');
-
- expect(el.classList.contains('is-stuck')).toBeFalsy();
- });
-
- it('does not add is-stuck class', () => {
- isSticky(el, 0, 0);
-
- expect(el.classList.contains('is-stuck')).toBeFalsy();
- });
-
- it('removes placeholder', () => {
- isSticky(el, 0, el.offsetTop, true);
- isSticky(el, 0, 0, true);
-
- expect(document.querySelector('.sticky-placeholder')).toBeNull();
- });
- });
-});
diff --git a/spec/javascripts/related_merge_requests/components/related_merge_requests_spec.js b/spec/javascripts/related_merge_requests/components/related_merge_requests_spec.js
deleted file mode 100644
index d8bdf69dfee..00000000000
--- a/spec/javascripts/related_merge_requests/components/related_merge_requests_spec.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import { mount, createLocalVue } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import RelatedIssuableItem from '~/vue_shared/components/issue/related_issuable_item.vue';
-import RelatedMergeRequests from '~/related_merge_requests/components/related_merge_requests.vue';
-import createStore from '~/related_merge_requests/store/index';
-
-const FIXTURE_PATH = 'issues/related_merge_requests.json';
-const API_ENDPOINT = '/api/v4/projects/2/issues/33/related_merge_requests';
-const localVue = createLocalVue();
-
-describe('RelatedMergeRequests', () => {
- let wrapper;
- let mock;
- let mockData;
-
- beforeEach(done => {
- loadFixtures(FIXTURE_PATH);
- mockData = getJSONFixture(FIXTURE_PATH);
- mock = new MockAdapter(axios);
- mock.onGet(`${API_ENDPOINT}?per_page=100`).reply(200, mockData, { 'x-total': 2 });
-
- wrapper = mount(localVue.extend(RelatedMergeRequests), {
- localVue,
- store: createStore(),
- propsData: {
- endpoint: API_ENDPOINT,
- projectNamespace: 'gitlab-org',
- projectPath: 'gitlab-ce',
- },
- });
-
- setTimeout(done);
- });
-
- afterEach(() => {
- wrapper.destroy();
- mock.restore();
- });
-
- describe('methods', () => {
- describe('getAssignees', () => {
- const assignees = [{ name: 'foo' }, { name: 'bar' }];
-
- describe('when there is assignees array', () => {
- it('should return assignees array', () => {
- const mr = { assignees };
-
- expect(wrapper.vm.getAssignees(mr)).toEqual(assignees);
- });
- });
-
- it('should return an array with single assingee', () => {
- const mr = { assignee: assignees[0] };
-
- expect(wrapper.vm.getAssignees(mr)).toEqual([assignees[0]]);
- });
-
- it('should return empty array when assignee is not set', () => {
- expect(wrapper.vm.getAssignees({})).toEqual([]);
- expect(wrapper.vm.getAssignees({ assignee: null })).toEqual([]);
- });
- });
- });
-
- describe('template', () => {
- it('should render related merge request items', () => {
- expect(wrapper.find('.js-items-count').text()).toEqual('2');
- expect(wrapper.findAll(RelatedIssuableItem).length).toEqual(2);
-
- const props = wrapper
- .findAll(RelatedIssuableItem)
- .at(1)
- .props();
- const data = mockData[1];
-
- expect(props.idKey).toEqual(data.id);
- expect(props.pathIdSeparator).toEqual('!');
- expect(props.pipelineStatus).toBe(data.head_pipeline.detailed_status);
- expect(props.assignees).toEqual([data.assignee]);
- expect(props.isMergeRequest).toBe(true);
- expect(props.confidential).toEqual(false);
- expect(props.title).toEqual(data.title);
- expect(props.state).toEqual(data.state);
- expect(props.createdAt).toEqual(data.created_at);
- });
- });
-});
diff --git a/spec/javascripts/related_merge_requests/store/actions_spec.js b/spec/javascripts/related_merge_requests/store/actions_spec.js
deleted file mode 100644
index c4cd9f5f803..00000000000
--- a/spec/javascripts/related_merge_requests/store/actions_spec.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import testAction from 'spec/helpers/vuex_action_helper';
-import axios from '~/lib/utils/axios_utils';
-import * as types from '~/related_merge_requests/store/mutation_types';
-import actionsModule, * as actions from '~/related_merge_requests/store/actions';
-
-describe('RelatedMergeRequest store actions', () => {
- let state;
- let flashSpy;
- let mock;
-
- beforeEach(() => {
- state = {
- apiEndpoint: '/api/related_merge_requests',
- };
- flashSpy = spyOnDependency(actionsModule, 'createFlash');
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('setInitialState', () => {
- it('commits types.SET_INITIAL_STATE with given props', done => {
- const props = { a: 1, b: 2 };
-
- testAction(
- actions.setInitialState,
- props,
- {},
- [{ type: types.SET_INITIAL_STATE, payload: props }],
- [],
- done,
- );
- });
- });
-
- describe('requestData', () => {
- it('commits types.REQUEST_DATA', done => {
- testAction(actions.requestData, null, {}, [{ type: types.REQUEST_DATA }], [], done);
- });
- });
-
- describe('receiveDataSuccess', () => {
- it('commits types.RECEIVE_DATA_SUCCESS with data', done => {
- const data = { a: 1, b: 2 };
-
- testAction(
- actions.receiveDataSuccess,
- data,
- {},
- [{ type: types.RECEIVE_DATA_SUCCESS, payload: data }],
- [],
- done,
- );
- });
- });
-
- describe('receiveDataError', () => {
- it('commits types.RECEIVE_DATA_ERROR', done => {
- testAction(
- actions.receiveDataError,
- null,
- {},
- [{ type: types.RECEIVE_DATA_ERROR }],
- [],
- done,
- );
- });
- });
-
- describe('fetchMergeRequests', () => {
- describe('for a successful request', () => {
- it('should dispatch success action', done => {
- const data = { a: 1 };
- mock.onGet(`${state.apiEndpoint}?per_page=100`).replyOnce(200, data, { 'x-total': 2 });
-
- testAction(
- actions.fetchMergeRequests,
- null,
- state,
- [],
- [{ type: 'requestData' }, { type: 'receiveDataSuccess', payload: { data, total: 2 } }],
- done,
- );
- });
- });
-
- describe('for a failing request', () => {
- it('should dispatch error action', done => {
- mock.onGet(`${state.apiEndpoint}?per_page=100`).replyOnce(400);
-
- testAction(
- actions.fetchMergeRequests,
- null,
- state,
- [],
- [{ type: 'requestData' }, { type: 'receiveDataError' }],
- () => {
- expect(flashSpy).toHaveBeenCalledTimes(1);
- expect(flashSpy).toHaveBeenCalledWith(jasmine.stringMatching('Something went wrong'));
-
- done();
- },
- );
- });
- });
- });
-});
diff --git a/spec/javascripts/related_merge_requests/store/mutations_spec.js b/spec/javascripts/related_merge_requests/store/mutations_spec.js
deleted file mode 100644
index 21b6e26376b..00000000000
--- a/spec/javascripts/related_merge_requests/store/mutations_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import mutations from '~/related_merge_requests/store/mutations';
-import * as types from '~/related_merge_requests/store/mutation_types';
-
-describe('RelatedMergeRequests Store Mutations', () => {
- describe('SET_INITIAL_STATE', () => {
- it('should set initial state according to given data', () => {
- const apiEndpoint = '/api';
- const state = {};
-
- mutations[types.SET_INITIAL_STATE](state, { apiEndpoint });
-
- expect(state.apiEndpoint).toEqual(apiEndpoint);
- });
- });
-
- describe('REQUEST_DATA', () => {
- it('should set loading flag', () => {
- const state = {};
-
- mutations[types.REQUEST_DATA](state);
-
- expect(state.isFetchingMergeRequests).toEqual(true);
- });
- });
-
- describe('RECEIVE_DATA_SUCCESS', () => {
- it('should set loading flag and data', () => {
- const state = {};
- const mrs = [1, 2, 3];
-
- mutations[types.RECEIVE_DATA_SUCCESS](state, { data: mrs, total: mrs.length });
-
- expect(state.isFetchingMergeRequests).toEqual(false);
- expect(state.mergeRequests).toEqual(mrs);
- expect(state.totalCount).toEqual(mrs.length);
- });
- });
-
- describe('RECEIVE_DATA_ERROR', () => {
- it('should set loading and error flags', () => {
- const state = {};
-
- mutations[types.RECEIVE_DATA_ERROR](state);
-
- expect(state.isFetchingMergeRequests).toEqual(false);
- expect(state.hasErrorFetchingMergeRequests).toEqual(true);
- });
- });
-});
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index c869ff96933..701a97ba5a6 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -2,6 +2,6 @@
// file this one re-exports from. For more detail about why, see:
// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/31349
-import mockData from '../../../spec/frontend/sidebar/mock_data';
+import mockData from '../../frontend/sidebar/mock_data';
export default mockData;