Commit fd19c626 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'himkp-jest-frequent-item' into 'master'

Migrate spec/javascripts/frequent_items/ to Jest

Closes #32479 and #28698

See merge request gitlab-org/gitlab!32498
parents 8c92785b 527a0a8f
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import Vue from 'vue'; import Vue from 'vue';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper'; import { mountComponentWithStore } from 'helpers/vue_mount_component_helper';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import appComponent from '~/frequent_items/components/app.vue'; import appComponent from '~/frequent_items/components/app.vue';
import eventHub from '~/frequent_items/event_hub'; import eventHub from '~/frequent_items/event_hub';
...@@ -8,6 +8,10 @@ import store from '~/frequent_items/store'; ...@@ -8,6 +8,10 @@ import store from '~/frequent_items/store';
import { FREQUENT_ITEMS, HOUR_IN_MS } from '~/frequent_items/constants'; import { FREQUENT_ITEMS, HOUR_IN_MS } from '~/frequent_items/constants';
import { getTopFrequentItems } from '~/frequent_items/utils'; import { getTopFrequentItems } from '~/frequent_items/utils';
import { currentSession, mockFrequentProjects, mockSearchedProjects } from '../mock_data'; import { currentSession, mockFrequentProjects, mockSearchedProjects } from '../mock_data';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import waitForPromises from 'helpers/wait_for_promises';
useLocalStorageSpy();
let session; let session;
const createComponentWithStore = (namespace = 'projects') => { const createComponentWithStore = (namespace = 'projects') => {
...@@ -42,7 +46,7 @@ describe('Frequent Items App Component', () => { ...@@ -42,7 +46,7 @@ describe('Frequent Items App Component', () => {
describe('methods', () => { describe('methods', () => {
describe('dropdownOpenHandler', () => { describe('dropdownOpenHandler', () => {
it('should fetch frequent items when no search has been previously made on desktop', () => { it('should fetch frequent items when no search has been previously made on desktop', () => {
spyOn(vm, 'fetchFrequentItems'); jest.spyOn(vm, 'fetchFrequentItems').mockImplementation(() => {});
vm.dropdownOpenHandler(); vm.dropdownOpenHandler();
...@@ -56,11 +60,11 @@ describe('Frequent Items App Component', () => { ...@@ -56,11 +60,11 @@ describe('Frequent Items App Component', () => {
beforeEach(() => { beforeEach(() => {
storage = {}; storage = {};
spyOn(window.localStorage, 'setItem').and.callFake((storageKey, value) => { localStorage.setItem.mockImplementation((storageKey, value) => {
storage[storageKey] = value; storage[storageKey] = value;
}); });
spyOn(window.localStorage, 'getItem').and.callFake(storageKey => { localStorage.getItem.mockImplementation(storageKey => {
if (storage[storageKey]) { if (storage[storageKey]) {
return storage[storageKey]; return storage[storageKey];
} }
...@@ -156,12 +160,12 @@ describe('Frequent Items App Component', () => { ...@@ -156,12 +160,12 @@ describe('Frequent Items App Component', () => {
describe('created', () => { describe('created', () => {
it('should bind event listeners on eventHub', done => { it('should bind event listeners on eventHub', done => {
spyOn(eventHub, '$on'); jest.spyOn(eventHub, '$on').mockImplementation(() => {});
createComponentWithStore().$mount(); createComponentWithStore().$mount();
Vue.nextTick(() => { Vue.nextTick(() => {
expect(eventHub.$on).toHaveBeenCalledWith('projects-dropdownOpen', jasmine.any(Function)); expect(eventHub.$on).toHaveBeenCalledWith('projects-dropdownOpen', expect.any(Function));
done(); done();
}); });
}); });
...@@ -169,13 +173,13 @@ describe('Frequent Items App Component', () => { ...@@ -169,13 +173,13 @@ describe('Frequent Items App Component', () => {
describe('beforeDestroy', () => { describe('beforeDestroy', () => {
it('should unbind event listeners on eventHub', done => { it('should unbind event listeners on eventHub', done => {
spyOn(eventHub, '$off'); jest.spyOn(eventHub, '$off').mockImplementation(() => {});
vm.$mount(); vm.$mount();
vm.$destroy(); vm.$destroy();
Vue.nextTick(() => { Vue.nextTick(() => {
expect(eventHub.$off).toHaveBeenCalledWith('projects-dropdownOpen', jasmine.any(Function)); expect(eventHub.$off).toHaveBeenCalledWith('projects-dropdownOpen', expect.any(Function));
done(); done();
}); });
}); });
...@@ -211,9 +215,7 @@ describe('Frequent Items App Component', () => { ...@@ -211,9 +215,7 @@ describe('Frequent Items App Component', () => {
it('should render frequent projects list', done => { it('should render frequent projects list', done => {
const expectedResult = getTopFrequentItems(mockFrequentProjects); const expectedResult = getTopFrequentItems(mockFrequentProjects);
spyOn(window.localStorage, 'getItem').and.callFake(() => localStorage.getItem.mockImplementation(() => JSON.stringify(mockFrequentProjects));
JSON.stringify(mockFrequentProjects),
);
expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(1); expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(1);
...@@ -236,15 +238,7 @@ describe('Frequent Items App Component', () => { ...@@ -236,15 +238,7 @@ describe('Frequent Items App Component', () => {
.then(() => { .then(() => {
expect(vm.$el.querySelector('.loading-animation')).toBeDefined(); expect(vm.$el.querySelector('.loading-animation')).toBeDefined();
}) })
.then(waitForPromises)
// 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(() => { .then(() => {
expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe( expect(vm.$el.querySelectorAll('.frequent-items-list-container li').length).toBe(
mockSearchedProjects.data.length, mockSearchedProjects.data.length,
......
import { TEST_HOST } from 'helpers/test_constants'; 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 = [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 = [ export const mockFrequentProjects = [
{ {
id: 1, id: 1,
...@@ -48,10 +137,34 @@ export const mockFrequentProjects = [ ...@@ -48,10 +137,34 @@ export const mockFrequentProjects = [
}, },
]; ];
export const mockProject = { export const mockSearchedProjects = { data: [mockRawProject] };
id: 1, export const mockProcessedSearchedProjects = [mockProject];
name: 'GitLab Community Edition',
namespace: 'gitlab-org / gitlab-ce', export const unsortedFrequentItems = [
webUrl: `${TEST_HOST}/gitlab-org/gitlab-foss`, { id: 1, frequency: 12, lastAccessedOn: 1491400843391 },
avatarUrl: null, { 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 },
];
import testAction from 'spec/helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import AccessorUtilities from '~/lib/utils/accessor'; import AccessorUtilities from '~/lib/utils/accessor';
...@@ -109,7 +109,7 @@ describe('Frequent Items Dropdown Store Actions', () => { ...@@ -109,7 +109,7 @@ describe('Frequent Items Dropdown Store Actions', () => {
}); });
it('should dispatch `receiveFrequentItemsError`', done => { it('should dispatch `receiveFrequentItemsError`', done => {
spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(false); jest.spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').mockReturnValue(false);
mockedState.namespace = mockNamespace; mockedState.namespace = mockNamespace;
mockedState.storageKey = mockStorageKey; mockedState.storageKey = mockStorageKey;
......
...@@ -11,25 +11,25 @@ import { mockProject, unsortedFrequentItems, sortedFrequentItems } from './mock_ ...@@ -11,25 +11,25 @@ import { mockProject, unsortedFrequentItems, sortedFrequentItems } from './mock_
describe('Frequent Items utils spec', () => { describe('Frequent Items utils spec', () => {
describe('isMobile', () => { describe('isMobile', () => {
it('returns true when the screen is medium ', () => { it('returns true when the screen is medium ', () => {
spyOn(bp, 'getBreakpointSize').and.returnValue('md'); jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('md');
expect(isMobile()).toBe(true); expect(isMobile()).toBe(true);
}); });
it('returns true when the screen is small ', () => { it('returns true when the screen is small ', () => {
spyOn(bp, 'getBreakpointSize').and.returnValue('sm'); jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('sm');
expect(isMobile()).toBe(true); expect(isMobile()).toBe(true);
}); });
it('returns true when the screen is extra-small ', () => { it('returns true when the screen is extra-small ', () => {
spyOn(bp, 'getBreakpointSize').and.returnValue('xs'); jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('xs');
expect(isMobile()).toBe(true); expect(isMobile()).toBe(true);
}); });
it('returns false when the screen is larger than medium ', () => { it('returns false when the screen is larger than medium ', () => {
spyOn(bp, 'getBreakpointSize').and.returnValue('lg'); jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('lg');
expect(isMobile()).toBe(false); expect(isMobile()).toBe(false);
}); });
...@@ -43,21 +43,21 @@ describe('Frequent Items utils spec', () => { ...@@ -43,21 +43,21 @@ describe('Frequent Items utils spec', () => {
}); });
it('returns correct amount of items for mobile', () => { it('returns correct amount of items for mobile', () => {
spyOn(bp, 'getBreakpointSize').and.returnValue('md'); jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('md');
const result = getTopFrequentItems(unsortedFrequentItems); const result = getTopFrequentItems(unsortedFrequentItems);
expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_MOBILE); expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_MOBILE);
}); });
it('returns correct amount of items for desktop', () => { it('returns correct amount of items for desktop', () => {
spyOn(bp, 'getBreakpointSize').and.returnValue('xl'); jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('xl');
const result = getTopFrequentItems(unsortedFrequentItems); const result = getTopFrequentItems(unsortedFrequentItems);
expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_DESKTOP); expect(result.length).toBe(FREQUENT_ITEMS.LIST_COUNT_DESKTOP);
}); });
it('sorts frequent items in order of frequency and lastAccessedOn', () => { it('sorts frequent items in order of frequency and lastAccessedOn', () => {
spyOn(bp, 'getBreakpointSize').and.returnValue('xl'); jest.spyOn(bp, 'getBreakpointSize').mockReturnValue('xl');
const result = getTopFrequentItems(unsortedFrequentItems); const result = getTopFrequentItems(unsortedFrequentItems);
const expectedResult = sortedFrequentItems.slice(0, FREQUENT_ITEMS.LIST_COUNT_DESKTOP); const expectedResult = sortedFrequentItems.slice(0, FREQUENT_ITEMS.LIST_COUNT_DESKTOP);
......
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 },
];
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment