debian-mirror-gitlab/spec/frontend/frequent_items/components/app_spec.js

255 lines
7.6 KiB
JavaScript
Raw Normal View History

2018-11-08 19:23:39 +05:30
import MockAdapter from 'axios-mock-adapter';
import Vue from 'vue';
2021-06-08 01:23:25 +05:30
import Vuex from 'vuex';
2020-10-24 23:57:45 +05:30
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
2021-06-08 01:23:25 +05:30
import { mountExtended } from 'helpers/vue_test_utils_helper';
2020-10-24 23:57:45 +05:30
import waitForPromises from 'helpers/wait_for_promises';
2021-06-08 01:23:25 +05:30
import App from '~/frequent_items/components/app.vue';
import FrequentItemsList from '~/frequent_items/components/frequent_items_list.vue';
2018-11-08 19:23:39 +05:30
import { FREQUENT_ITEMS, HOUR_IN_MS } from '~/frequent_items/constants';
2021-03-11 19:13:27 +05:30
import eventHub from '~/frequent_items/event_hub';
import { createStore } from '~/frequent_items/store';
2018-11-08 19:23:39 +05:30
import { getTopFrequentItems } from '~/frequent_items/utils';
2021-03-11 19:13:27 +05:30
import axios from '~/lib/utils/axios_utils';
2018-11-08 19:23:39 +05:30
import { currentSession, mockFrequentProjects, mockSearchedProjects } from '../mock_data';
2020-05-24 23:13:21 +05:30
2021-06-08 01:23:25 +05:30
Vue.use(Vuex);
2020-05-24 23:13:21 +05:30
useLocalStorageSpy();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
const TEST_NAMESPACE = 'projects';
const TEST_VUEX_MODULE = 'frequentProjects';
const TEST_PROJECT = currentSession[TEST_NAMESPACE].project;
const TEST_STORAGE_KEY = currentSession[TEST_NAMESPACE].storageKey;
2021-09-04 01:27:46 +05:30
const TEST_SEARCH_CLASS = 'test-search-class';
2018-11-08 19:23:39 +05:30
describe('Frequent Items App Component', () => {
2021-06-08 01:23:25 +05:30
let wrapper;
2018-11-08 19:23:39 +05:30
let mock;
2021-06-08 01:23:25 +05:30
let store;
2021-09-04 01:27:46 +05:30
const createComponent = (props = {}) => {
2021-06-08 01:23:25 +05:30
const session = currentSession[TEST_NAMESPACE];
gon.api_version = session.apiVersion;
wrapper = mountExtended(App, {
store,
propsData: {
namespace: TEST_NAMESPACE,
currentUserName: session.username,
2021-09-04 01:27:46 +05:30
currentItem: session.project,
...props,
2021-06-08 01:23:25 +05:30
},
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);
};
2018-11-08 19:23:39 +05:30
beforeEach(() => {
mock = new MockAdapter(axios);
2021-06-08 01:23:25 +05:30
store = createStore();
2018-11-08 19:23:39 +05:30
});
afterEach(() => {
mock.restore();
2021-06-08 01:23:25 +05:30
wrapper.destroy();
2018-11-08 19:23:39 +05:30
});
2021-06-08 01:23:25 +05:30
describe('default', () => {
beforeEach(() => {
jest.spyOn(store, 'dispatch');
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
createComponent();
2018-11-08 19:23:39 +05:30
});
2021-06-08 01:23:25 +05:30
it('should fetch frequent items', () => {
triggerDropdownOpen();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(store.dispatch).toHaveBeenCalledWith(`${TEST_VUEX_MODULE}/fetchFrequentItems`);
});
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
it('should not fetch frequent items if detroyed', () => {
wrapper.destroy();
triggerDropdownOpen();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(store.dispatch).not.toHaveBeenCalledWith(`${TEST_VUEX_MODULE}/fetchFrequentItems`);
});
2021-03-11 19:13:27 +05:30
2021-06-08 01:23:25 +05:30
it('should render search input', () => {
2021-09-04 01:27:46 +05:30
expect(findSearchInput().classes()).toEqual(['search-input-container']);
2021-06-08 01:23:25 +05:30
});
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
it('should render loading animation', async () => {
triggerDropdownOpen();
store.state[TEST_VUEX_MODULE].isLoadingItems = true;
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
await wrapper.vm.$nextTick();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
const loading = findLoading();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(loading.exists()).toBe(true);
expect(loading.find('[aria-label="Loading projects"]').exists()).toBe(true);
});
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
it('should render frequent projects list header', () => {
const sectionHeader = findSectionHeader();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(sectionHeader.exists()).toBe(true);
expect(sectionHeader.text()).toBe('Frequently visited');
});
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
it('should render frequent projects list', async () => {
const expectedResult = getTopFrequentItems(mockFrequentProjects);
localStorage.setItem(TEST_STORAGE_KEY, JSON.stringify(mockFrequentProjects));
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(findFrequentItems().length).toBe(1);
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
triggerDropdownOpen();
await wrapper.vm.$nextTick();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(findFrequentItems().length).toBe(expectedResult.length);
expect(findFrequentItemsList().props()).toEqual({
items: expectedResult,
namespace: TEST_NAMESPACE,
hasSearchQuery: false,
isFetchFailed: false,
matcher: '',
2018-11-08 19:23:39 +05:30
});
});
2021-06-08 01:23:25 +05:30
it('should render searched projects list', async () => {
mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(200, mockSearchedProjects.data);
setSearch('gitlab');
await wrapper.vm.$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, web_url, name_with_namespace, ...item }) => ({
...item,
avatarUrl: avatar_url,
webUrl: web_url,
namespace: name_with_namespace,
}),
),
namespace: TEST_NAMESPACE,
hasSearchQuery: true,
isFetchFailed: false,
matcher: 'gitlab',
}),
);
2018-11-08 19:23:39 +05:30
});
});
2021-09-04 01:27:46 +05:30
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]);
});
});
2021-06-08 01:23:25 +05:30
describe('logging', () => {
it('when created, it should create a project storage entry and adds a project', () => {
createComponent();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(getStoredProjects()).toEqual([
expect.objectContaining({
frequency: 1,
lastAccessedOn: Date.now(),
}),
]);
});
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
describe('when created multiple times', () => {
beforeEach(() => {
createComponent();
wrapper.destroy();
createComponent();
wrapper.destroy();
2018-11-08 19:23:39 +05:30
});
2021-06-08 01:23:25 +05:30
it('should only log once', () => {
expect(getStoredProjects()).toEqual([
expect.objectContaining({
lastAccessedOn: Date.now(),
frequency: 1,
}),
]);
});
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
it('should increase frequency, when created an hour later', () => {
const hourLater = Date.now() + HOUR_IN_MS + 1;
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
jest.spyOn(Date, 'now').mockReturnValue(hourLater);
createComponent({ currentItem: { ...TEST_PROJECT, lastAccessedOn: hourLater } });
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(getStoredProjects()).toEqual([
expect.objectContaining({
lastAccessedOn: hourLater,
frequency: 2,
}),
]);
2018-11-08 19:23:39 +05:30
});
});
2021-06-08 01:23:25 +05:30
it('should always update project metadata', () => {
const oldProject = {
...TEST_PROJECT,
};
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
const newProject = {
...oldProject,
name: 'New Name',
avatarUrl: 'new/avatar.png',
namespace: 'New / Namespace',
webUrl: 'http://localhost/new/web/url',
};
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
createComponent({ currentItem: oldProject });
wrapper.destroy();
expect(getStoredProjects()).toEqual([expect.objectContaining(oldProject)]);
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
createComponent({ currentItem: newProject });
wrapper.destroy();
2018-11-08 19:23:39 +05:30
2021-06-08 01:23:25 +05:30
expect(getStoredProjects()).toEqual([expect.objectContaining(newProject)]);
2018-11-08 19:23:39 +05:30
});
2021-06-08 01:23:25 +05:30
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);
2018-11-08 19:23:39 +05:30
});
});
});