2021-11-18 22:05:49 +05:30
|
|
|
import { GlTable, GlLink, GlPagination, GlAlert } from '@gitlab/ui';
|
|
|
|
import * as Sentry from '@sentry/browser';
|
2021-10-27 15:23:28 +05:30
|
|
|
import { shallowMount, mount } from '@vue/test-utils';
|
|
|
|
import MockAdapter from 'axios-mock-adapter';
|
|
|
|
import waitForPromises from 'helpers/wait_for_promises';
|
|
|
|
import { DEFAULT_PER_PAGE } from '~/api';
|
|
|
|
import IntegrationOverrides from '~/integrations/overrides/components/integration_overrides.vue';
|
2022-03-02 08:16:31 +05:30
|
|
|
import IntegrationTabs from '~/integrations/overrides/components/integration_tabs.vue';
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
import axios from '~/lib/utils/axios_utils';
|
2023-03-17 16:20:25 +05:30
|
|
|
import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
|
2021-10-27 15:23:28 +05:30
|
|
|
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
|
2022-01-26 12:08:38 +05:30
|
|
|
import UrlSync from '~/vue_shared/components/url_sync.vue';
|
2021-10-27 15:23:28 +05:30
|
|
|
|
|
|
|
const mockOverrides = Array(DEFAULT_PER_PAGE * 3)
|
|
|
|
.fill(1)
|
|
|
|
.map((_, index) => ({
|
2022-08-27 11:52:29 +05:30
|
|
|
id: index,
|
2021-10-27 15:23:28 +05:30
|
|
|
name: `test-proj-${index}`,
|
|
|
|
avatar_url: `avatar-${index}`,
|
|
|
|
full_path: `test-proj-${index}`,
|
|
|
|
full_name: `test-proj-${index}`,
|
|
|
|
}));
|
|
|
|
|
|
|
|
describe('IntegrationOverrides', () => {
|
|
|
|
let wrapper;
|
|
|
|
let mockAxios;
|
|
|
|
|
|
|
|
const defaultProps = {
|
|
|
|
overridesPath: 'mock/overrides',
|
|
|
|
};
|
|
|
|
|
2022-01-26 12:08:38 +05:30
|
|
|
const createComponent = ({ mountFn = shallowMount, stubs } = {}) => {
|
2021-10-27 15:23:28 +05:30
|
|
|
wrapper = mountFn(IntegrationOverrides, {
|
|
|
|
propsData: defaultProps,
|
2022-01-26 12:08:38 +05:30
|
|
|
stubs,
|
2021-10-27 15:23:28 +05:30
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
beforeEach(() => {
|
|
|
|
mockAxios = new MockAdapter(axios);
|
2023-03-17 16:20:25 +05:30
|
|
|
mockAxios.onGet(defaultProps.overridesPath).reply(HTTP_STATUS_OK, mockOverrides, {
|
2021-10-27 15:23:28 +05:30
|
|
|
'X-TOTAL': mockOverrides.length,
|
|
|
|
'X-PAGE': 1,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
mockAxios.restore();
|
|
|
|
});
|
|
|
|
|
|
|
|
const findGlTable = () => wrapper.findComponent(GlTable);
|
|
|
|
const findPagination = () => wrapper.findComponent(GlPagination);
|
2022-03-02 08:16:31 +05:30
|
|
|
const findIntegrationTabs = () => wrapper.findComponent(IntegrationTabs);
|
2021-10-27 15:23:28 +05:30
|
|
|
const findRowsAsModel = () =>
|
|
|
|
findGlTable()
|
|
|
|
.findAllComponents(GlLink)
|
|
|
|
.wrappers.map((link) => {
|
|
|
|
const avatar = link.findComponent(ProjectAvatar);
|
|
|
|
|
|
|
|
return {
|
2022-08-27 11:52:29 +05:30
|
|
|
id: avatar.props('projectId'),
|
2021-10-27 15:23:28 +05:30
|
|
|
href: link.attributes('href'),
|
|
|
|
avatarUrl: avatar.props('projectAvatarUrl'),
|
|
|
|
avatarName: avatar.props('projectName'),
|
|
|
|
text: link.text(),
|
|
|
|
};
|
|
|
|
});
|
2021-11-18 22:05:49 +05:30
|
|
|
const findAlert = () => wrapper.findComponent(GlAlert);
|
2021-10-27 15:23:28 +05:30
|
|
|
|
|
|
|
describe('while loading', () => {
|
|
|
|
it('sets GlTable `busy` attribute to `true`', () => {
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
const table = findGlTable();
|
|
|
|
expect(table.exists()).toBe(true);
|
|
|
|
expect(table.attributes('busy')).toBe('true');
|
|
|
|
});
|
2022-03-02 08:16:31 +05:30
|
|
|
|
|
|
|
it('renders IntegrationTabs with count as `null`', () => {
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
expect(findIntegrationTabs().props('projectOverridesCount')).toBe(null);
|
|
|
|
});
|
2021-10-27 15:23:28 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
describe('when initial request is successful', () => {
|
|
|
|
it('sets GlTable `busy` attribute to `false`', async () => {
|
|
|
|
createComponent();
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
const table = findGlTable();
|
|
|
|
expect(table.exists()).toBe(true);
|
2022-08-27 11:52:29 +05:30
|
|
|
expect(table.attributes('busy')).toBeUndefined();
|
2021-10-27 15:23:28 +05:30
|
|
|
});
|
|
|
|
|
2022-03-02 08:16:31 +05:30
|
|
|
it('renders IntegrationTabs with count', async () => {
|
|
|
|
createComponent();
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(findIntegrationTabs().props('projectOverridesCount')).toBe(mockOverrides.length);
|
|
|
|
});
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
describe('table template', () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
createComponent({ mountFn: mount });
|
|
|
|
await waitForPromises();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('renders overrides as rows in table', () => {
|
|
|
|
expect(findRowsAsModel()).toEqual(
|
|
|
|
mockOverrides.map((x) => ({
|
2022-08-27 11:52:29 +05:30
|
|
|
id: x.id,
|
2021-10-27 15:23:28 +05:30
|
|
|
href: x.full_path,
|
|
|
|
avatarUrl: x.avatar_url,
|
|
|
|
avatarName: x.name,
|
|
|
|
text: expect.stringContaining(x.full_name),
|
|
|
|
})),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('when request fails', () => {
|
|
|
|
beforeEach(async () => {
|
2021-11-18 22:05:49 +05:30
|
|
|
jest.spyOn(Sentry, 'captureException');
|
2023-03-17 16:20:25 +05:30
|
|
|
mockAxios.onGet(defaultProps.overridesPath).reply(HTTP_STATUS_INTERNAL_SERVER_ERROR);
|
2021-11-18 22:05:49 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
createComponent();
|
|
|
|
await waitForPromises();
|
|
|
|
});
|
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
it('displays error alert', () => {
|
|
|
|
const alert = findAlert();
|
|
|
|
expect(alert.exists()).toBe(true);
|
|
|
|
expect(alert.text()).toBe(IntegrationOverrides.i18n.defaultErrorMessage);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('hides overrides table', () => {
|
|
|
|
const table = findGlTable();
|
|
|
|
expect(table.exists()).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('captures exception in Sentry', () => {
|
|
|
|
expect(Sentry.captureException).toHaveBeenCalledWith(expect.any(Error));
|
2021-10-27 15:23:28 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('pagination', () => {
|
2022-01-26 12:08:38 +05:30
|
|
|
describe('when total items does not exceed the page limit', () => {
|
|
|
|
it('does not render', async () => {
|
2023-03-17 16:20:25 +05:30
|
|
|
mockAxios.onGet(defaultProps.overridesPath).reply(HTTP_STATUS_OK, [mockOverrides[0]], {
|
2022-01-26 12:08:38 +05:30
|
|
|
'X-TOTAL': DEFAULT_PER_PAGE - 1,
|
|
|
|
'X-PAGE': 1,
|
|
|
|
});
|
|
|
|
|
|
|
|
createComponent();
|
|
|
|
|
|
|
|
// wait for initial load
|
|
|
|
await waitForPromises();
|
2021-10-27 15:23:28 +05:30
|
|
|
|
2022-01-26 12:08:38 +05:30
|
|
|
expect(findPagination().exists()).toBe(false);
|
2021-10-27 15:23:28 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-01-26 12:08:38 +05:30
|
|
|
describe('when total items exceeds the page limit', () => {
|
|
|
|
const mockPage = 2;
|
|
|
|
|
|
|
|
beforeEach(async () => {
|
|
|
|
createComponent({ stubs: { UrlSync } });
|
2023-03-17 16:20:25 +05:30
|
|
|
mockAxios.onGet(defaultProps.overridesPath).reply(HTTP_STATUS_OK, [mockOverrides[0]], {
|
2022-01-26 12:08:38 +05:30
|
|
|
'X-TOTAL': DEFAULT_PER_PAGE * 2,
|
|
|
|
'X-PAGE': mockPage,
|
|
|
|
});
|
|
|
|
|
|
|
|
// wait for initial load
|
|
|
|
await waitForPromises();
|
2021-10-27 15:23:28 +05:30
|
|
|
});
|
|
|
|
|
2022-01-26 12:08:38 +05:30
|
|
|
it('renders', () => {
|
|
|
|
expect(findPagination().exists()).toBe(true);
|
|
|
|
});
|
2021-10-27 15:23:28 +05:30
|
|
|
|
2022-01-26 12:08:38 +05:30
|
|
|
describe('when navigating to a page', () => {
|
|
|
|
beforeEach(async () => {
|
|
|
|
jest.spyOn(axios, 'get');
|
|
|
|
|
|
|
|
// trigger a page change
|
|
|
|
await findPagination().vm.$emit('input', mockPage);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('performs GET request with correct params', () => {
|
|
|
|
expect(axios.get).toHaveBeenCalledWith(defaultProps.overridesPath, {
|
|
|
|
params: { page: mockPage, per_page: DEFAULT_PER_PAGE },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('updates `page` URL parameter', () => {
|
|
|
|
expect(window.location.search).toBe(`?page=${mockPage}`);
|
|
|
|
});
|
|
|
|
});
|
2021-10-27 15:23:28 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|