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>2023-12-01 15:10:10 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-12-01 15:10:10 +0300
commit79c94e595b13bd4b4522e725e6096a41ff1a27ec (patch)
treebb55afb6b391b5d28683361024e47d175a18c8e9 /spec/frontend
parent17a47c3e305567151191ce166702bd4e35e62a7b (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r--spec/frontend/ci/job_details/store/actions_spec.js121
-rw-r--r--spec/frontend/frequent_items/components/app_spec.js286
-rw-r--r--spec/frontend/frequent_items/components/frequent_items_list_item_spec.js161
-rw-r--r--spec/frontend/frequent_items/components/frequent_items_list_spec.js121
-rw-r--r--spec/frontend/frequent_items/components/frequent_items_search_input_spec.js74
-rw-r--r--spec/frontend/frequent_items/mock_data.js169
-rw-r--r--spec/frontend/frequent_items/store/actions_spec.js304
-rw-r--r--spec/frontend/frequent_items/store/getters_spec.js24
-rw-r--r--spec/frontend/frequent_items/store/mutations_spec.js152
-rw-r--r--spec/frontend/frequent_items/utils_spec.js131
-rw-r--r--spec/frontend/import/details/components/bulk_import_details_app_spec.js14
-rw-r--r--spec/frontend/import_entities/import_groups/utils_spec.js2
-rw-r--r--spec/frontend/lib/utils/vuex_module_mappers_spec.js133
-rw-r--r--spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js2
-rw-r--r--spec/frontend/super_sidebar/mock_data.js29
-rw-r--r--spec/frontend/super_sidebar/utils_spec.js4
16 files changed, 118 insertions, 1609 deletions
diff --git a/spec/frontend/ci/job_details/store/actions_spec.js b/spec/frontend/ci/job_details/store/actions_spec.js
index 1a24bec092f..3e3e872f698 100644
--- a/spec/frontend/ci/job_details/store/actions_spec.js
+++ b/spec/frontend/ci/job_details/store/actions_spec.js
@@ -15,7 +15,6 @@ import {
fetchJobLog,
startPollingJobLog,
stopPollingJobLog,
- receiveJobLogSuccess,
receiveJobLogError,
toggleCollapsibleLine,
requestJobsForStage,
@@ -27,11 +26,15 @@ import {
toggleSidebar,
receiveTestSummarySuccess,
} from '~/ci/job_details/store/actions';
+import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
+
import * as types from '~/ci/job_details/store/mutation_types';
import state from '~/ci/job_details/store/state';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+jest.mock('~/lib/utils/scroll_utils');
+
describe('Job State actions', () => {
let mockedState;
@@ -212,42 +215,39 @@ describe('Job State actions', () => {
});
describe('success', () => {
- it('dispatches requestJobLog, receiveJobLogSuccess and stopPollingJobLog when job is complete', () => {
- mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, {
- html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
- complete: true,
+ let jobLogPayload;
+
+ beforeEach(() => {
+ isScrolledToBottom.mockReturnValue(false);
+ });
+
+ describe('when job is complete', () => {
+ beforeEach(() => {
+ jobLogPayload = {
+ html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
+ complete: true,
+ };
+
+ mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, jobLogPayload);
});
- return testAction(
- fetchJobLog,
- null,
- mockedState,
- [],
- [
- {
- type: 'toggleScrollisInBottom',
- payload: true,
- },
- {
- payload: {
- html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
- complete: true,
+ it('commits RECEIVE_JOB_LOG_SUCCESS, dispatches stopPollingJobLog and requestTestSummary', () => {
+ return testAction(
+ fetchJobLog,
+ null,
+ mockedState,
+ [
+ {
+ type: types.RECEIVE_JOB_LOG_SUCCESS,
+ payload: jobLogPayload,
},
- type: 'receiveJobLogSuccess',
- },
- {
- type: 'stopPollingJobLog',
- },
- {
- type: 'requestTestSummary',
- },
- ],
- );
+ ],
+ [{ type: 'stopPollingJobLog' }, { type: 'requestTestSummary' }],
+ );
+ });
});
describe('when job is incomplete', () => {
- let jobLogPayload;
-
beforeEach(() => {
jobLogPayload = {
html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
@@ -262,12 +262,13 @@ describe('Job State actions', () => {
fetchJobLog,
null,
mockedState,
- [],
[
- { type: 'toggleScrollisInBottom', payload: true },
- { type: 'receiveJobLogSuccess', payload: jobLogPayload },
- { type: 'startPollingJobLog' },
+ {
+ type: types.RECEIVE_JOB_LOG_SUCCESS,
+ payload: jobLogPayload,
+ },
],
+ [{ type: 'startPollingJobLog' }],
);
});
@@ -278,10 +279,44 @@ describe('Job State actions', () => {
fetchJobLog,
null,
mockedState,
+ [
+ {
+ type: types.RECEIVE_JOB_LOG_SUCCESS,
+ payload: jobLogPayload,
+ },
+ ],
[],
+ );
+ });
+ });
+
+ describe('when user scrolled to the bottom', () => {
+ beforeEach(() => {
+ isScrolledToBottom.mockReturnValue(true);
+
+ jobLogPayload = {
+ html: 'I, [2018-08-17T22:57:45.707325 #1841] INFO -- :',
+ complete: true,
+ };
+
+ mock.onGet(`${TEST_HOST}/endpoint/trace.json`).replyOnce(HTTP_STATUS_OK, jobLogPayload);
+ });
+
+ it('should auto scroll to bottom by dispatching scrollBottom', () => {
+ return testAction(
+ fetchJobLog,
+ null,
+ mockedState,
[
- { type: 'toggleScrollisInBottom', payload: true },
- { type: 'receiveJobLogSuccess', payload: jobLogPayload },
+ {
+ type: types.RECEIVE_JOB_LOG_SUCCESS,
+ payload: jobLogPayload,
+ },
+ ],
+ [
+ { type: 'stopPollingJobLog' },
+ { type: 'requestTestSummary' },
+ { type: 'scrollBottom' },
],
);
});
@@ -393,18 +428,6 @@ describe('Job State actions', () => {
});
});
- describe('receiveJobLogSuccess', () => {
- it('should commit RECEIVE_JOB_LOG_SUCCESS mutation', () => {
- return testAction(
- receiveJobLogSuccess,
- 'hello world',
- mockedState,
- [{ type: types.RECEIVE_JOB_LOG_SUCCESS, payload: 'hello world' }],
- [],
- );
- });
- });
-
describe('receiveJobLogError', () => {
it('should commit stop polling job log', () => {
return testAction(receiveJobLogError, null, mockedState, [], [{ type: 'stopPollingJobLog' }]);
diff --git a/spec/frontend/frequent_items/components/app_spec.js b/spec/frontend/frequent_items/components/app_spec.js
deleted file mode 100644
index 122155a5d3f..00000000000
--- a/spec/frontend/frequent_items/components/app_spec.js
+++ /dev/null
@@ -1,286 +0,0 @@
-import { GlButton, GlIcon } from '@gitlab/ui';
-import MockAdapter from 'axios-mock-adapter';
-import Vue, { nextTick } from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import App from '~/frequent_items/components/app.vue';
-import FrequentItemsList from '~/frequent_items/components/frequent_items_list.vue';
-import { FREQUENT_ITEMS, FIFTEEN_MINUTES_IN_MS } from '~/frequent_items/constants';
-import eventHub from '~/frequent_items/event_hub';
-import { createStore } from '~/frequent_items/store';
-import { getTopFrequentItems } from '~/frequent_items/utils';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { currentSession, mockFrequentProjects, mockSearchedProjects } from '../mock_data';
-
-Vue.use(Vuex);
-
-useLocalStorageSpy();
-
-const TEST_NAMESPACE = 'projects';
-const TEST_VUEX_MODULE = 'frequentProjects';
-const TEST_PROJECT = currentSession[TEST_NAMESPACE].project;
-const TEST_STORAGE_KEY = currentSession[TEST_NAMESPACE].storageKey;
-const TEST_SEARCH_CLASS = 'test-search-class';
-
-describe('Frequent Items App Component', () => {
- let wrapper;
- let mock;
- let store;
-
- const createComponent = (props = {}) => {
- const session = currentSession[TEST_NAMESPACE];
- gon.api_version = session.apiVersion;
-
- wrapper = mountExtended(App, {
- store,
- propsData: {
- namespace: TEST_NAMESPACE,
- currentUserName: session.username,
- currentItem: session.project,
- ...props,
- },
- provide: {
- vuexModule: TEST_VUEX_MODULE,
- },
- });
- };
-
- const triggerDropdownOpen = () => eventHub.$emit(`${TEST_NAMESPACE}-dropdownOpen`);
- const getStoredProjects = () => JSON.parse(localStorage.getItem(TEST_STORAGE_KEY));
- const findSearchInput = () => wrapper.findByTestId('frequent-items-search-input');
- const findLoading = () => wrapper.findByTestId('loading');
- const findSectionHeader = () => wrapper.findByTestId('header');
- const findFrequentItemsList = () => wrapper.findComponent(FrequentItemsList);
- const findFrequentItems = () => findFrequentItemsList().findAll('li');
- const setSearch = (search) => {
- const searchInput = wrapper.find('input');
-
- searchInput.setValue(search);
- };
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- store = createStore();
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('default', () => {
- beforeEach(() => {
- jest.spyOn(store, 'dispatch');
-
- createComponent();
- });
-
- it('should fetch frequent items', () => {
- triggerDropdownOpen();
-
- expect(store.dispatch).toHaveBeenCalledWith(`${TEST_VUEX_MODULE}/fetchFrequentItems`);
- });
-
- it('should not fetch frequent items if detroyed', () => {
- wrapper.destroy();
- triggerDropdownOpen();
-
- expect(store.dispatch).not.toHaveBeenCalledWith(`${TEST_VUEX_MODULE}/fetchFrequentItems`);
- });
-
- it('should render search input', () => {
- expect(findSearchInput().classes()).toEqual(['search-input-container']);
- });
-
- it('should render loading animation', async () => {
- triggerDropdownOpen();
- store.state[TEST_VUEX_MODULE].isLoadingItems = true;
-
- await nextTick();
-
- const loading = findLoading();
-
- expect(loading.exists()).toBe(true);
- expect(loading.find('[aria-label="Loading projects"]').exists()).toBe(true);
- expect(findSectionHeader().exists()).toBe(false);
- });
-
- it('should render frequent projects list header', () => {
- const sectionHeader = findSectionHeader();
-
- expect(sectionHeader.exists()).toBe(true);
- expect(sectionHeader.text()).toBe('Frequently visited');
- });
-
- it('should render searched projects list', async () => {
- mock
- .onGet(/\/api\/v4\/projects.json(.*)$/)
- .replyOnce(HTTP_STATUS_OK, mockSearchedProjects.data);
-
- setSearch('gitlab');
- await nextTick();
-
- expect(findLoading().exists()).toBe(true);
-
- await waitForPromises();
-
- expect(findFrequentItems().length).toBe(mockSearchedProjects.data.length);
- expect(findFrequentItemsList().props()).toEqual(
- expect.objectContaining({
- items: mockSearchedProjects.data.map(
- ({
- avatar_url: avatarUrl,
- web_url: webUrl,
- name_with_namespace: namespace,
- ...item
- }) => ({
- ...item,
- avatarUrl,
- webUrl,
- namespace,
- }),
- ),
- namespace: TEST_NAMESPACE,
- hasSearchQuery: true,
- isFetchFailed: false,
- matcher: 'gitlab',
- }),
- );
- });
-
- describe('with frequent items list', () => {
- const expectedResult = getTopFrequentItems(mockFrequentProjects);
-
- beforeEach(async () => {
- localStorage.setItem(TEST_STORAGE_KEY, JSON.stringify(mockFrequentProjects));
- triggerDropdownOpen();
- await nextTick();
- });
-
- it('should render edit button within header', () => {
- const itemEditButton = findSectionHeader().findComponent(GlButton);
-
- expect(itemEditButton.exists()).toBe(true);
- expect(itemEditButton.attributes('title')).toBe('Toggle edit mode');
- expect(itemEditButton.findComponent(GlIcon).props('name')).toBe('pencil');
- });
-
- it('should render frequent projects list', () => {
- expect(findFrequentItems().length).toBe(expectedResult.length);
- expect(findFrequentItemsList().props()).toEqual({
- items: expectedResult,
- namespace: TEST_NAMESPACE,
- hasSearchQuery: false,
- isFetchFailed: false,
- isItemRemovalFailed: false,
- matcher: '',
- });
- });
-
- it('dispatches action `toggleItemsListEditablity` when edit button is clicked', async () => {
- const itemEditButton = findSectionHeader().findComponent(GlButton);
- itemEditButton.vm.$emit('click');
-
- await nextTick();
-
- expect(store.dispatch).toHaveBeenCalledWith(
- `${TEST_VUEX_MODULE}/toggleItemsListEditablity`,
- );
- });
- });
- });
-
- describe('with searchClass', () => {
- beforeEach(() => {
- createComponent({ searchClass: TEST_SEARCH_CLASS });
- });
-
- it('should render search input with searchClass', () => {
- expect(findSearchInput().classes()).toEqual(['search-input-container', TEST_SEARCH_CLASS]);
- });
- });
-
- describe('logging', () => {
- it('when created, it should create a project storage entry and adds a project', () => {
- createComponent();
-
- expect(getStoredProjects()).toEqual([
- expect.objectContaining({
- frequency: 1,
- lastAccessedOn: Date.now(),
- }),
- ]);
- });
-
- describe('when created multiple times', () => {
- beforeEach(() => {
- createComponent();
- wrapper.destroy();
- createComponent();
- wrapper.destroy();
- });
-
- it('should only log once', () => {
- expect(getStoredProjects()).toEqual([
- expect.objectContaining({
- lastAccessedOn: Date.now(),
- frequency: 1,
- }),
- ]);
- });
-
- it('should increase frequency, when created 15 minutes later', () => {
- const fifteenMinutesLater = Date.now() + FIFTEEN_MINUTES_IN_MS + 1;
-
- jest.spyOn(Date, 'now').mockReturnValue(fifteenMinutesLater);
- createComponent({ currentItem: { ...TEST_PROJECT, lastAccessedOn: fifteenMinutesLater } });
-
- expect(getStoredProjects()).toEqual([
- expect.objectContaining({
- lastAccessedOn: fifteenMinutesLater,
- frequency: 2,
- }),
- ]);
- });
- });
-
- it('should always update project metadata', () => {
- const oldProject = {
- ...TEST_PROJECT,
- };
-
- const newProject = {
- ...oldProject,
- name: 'New Name',
- avatarUrl: 'new/avatar.png',
- namespace: 'New / Namespace',
- webUrl: 'http://localhost/new/web/url',
- };
-
- createComponent({ currentItem: oldProject });
- wrapper.destroy();
- expect(getStoredProjects()).toEqual([expect.objectContaining(oldProject)]);
-
- createComponent({ currentItem: newProject });
- wrapper.destroy();
-
- expect(getStoredProjects()).toEqual([expect.objectContaining(newProject)]);
- });
-
- it('should not add more than 20 projects in store', () => {
- for (let id = 0; id < FREQUENT_ITEMS.MAX_COUNT + 10; id += 1) {
- const project = {
- ...TEST_PROJECT,
- id,
- };
- createComponent({ currentItem: project });
- wrapper.destroy();
- }
-
- expect(getStoredProjects().length).toBe(FREQUENT_ITEMS.MAX_COUNT);
- });
- });
-});
diff --git a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js
deleted file mode 100644
index 55d20ad603c..00000000000
--- a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js
+++ /dev/null
@@ -1,161 +0,0 @@
-import { GlIcon } from '@gitlab/ui';
-import Vue, { nextTick } from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { trimText } from 'helpers/text_helper';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue';
-import { createStore } from '~/frequent_items/store';
-import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
-import { mockProject } from '../mock_data';
-
-Vue.use(Vuex);
-
-describe('FrequentItemsListItemComponent', () => {
- const TEST_VUEX_MODULE = 'frequentProjects';
- let wrapper;
- let trackingSpy;
- let store;
-
- const findTitle = () => wrapper.findByTestId('frequent-items-item-title');
- const findAvatar = () => wrapper.findComponent(ProjectAvatar);
- const findAllTitles = () => wrapper.findAllByTestId('frequent-items-item-title');
- const findNamespace = () => wrapper.findByTestId('frequent-items-item-namespace');
- const findAllFrequentItems = () => wrapper.findAllByTestId('frequent-item-link');
- const findAllNamespace = () => wrapper.findAllByTestId('frequent-items-item-namespace');
- const findAllAvatars = () => wrapper.findAllComponents(ProjectAvatar);
- const findAllMetadataContainers = () =>
- wrapper.findAllByTestId('frequent-items-item-metadata-container');
- const findRemoveButton = () => wrapper.findByTestId('item-remove');
-
- const toggleItemsListEditablity = async () => {
- store.dispatch(`${TEST_VUEX_MODULE}/toggleItemsListEditablity`);
-
- await nextTick();
- };
-
- const createComponent = (props = {}) => {
- wrapper = shallowMountExtended(frequentItemsListItemComponent, {
- store,
- propsData: {
- itemId: mockProject.id,
- itemName: mockProject.name,
- namespace: mockProject.namespace,
- webUrl: mockProject.webUrl,
- avatarUrl: mockProject.avatarUrl,
- ...props,
- },
- provide: {
- vuexModule: TEST_VUEX_MODULE,
- },
- });
- };
-
- beforeEach(() => {
- store = createStore();
- trackingSpy = mockTracking('_category_', document, jest.spyOn);
- trackingSpy.mockImplementation(() => {});
- });
-
- afterEach(() => {
- unmockTracking();
- });
-
- describe('computed', () => {
- describe('highlightedItemName', () => {
- it('should enclose part of project name in <b> & </b> which matches with `matcher` prop', () => {
- createComponent({ matcher: 'lab' });
-
- expect(findTitle().element.innerHTML).toContain('<b>L</b><b>a</b><b>b</b>');
- });
-
- it('should return project name as it is if `matcher` is not available', () => {
- createComponent({ matcher: null });
-
- expect(trimText(findTitle().text())).toBe(mockProject.name);
- });
- });
-
- describe('truncatedNamespace', () => {
- it('should truncate project name from namespace string', () => {
- createComponent({ namespace: 'platform / nokia-3310' });
-
- expect(trimText(findNamespace().text())).toBe('platform');
- });
-
- it('should truncate namespace string from the middle if it includes more than two groups in path', () => {
- createComponent({
- namespace: 'platform / hardware / broadcom / Wifi Group / Mobile Chipset / nokia-3310',
- });
-
- expect(trimText(findNamespace().text())).toBe('platform / ... / Mobile Chipset');
- });
- });
- });
-
- describe('template', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders avatar', () => {
- expect(findAvatar().exists()).toBe(true);
- });
-
- it('renders root element with the right classes', () => {
- expect(wrapper.classes('frequent-items-list-item-container')).toBe(true);
- });
-
- it.each`
- name | selector | expected
- ${'list item'} | ${findAllFrequentItems} | ${1}
- ${'avatar container'} | ${findAllAvatars} | ${1}
- ${'metadata container'} | ${findAllMetadataContainers} | ${1}
- ${'title'} | ${findAllTitles} | ${1}
- ${'namespace'} | ${findAllNamespace} | ${1}
- `('should render $expected $name', ({ selector, expected }) => {
- expect(selector()).toHaveLength(expected);
- });
-
- it('renders remove button within item when `isItemsListEditable` is true', async () => {
- await toggleItemsListEditablity();
-
- const removeButton = findRemoveButton();
- expect(removeButton.exists()).toBe(true);
- expect(removeButton.attributes('title')).toBe('Remove');
- expect(removeButton.findComponent(GlIcon).props('name')).toBe('close');
- });
-
- it('dispatches action `removeFrequentItem` when remove button is clicked', async () => {
- await toggleItemsListEditablity();
-
- jest.spyOn(store, 'dispatch');
-
- const removeButton = findRemoveButton();
- removeButton.vm.$emit(
- 'click',
- { stopPropagation: jest.fn(), preventDefault: jest.fn() },
- mockProject.id,
- );
-
- await nextTick();
-
- expect(store.dispatch).toHaveBeenCalledWith(
- `${TEST_VUEX_MODULE}/removeFrequentItem`,
- mockProject.id,
- );
- });
-
- it('tracks when item link is clicked', () => {
- const link = wrapper.findByTestId('frequent-item-link');
-
- link.vm.$emit('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_link', {
- label: 'projects_dropdown_frequent_items_list_item',
- property: 'navigation_top',
- });
- });
- });
-});
diff --git a/spec/frontend/frequent_items/components/frequent_items_list_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_spec.js
deleted file mode 100644
index 8055b7a9c13..00000000000
--- a/spec/frontend/frequent_items/components/frequent_items_list_spec.js
+++ /dev/null
@@ -1,121 +0,0 @@
-import Vue, { nextTick } from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import frequentItemsListComponent from '~/frequent_items/components/frequent_items_list.vue';
-import frequentItemsListItemComponent from '~/frequent_items/components/frequent_items_list_item.vue';
-import { createStore } from '~/frequent_items/store';
-import { mockFrequentProjects } from '../mock_data';
-
-Vue.use(Vuex);
-
-describe('FrequentItemsListComponent', () => {
- let wrapper;
-
- const createComponent = (props = {}) => {
- wrapper = mountExtended(frequentItemsListComponent, {
- store: createStore(),
- propsData: {
- namespace: 'projects',
- items: mockFrequentProjects,
- isFetchFailed: false,
- isItemRemovalFailed: false,
- hasSearchQuery: false,
- matcher: 'lab',
- ...props,
- },
- provide: {
- vuexModule: 'frequentProjects',
- },
- });
- };
-
- describe('computed', () => {
- describe('isListEmpty', () => {
- it('should return `true` or `false` representing whether if `items` is empty or not with projects', async () => {
- createComponent({
- items: [],
- });
-
- expect(wrapper.vm.isListEmpty).toBe(true);
-
- wrapper.setProps({
- items: mockFrequentProjects,
- });
- await nextTick();
-
- expect(wrapper.vm.isListEmpty).toBe(false);
- });
- });
-
- describe('fetched item messages', () => {
- it('should show default empty list message', () => {
- createComponent({
- items: [],
- });
-
- expect(wrapper.findByTestId('frequent-items-list-empty').text()).toContain(
- 'Projects you visit often will appear here',
- );
- });
-
- it.each`
- isFetchFailed | isItemRemovalFailed
- ${true} | ${false}
- ${false} | ${true}
- `(
- 'should show failure message when `isFetchFailed` is $isFetchFailed or `isItemRemovalFailed` is $isItemRemovalFailed',
- ({ isFetchFailed, isItemRemovalFailed }) => {
- createComponent({
- items: [],
- isFetchFailed,
- isItemRemovalFailed,
- });
-
- expect(wrapper.findByTestId('frequent-items-list-empty').text()).toContain(
- 'This feature requires browser localStorage support',
- );
- },
- );
- });
-
- describe('searched item messages', () => {
- it('should return appropriate empty list message based on value of `searchFailed` prop with projects', async () => {
- createComponent({
- hasSearchQuery: true,
- isFetchFailed: true,
- });
-
- expect(wrapper.vm.listEmptyMessage).toBe('Something went wrong on our end.');
-
- wrapper.setProps({
- isFetchFailed: false,
- });
- await nextTick();
-
- expect(wrapper.vm.listEmptyMessage).toBe('Sorry, no projects matched your search');
- });
- });
- });
-
- describe('template', () => {
- it('should render component element with list of projects', async () => {
- createComponent();
-
- await nextTick();
- expect(wrapper.classes('frequent-items-list-container')).toBe(true);
- expect(wrapper.findAllByTestId('frequent-items-list')).toHaveLength(1);
- expect(wrapper.findAllComponents(frequentItemsListItemComponent)).toHaveLength(5);
- });
-
- it('should render component element with empty message', async () => {
- createComponent({
- items: [],
- });
-
- await nextTick();
- expect(wrapper.vm.$el.querySelectorAll('li.section-empty')).toHaveLength(1);
- expect(wrapper.findAllComponents(frequentItemsListItemComponent)).toHaveLength(0);
- });
- });
-});
diff --git a/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js b/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js
deleted file mode 100644
index d6aa0f4e221..00000000000
--- a/spec/frontend/frequent_items/components/frequent_items_search_input_spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import { GlSearchBoxByType } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import searchComponent from '~/frequent_items/components/frequent_items_search_input.vue';
-import { createStore } from '~/frequent_items/store';
-
-Vue.use(Vuex);
-
-describe('FrequentItemsSearchInputComponent', () => {
- let wrapper;
- let trackingSpy;
- let vm;
- let store;
-
- const createComponent = (namespace = 'projects') =>
- shallowMount(searchComponent, {
- store,
- propsData: { namespace },
- provide: {
- vuexModule: 'frequentProjects',
- },
- });
-
- const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
-
- beforeEach(() => {
- store = createStore();
- jest.spyOn(store, 'dispatch').mockImplementation(() => {});
-
- trackingSpy = mockTracking('_category_', document, jest.spyOn);
- trackingSpy.mockImplementation(() => {});
-
- wrapper = createComponent();
-
- ({ vm } = wrapper);
- });
-
- afterEach(() => {
- unmockTracking();
- vm.$destroy();
- });
-
- describe('template', () => {
- it('should render component element', () => {
- expect(wrapper.classes()).toContain('search-input-container');
- expect(findSearchBoxByType().exists()).toBe(true);
- expect(findSearchBoxByType().attributes()).toMatchObject({
- placeholder: 'Search your projects',
- });
- });
- });
-
- describe('tracking', () => {
- it('tracks when search query is entered', async () => {
- expect(trackingSpy).not.toHaveBeenCalled();
- expect(store.dispatch).not.toHaveBeenCalled();
-
- const value = 'my project';
-
- findSearchBoxByType().vm.$emit('input', value);
-
- await nextTick();
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'type_search_query', {
- label: 'projects_dropdown_frequent_items_search_input',
- property: 'navigation_top',
- });
- expect(store.dispatch).toHaveBeenCalledWith('frequentProjects/setSearchQuery', value);
- });
- });
-});
diff --git a/spec/frontend/frequent_items/mock_data.js b/spec/frontend/frequent_items/mock_data.js
deleted file mode 100644
index 6563daee6c3..00000000000
--- a/spec/frontend/frequent_items/mock_data.js
+++ /dev/null
@@ -1,169 +0,0 @@
-import { TEST_HOST } from 'helpers/test_constants';
-
-export const currentSession = {
- groups: {
- username: 'root',
- storageKey: 'root/frequent-groups',
- apiVersion: 'v4',
- group: {
- id: 1,
- name: 'dummy-group',
- full_name: 'dummy-parent-group',
- webUrl: `${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: `${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: `${TEST_HOST}/Commit451/Sub451`,
- avatarUrl: null,
-};
-
-export const mockRawGroup = {
- id: 1,
- name: 'Sub451',
- full_name: 'Commit451 / Sub451',
- web_url: `${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 = { data: [mockRawGroup] };
-export const mockProcessedSearchedGroups = [mockGroup];
-
-export const mockProject = {
- id: 1,
- name: 'GitLab Community Edition',
- namespace: 'gitlab-org / gitlab-ce',
- webUrl: `${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: `${TEST_HOST}/gitlab-org/gitlab-foss`,
- avatar_url: null,
-};
-
-export const mockFrequentProjects = [
- {
- id: 1,
- name: 'GitLab Community Edition',
- namespace: 'gitlab-org / gitlab-ce',
- webUrl: `${TEST_HOST}/gitlab-org/gitlab-foss`,
- avatarUrl: null,
- frequency: 1,
- lastAccessedOn: Date.now(),
- },
- {
- id: 2,
- name: 'GitLab CI',
- namespace: 'gitlab-org / gitlab-ci',
- webUrl: `${TEST_HOST}/gitlab-org/gitlab-ci`,
- avatarUrl: null,
- frequency: 9,
- lastAccessedOn: Date.now(),
- },
- {
- id: 3,
- name: 'Typeahead.Js',
- namespace: 'twitter / typeahead-js',
- webUrl: `${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: `${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: `${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/frontend/frequent_items/store/actions_spec.js b/spec/frontend/frequent_items/store/actions_spec.js
deleted file mode 100644
index 2feb488da2c..00000000000
--- a/spec/frontend/frequent_items/store/actions_spec.js
+++ /dev/null
@@ -1,304 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import testAction from 'helpers/vuex_action_helper';
-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 AccessorUtilities from '~/lib/utils/accessor';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-import {
- mockNamespace,
- mockStorageKey,
- mockFrequentProjects,
- mockSearchedProjects,
-} from '../mock_data';
-
-describe('Frequent Items Dropdown Store Actions', () => {
- useLocalStorageSpy();
- 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', () => {
- return testAction(
- actions.setNamespace,
- mockNamespace,
- mockedState,
- [{ type: types.SET_NAMESPACE, payload: mockNamespace }],
- [],
- );
- });
- });
-
- describe('setStorageKey', () => {
- it('should set storage key', () => {
- return testAction(
- actions.setStorageKey,
- mockStorageKey,
- mockedState,
- [{ type: types.SET_STORAGE_KEY, payload: mockStorageKey }],
- [],
- );
- });
- });
-
- describe('toggleItemsListEditablity', () => {
- it('should toggle items list editablity', () => {
- return testAction(
- actions.toggleItemsListEditablity,
- null,
- mockedState,
- [{ type: types.TOGGLE_ITEMS_LIST_EDITABILITY }],
- [],
- );
- });
- });
-
- describe('requestFrequentItems', () => {
- it('should request frequent items', () => {
- return testAction(
- actions.requestFrequentItems,
- null,
- mockedState,
- [{ type: types.REQUEST_FREQUENT_ITEMS }],
- [],
- );
- });
- });
-
- describe('receiveFrequentItemsSuccess', () => {
- it('should set frequent items', () => {
- return testAction(
- actions.receiveFrequentItemsSuccess,
- mockFrequentProjects,
- mockedState,
- [{ type: types.RECEIVE_FREQUENT_ITEMS_SUCCESS, payload: mockFrequentProjects }],
- [],
- );
- });
- });
-
- describe('receiveFrequentItemsError', () => {
- it('should set frequent items error state', () => {
- return testAction(
- actions.receiveFrequentItemsError,
- null,
- mockedState,
- [{ type: types.RECEIVE_FREQUENT_ITEMS_ERROR }],
- [],
- );
- });
- });
-
- describe('fetchFrequentItems', () => {
- it('should dispatch `receiveFrequentItemsSuccess`', () => {
- mockedState.namespace = mockNamespace;
- mockedState.storageKey = mockStorageKey;
-
- return testAction(
- actions.fetchFrequentItems,
- null,
- mockedState,
- [],
- [{ type: 'requestFrequentItems' }, { type: 'receiveFrequentItemsSuccess', payload: [] }],
- );
- });
-
- it('should dispatch `receiveFrequentItemsError`', () => {
- jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(false);
- mockedState.namespace = mockNamespace;
- mockedState.storageKey = mockStorageKey;
-
- return testAction(
- actions.fetchFrequentItems,
- null,
- mockedState,
- [],
- [{ type: 'requestFrequentItems' }, { type: 'receiveFrequentItemsError' }],
- );
- });
- });
-
- describe('requestSearchedItems', () => {
- it('should request searched items', () => {
- return testAction(
- actions.requestSearchedItems,
- null,
- mockedState,
- [{ type: types.REQUEST_SEARCHED_ITEMS }],
- [],
- );
- });
- });
-
- describe('receiveSearchedItemsSuccess', () => {
- it('should set searched items', () => {
- return testAction(
- actions.receiveSearchedItemsSuccess,
- mockSearchedProjects,
- mockedState,
- [{ type: types.RECEIVE_SEARCHED_ITEMS_SUCCESS, payload: mockSearchedProjects }],
- [],
- );
- });
- });
-
- describe('receiveSearchedItemsError', () => {
- it('should set searched items error state', () => {
- return testAction(
- actions.receiveSearchedItemsError,
- null,
- mockedState,
- [{ type: types.RECEIVE_SEARCHED_ITEMS_ERROR }],
- [],
- );
- });
- });
-
- describe('fetchSearchedItems', () => {
- beforeEach(() => {
- gon.api_version = 'v4';
- });
-
- it('should dispatch `receiveSearchedItemsSuccess`', () => {
- mock
- .onGet(/\/api\/v4\/projects.json(.*)$/)
- .replyOnce(HTTP_STATUS_OK, mockSearchedProjects, {});
-
- return testAction(
- actions.fetchSearchedItems,
- null,
- mockedState,
- [],
- [
- { type: 'requestSearchedItems' },
- {
- type: 'receiveSearchedItemsSuccess',
- payload: { data: mockSearchedProjects, headers: {} },
- },
- ],
- );
- });
-
- it('should dispatch `receiveSearchedItemsError`', () => {
- gon.api_version = 'v4';
- mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
-
- return testAction(
- actions.fetchSearchedItems,
- null,
- mockedState,
- [],
- [{ type: 'requestSearchedItems' }, { type: 'receiveSearchedItemsError' }],
- );
- });
- });
-
- describe('setSearchQuery', () => {
- it('should commit query and dispatch `fetchSearchedItems` when query is present', () => {
- return testAction(
- actions.setSearchQuery,
- { query: 'test' },
- mockedState,
- [{ type: types.SET_SEARCH_QUERY, payload: { query: 'test' } }],
- [{ type: 'fetchSearchedItems', payload: { query: 'test' } }],
- );
- });
-
- it('should commit query and dispatch `fetchFrequentItems` when query is empty', () => {
- return testAction(
- actions.setSearchQuery,
- null,
- mockedState,
- [{ type: types.SET_SEARCH_QUERY, payload: null }],
- [{ type: 'fetchFrequentItems' }],
- );
- });
- });
-
- describe('removeFrequentItemSuccess', () => {
- it('should remove frequent item on success', () => {
- return testAction(
- actions.removeFrequentItemSuccess,
- { itemId: 1 },
- mockedState,
- [
- {
- type: types.RECEIVE_REMOVE_FREQUENT_ITEM_SUCCESS,
- payload: { itemId: 1 },
- },
- ],
- [],
- );
- });
- });
-
- describe('removeFrequentItemError', () => {
- it('should should not remove frequent item on failure', () => {
- return testAction(
- actions.removeFrequentItemError,
- null,
- mockedState,
- [{ type: types.RECEIVE_REMOVE_FREQUENT_ITEM_ERROR }],
- [],
- );
- });
- });
-
- describe('removeFrequentItem', () => {
- beforeEach(() => {
- mockedState.items = [...mockFrequentProjects];
- window.localStorage.setItem(mockStorageKey, JSON.stringify(mockFrequentProjects));
- });
-
- it('should remove provided itemId from localStorage', () => {
- jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(true);
-
- actions.removeFrequentItem(
- { commit: jest.fn(), dispatch: jest.fn(), state: mockedState },
- mockFrequentProjects[0].id,
- );
-
- expect(window.localStorage.getItem(mockStorageKey)).toBe(
- JSON.stringify(mockFrequentProjects.slice(1)), // First item was removed
- );
- });
-
- it('should dispatch `removeFrequentItemSuccess` on localStorage update success', () => {
- jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(true);
-
- return testAction(
- actions.removeFrequentItem,
- mockFrequentProjects[0].id,
- mockedState,
- [],
- [{ type: 'removeFrequentItemSuccess', payload: mockFrequentProjects[0].id }],
- );
- });
-
- it('should dispatch `removeFrequentItemError` on localStorage update failure', () => {
- jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(false);
-
- return testAction(
- actions.removeFrequentItem,
- mockFrequentProjects[0].id,
- mockedState,
- [],
- [{ type: 'removeFrequentItemError' }],
- );
- });
- });
-});
diff --git a/spec/frontend/frequent_items/store/getters_spec.js b/spec/frontend/frequent_items/store/getters_spec.js
deleted file mode 100644
index 97732cd95fc..00000000000
--- a/spec/frontend/frequent_items/store/getters_spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import * as getters from '~/frequent_items/store/getters';
-import state from '~/frequent_items/store/state';
-
-describe('Frequent Items Dropdown Store Getters', () => {
- let mockedState;
-
- beforeEach(() => {
- mockedState = state();
- });
-
- describe('hasSearchQuery', () => {
- it('should return `true` when search query is present', () => {
- mockedState.searchQuery = 'test';
-
- expect(getters.hasSearchQuery(mockedState)).toBe(true);
- });
-
- it('should return `false` when search query is empty', () => {
- mockedState.searchQuery = '';
-
- expect(getters.hasSearchQuery(mockedState)).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/frequent_items/store/mutations_spec.js b/spec/frontend/frequent_items/store/mutations_spec.js
deleted file mode 100644
index 1e1878c3377..00000000000
--- a/spec/frontend/frequent_items/store/mutations_spec.js
+++ /dev/null
@@ -1,152 +0,0 @@
-import * as types from '~/frequent_items/store/mutation_types';
-import mutations from '~/frequent_items/store/mutations';
-import state from '~/frequent_items/store/state';
-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('TOGGLE_ITEMS_LIST_EDITABILITY', () => {
- it('should toggle items list editablity', () => {
- mutations[types.TOGGLE_ITEMS_LIST_EDITABILITY](stateCopy);
-
- expect(stateCopy.isItemsListEditable).toEqual(true);
-
- mutations[types.TOGGLE_ITEMS_LIST_EDITABILITY](stateCopy);
-
- expect(stateCopy.isItemsListEditable).toEqual(false);
- });
- });
-
- 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);
- });
- });
-
- describe('RECEIVE_REMOVE_FREQUENT_ITEM_SUCCESS', () => {
- it('should remove item with provided itemId from the items', () => {
- stateCopy.isItemRemovalFailed = true;
- stateCopy.items = mockFrequentProjects;
-
- mutations[types.RECEIVE_REMOVE_FREQUENT_ITEM_SUCCESS](stateCopy, mockFrequentProjects[0].id);
-
- expect(stateCopy.items).toHaveLength(mockFrequentProjects.length - 1);
- expect(stateCopy.items).toEqual([...mockFrequentProjects.slice(1)]);
- expect(stateCopy.isItemRemovalFailed).toBe(false);
- });
- });
-
- describe('RECEIVE_REMOVE_FREQUENT_ITEM_ERROR', () => {
- it('should remove item with provided itemId from the items', () => {
- stateCopy.isItemRemovalFailed = false;
-
- mutations[types.RECEIVE_REMOVE_FREQUENT_ITEM_ERROR](stateCopy);
-
- expect(stateCopy.isItemRemovalFailed).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/frequent_items/utils_spec.js b/spec/frontend/frequent_items/utils_spec.js
deleted file mode 100644
index 8d4c89bd48f..00000000000
--- a/spec/frontend/frequent_items/utils_spec.js
+++ /dev/null
@@ -1,131 +0,0 @@
-import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
-import { FIFTEEN_MINUTES_IN_MS, FREQUENT_ITEMS } from '~/frequent_items/constants';
-import {
- isMobile,
- getTopFrequentItems,
- updateExistingFrequentItem,
- sanitizeItem,
-} from '~/frequent_items/utils';
-import { mockProject, unsortedFrequentItems, sortedFrequentItems } from './mock_data';
-
-describe('Frequent Items utils spec', () => {
- describe('isMobile', () => {
- it('returns true when the screen is medium', () => {
- jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('md');
-
- expect(isMobile()).toBe(true);
- });
-
- it('returns true when the screen is small', () => {
- jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('sm');
-
- expect(isMobile()).toBe(true);
- });
-
- it('returns true when the screen is extra-small', () => {
- jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('xs');
-
- expect(isMobile()).toBe(true);
- });
-
- it('returns false when the screen is larger than medium', () => {
- jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('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', () => {
- jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('md');
- const result = getTopFrequentItems(unsortedFrequentItems);
-
- expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_MOBILE);
- });
-
- it('returns correct amount of items for desktop', () => {
- jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('xl');
- const result = getTopFrequentItems(unsortedFrequentItems);
-
- expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_DESKTOP);
- });
-
- it('sorts frequent items in order of frequency and lastAccessedOn', () => {
- jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('xl');
- const result = getTopFrequentItems(unsortedFrequentItems);
- const expectedResult = sortedFrequentItems.slice(0, FREQUENT_ITEMS.LIST_COUNT_DESKTOP);
-
- expect(result).toEqual(expectedResult);
- });
- });
-
- describe('updateExistingFrequentItem', () => {
- const LAST_ACCESSED = 1497979281815;
- const WITHIN_FIFTEEN_MINUTES = LAST_ACCESSED + FIFTEEN_MINUTES_IN_MS;
- const OVER_FIFTEEN_MINUTES = WITHIN_FIFTEEN_MINUTES + 1;
- const EXISTING_ITEM = Object.freeze({
- ...mockProject,
- frequency: 1,
- lastAccessedOn: 1497979281815,
- });
-
- it.each`
- desc | existingProps | newProps | expected
- ${'updates item if accessed over 15 minutes ago'} | ${{}} | ${{ lastAccessedOn: OVER_FIFTEEN_MINUTES }} | ${{ lastAccessedOn: Date.now(), frequency: 2 }}
- ${'does not update is accessed with 15 minutes'} | ${{}} | ${{ lastAccessedOn: WITHIN_FIFTEEN_MINUTES }} | ${{ lastAccessedOn: EXISTING_ITEM.lastAccessedOn, frequency: 1 }}
- ${'updates if lastAccessedOn not found'} | ${{ lastAccessedOn: undefined }} | ${{ lastAccessedOn: WITHIN_FIFTEEN_MINUTES }} | ${{ lastAccessedOn: Date.now(), frequency: 2 }}
- `('$desc', ({ existingProps, newProps, expected }) => {
- const newItem = {
- ...EXISTING_ITEM,
- ...newProps,
- };
- const existingItem = {
- ...EXISTING_ITEM,
- ...existingProps,
- };
-
- const result = updateExistingFrequentItem(existingItem, newItem);
-
- expect(result).toEqual({
- ...newItem,
- ...expected,
- });
- });
- });
-
- 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/frontend/import/details/components/bulk_import_details_app_spec.js b/spec/frontend/import/details/components/bulk_import_details_app_spec.js
index d32afb7ddcb..18b03ed9802 100644
--- a/spec/frontend/import/details/components/bulk_import_details_app_spec.js
+++ b/spec/frontend/import/details/components/bulk_import_details_app_spec.js
@@ -1,18 +1,30 @@
import { shallowMount } from '@vue/test-utils';
+import { getParameterValues } from '~/lib/utils/url_utility';
+
import BulkImportDetailsApp from '~/import/details/components/bulk_import_details_app.vue';
+jest.mock('~/lib/utils/url_utility');
+
describe('Bulk import details app', () => {
let wrapper;
+ const mockId = 151;
+
const createComponent = () => {
wrapper = shallowMount(BulkImportDetailsApp);
};
+ beforeEach(() => {
+ getParameterValues.mockReturnValueOnce([mockId]);
+ });
+
describe('template', () => {
it('renders heading', () => {
createComponent();
- expect(wrapper.find('h1').text()).toBe('GitLab Migration details');
+ const headingText = wrapper.find('h1').text();
+
+ expect(headingText).toBe(`Items that failed to be imported for ${mockId}`);
});
});
});
diff --git a/spec/frontend/import_entities/import_groups/utils_spec.js b/spec/frontend/import_entities/import_groups/utils_spec.js
index 2892c5c217b..3db57170ed3 100644
--- a/spec/frontend/import_entities/import_groups/utils_spec.js
+++ b/spec/frontend/import_entities/import_groups/utils_spec.js
@@ -5,7 +5,7 @@ const FINISHED_STATUSES = [STATUSES.FINISHED, STATUSES.FAILED, STATUSES.TIMEOUT]
const OTHER_STATUSES = Object.values(STATUSES).filter(
(status) => !FINISHED_STATUSES.includes(status),
);
-describe('gitlab migration status utils', () => {
+describe('Direct transfer status utils', () => {
describe('isFinished', () => {
it.each(FINISHED_STATUSES.map((s) => [s]))(
'reports group as finished when import status is %s',
diff --git a/spec/frontend/lib/utils/vuex_module_mappers_spec.js b/spec/frontend/lib/utils/vuex_module_mappers_spec.js
deleted file mode 100644
index 9070903728b..00000000000
--- a/spec/frontend/lib/utils/vuex_module_mappers_spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import {
- mapVuexModuleActions,
- mapVuexModuleGetters,
- mapVuexModuleState,
- REQUIRE_STRING_ERROR_MESSAGE,
-} from '~/lib/utils/vuex_module_mappers';
-
-const TEST_MODULE_NAME = 'testModuleName';
-
-Vue.use(Vuex);
-
-// setup test component and store ----------------------------------------------
-//
-// These are used to indirectly test `vuex_module_mappers`.
-const TestComponent = {
- props: {
- vuexModule: {
- type: String,
- required: true,
- },
- },
- computed: {
- ...mapVuexModuleState((vm) => vm.vuexModule, { name: 'name', value: 'count' }),
- ...mapVuexModuleGetters((vm) => vm.vuexModule, ['hasValue', 'hasName']),
- stateJson() {
- return JSON.stringify({
- name: this.name,
- value: this.value,
- });
- },
- gettersJson() {
- return JSON.stringify({
- hasValue: this.hasValue,
- hasName: this.hasName,
- });
- },
- },
- methods: {
- ...mapVuexModuleActions((vm) => vm.vuexModule, ['increment']),
- },
- template: `
-<div>
- <pre data-testid="state">{{ stateJson }}</pre>
- <pre data-testid="getters">{{ gettersJson }}</pre>
-</div>`,
-};
-
-const createTestStore = () => {
- return new Vuex.Store({
- modules: {
- [TEST_MODULE_NAME]: {
- namespaced: true,
- state: {
- name: 'Lorem',
- count: 0,
- },
- mutations: {
- INCREMENT: (state, amount) => {
- state.count += amount;
- },
- },
- actions: {
- increment({ commit }, amount) {
- commit('INCREMENT', amount);
- },
- },
- getters: {
- hasValue: (state) => state.count > 0,
- hasName: (state) => Boolean(state.name.length),
- },
- },
- },
- });
-};
-
-describe('~/lib/utils/vuex_module_mappers', () => {
- let store;
- let wrapper;
-
- const getJsonInTemplate = (testId) =>
- JSON.parse(wrapper.find(`[data-testid="${testId}"]`).text());
- const getMappedState = () => getJsonInTemplate('state');
- const getMappedGetters = () => getJsonInTemplate('getters');
-
- beforeEach(() => {
- store = createTestStore();
-
- wrapper = mount(TestComponent, {
- propsData: {
- vuexModule: TEST_MODULE_NAME,
- },
- store,
- });
- });
-
- describe('from module defined by prop', () => {
- it('maps state', () => {
- expect(getMappedState()).toEqual({
- name: store.state[TEST_MODULE_NAME].name,
- value: store.state[TEST_MODULE_NAME].count,
- });
- });
-
- it('maps getters', () => {
- expect(getMappedGetters()).toEqual({
- hasName: true,
- hasValue: false,
- });
- });
-
- it('maps action', () => {
- jest.spyOn(store, 'dispatch');
-
- expect(store.dispatch).not.toHaveBeenCalled();
-
- wrapper.vm.increment(10);
-
- expect(store.dispatch).toHaveBeenCalledWith(`${TEST_MODULE_NAME}/increment`, 10);
- });
- });
-
- describe('with non-string object value', () => {
- it('throws helpful error', () => {
- expect(() => mapVuexModuleActions((vm) => vm.bogus, { foo: () => {} })).toThrow(
- REQUIRE_STRING_ERROR_MESSAGE,
- );
- });
- });
-});
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
index f6ad304f790..fca3a14d82f 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_root_spec.js
@@ -84,7 +84,7 @@ describe('ServiceDeskRoot', () => {
const alertBodyLink = alertEl.findComponent(GlLink);
expect(alertBodyLink.exists()).toBe(true);
expect(alertBodyLink.attributes('href')).toBe(
- '/help/user/project/service_desk.html#use-an-additional-service-desk-alias-email',
+ '/help/user/project/service_desk/configure.html#use-an-additional-service-desk-alias-email',
);
expect(alertBodyLink.text()).toBe('How do I create a custom email address?');
});
diff --git a/spec/frontend/super_sidebar/mock_data.js b/spec/frontend/super_sidebar/mock_data.js
index f5e7a7507ea..fc264ad5e0a 100644
--- a/spec/frontend/super_sidebar/mock_data.js
+++ b/spec/frontend/super_sidebar/mock_data.js
@@ -305,3 +305,32 @@ export const cachedFrequentGroups = JSON.stringify([
frequency: 3,
},
]);
+
+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/frontend/super_sidebar/utils_spec.js b/spec/frontend/super_sidebar/utils_spec.js
index 3e99099b663..a9e4345f9cc 100644
--- a/spec/frontend/super_sidebar/utils_spec.js
+++ b/spec/frontend/super_sidebar/utils_spec.js
@@ -4,10 +4,10 @@ import { getTopFrequentItems, trackContextAccess, ariaCurrent } from '~/super_si
import axios from '~/lib/utils/axios_utils';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import AccessorUtilities from '~/lib/utils/accessor';
-import { FREQUENT_ITEMS, FIFTEEN_MINUTES_IN_MS } from '~/frequent_items/constants';
+import { FREQUENT_ITEMS, FIFTEEN_MINUTES_IN_MS } from '~/super_sidebar/constants';
import { HTTP_STATUS_OK, HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
import waitForPromises from 'helpers/wait_for_promises';
-import { unsortedFrequentItems, sortedFrequentItems } from '../frequent_items/mock_data';
+import { unsortedFrequentItems, sortedFrequentItems } from './mock_data';
jest.mock('~/sentry/sentry_browser_wrapper');