Commit 3f702298 authored by Jose Vargas's avatar Jose Vargas

Move non EE dashboard specs to jest

This changes the non EE dashboard specs
for the monitoring feature to jest
parent 858555fa
......@@ -8,7 +8,7 @@ import {
mockedQueryResultPayload,
environmentData,
} from 'spec/monitoring/mock_data';
import propsData from 'spec/monitoring/components/dashboard_spec';
import propsData from 'spec/monitoring/components/dashboard_resize_spec';
import CustomMetricsFormFields from 'ee/custom_metrics/components/custom_metrics_form_fields.vue';
import Tracking from '~/tracking';
import { createStore } from '~/monitoring/stores';
......
import Vue from 'vue';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlToast } from '@gitlab/ui';
import { shallowMount, createLocalVue, mount } from '@vue/test-utils';
import { GlDropdownItem, GlButton, GlToast } from '@gitlab/ui';
import VueDraggable from 'vuedraggable';
import MockAdapter from 'axios-mock-adapter';
import Dashboard from '~/monitoring/components/dashboard.vue';
import axios from '~/lib/utils/axios_utils';
import statusCodes from '~/lib/utils/http_status';
import { metricStates } from '~/monitoring/constants';
import Dashboard from '~/monitoring/components/dashboard.vue';
import DateTimePicker from '~/monitoring/components/date_time_picker/date_time_picker.vue';
import GroupEmptyState from '~/monitoring/components/group_empty_state.vue';
import * as types from '~/monitoring/stores/mutation_types';
import { createStore } from '~/monitoring/stores';
import axios from '~/lib/utils/axios_utils';
import * as types from '~/monitoring/stores/mutation_types';
import * as monitoringUtils from '~/monitoring/utils';
import { setupComponentStore, propsData } from '../init_utils';
import {
metricsGroupsAPIResponse,
mockedEmptyResult,
mockedQueryResultPayload,
mockedQueryResultPayloadCoresTotal,
mockApiEndpoint,
environmentData,
dashboardGitResponse,
} from '../mock_data';
const localVue = createLocalVue();
const propsData = {
hasMetrics: false,
documentationPath: '/path/to/docs',
settingsPath: '/path/to/settings',
clustersPath: '/path/to/clusters',
tagsPath: '/path/to/tags',
projectPath: '/path/to/project',
metricsEndpoint: mockApiEndpoint,
deploymentsEndpoint: null,
emptyGettingStartedSvgPath: '/path/to/getting-started.svg',
emptyLoadingSvgPath: '/path/to/loading.svg',
emptyNoDataSvgPath: '/path/to/no-data.svg',
emptyNoDataSmallSvgPath: '/path/to/no-data-small.svg',
emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
environmentsEndpoint: '/root/hello-prometheus/environments/35',
currentEnvironmentName: 'production',
customMetricsAvailable: false,
customMetricsPath: '',
validateQueryPath: '',
};
const resetSpy = spy => {
if (spy) {
spy.calls.reset();
}
};
let expectedPanelCount;
function setupComponentStore(component) {
// Load 2 panel groups
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
metricsGroupsAPIResponse,
);
// Load 3 panels to the dashboard, one with an empty result
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedEmptyResult,
);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayload,
);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayloadCoresTotal,
);
expectedPanelCount = 2;
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
environmentData,
);
}
const expectedPanelCount = 2;
describe('Dashboard', () => {
let DashboardComponent;
let mock;
let store;
let component;
let wrapper;
let mock;
const createComponentWrapper = (props = {}, options = {}) => {
const createShallowWrapper = (props = {}, options = {}) => {
wrapper = shallowMount(localVue.extend(DashboardComponent), {
localVue,
sync: false,
......@@ -95,21 +39,23 @@ describe('Dashboard', () => {
});
};
beforeEach(() => {
setFixtures(`
<div class="prometheus-graphs"></div>
<div class="layout-page"></div>
`);
const createMountedWrapper = (props = {}, options = {}) => {
wrapper = mount(localVue.extend(DashboardComponent), {
localVue,
sync: false,
propsData: { ...propsData, ...props },
store,
...options,
});
};
beforeEach(() => {
store = createStore();
mock = new MockAdapter(axios);
DashboardComponent = localVue.extend(Dashboard);
mock = new MockAdapter(axios);
});
afterEach(() => {
if (component) {
component.$destroy();
}
if (wrapper) {
wrapper.destroy();
}
......@@ -118,37 +64,26 @@ describe('Dashboard', () => {
describe('no metrics are available yet', () => {
beforeEach(() => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData },
store,
});
mock.onGet(mockApiEndpoint).reply(statusCodes.OK, metricsGroupsAPIResponse);
createShallowWrapper({}, { attachToDocument: true });
});
it('shows a getting started empty state when no metrics are present', () => {
expect(component.$el.querySelector('.prometheus-graphs')).toBe(null);
expect(component.emptyState).toEqual('gettingStarted');
afterEach(() => {
wrapper.destroy();
});
it('shows the environment selector', () => {
expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy();
expect(wrapper.vm.$el.querySelector('.js-environments-dropdown')).toBeTruthy();
});
});
describe('no data found', () => {
it('shows the environment selector dropdown', () => {
createComponentWrapper();
expect(wrapper.find('.js-environments-dropdown').exists()).toBeTruthy();
});
});
describe('cluster health', () => {
beforeEach(done => {
createComponentWrapper({ hasMetrics: true });
mock.onGet(mockApiEndpoint).reply(statusCodes.OK, metricsGroupsAPIResponse);
createShallowWrapper({}, { attachToDocument: true });
// all_dashboards is not defined in health dashboards
wrapper.vm.$store.commit(`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, undefined);
wrapper.vm.$nextTick(done);
});
......@@ -156,254 +91,186 @@ describe('Dashboard', () => {
wrapper.destroy();
});
it('renders correctly', () => {
expect(wrapper.isVueInstance()).toBe(true);
expect(wrapper.exists()).toBe(true);
it('shows the environment selector dropdown', () => {
expect(wrapper.vm.$el.querySelector('.js-environments-dropdown')).toBeTruthy();
});
});
describe('requests information to the server', () => {
let spy;
describe('request information to the server', () => {
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
});
afterEach(() => {
resetSpy(spy);
});
it('shows up a loading state', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData, hasMetrics: true },
store,
});
Vue.nextTick(() => {
expect(component.emptyState).toEqual('loading');
done();
});
});
createShallowWrapper({ hasMetrics: true }, { attachToDocument: true });
it('hides the group panels when showPanels is false', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
showPanels: false,
},
store,
});
setupComponentStore(component);
Vue.nextTick()
wrapper.vm
.$nextTick()
.then(() => {
expect(component.showEmptyState).toEqual(false);
expect(component.$el.querySelector('.prometheus-panel')).toEqual(null);
expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy();
expect(wrapper.vm.emptyState).toEqual('loading');
done();
})
.catch(done.fail);
});
describe('when all the requests have been commited by the store', () => {
beforeEach(() => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
},
store,
});
setupComponentStore(component);
});
it('renders the environments dropdown with a number of environments', done => {
Vue.nextTick()
.then(() => {
const dropdownMenuEnvironments = component.$el.querySelectorAll(
'.js-environments-dropdown .dropdown-item',
);
expect(component.environments.length).toEqual(environmentData.length);
expect(dropdownMenuEnvironments.length).toEqual(component.environments.length);
Array.from(dropdownMenuEnvironments).forEach((value, index) => {
if (environmentData[index].metrics_path) {
expect(value).toHaveAttr('href', environmentData[index].metrics_path);
}
});
done();
})
.catch(done.fail);
});
it('renders the environments dropdown with a single active element', done => {
Vue.nextTick()
.then(() => {
const dropdownItems = component.$el.querySelectorAll(
'.js-environments-dropdown .dropdown-item.active',
);
expect(dropdownItems.length).toEqual(1);
done();
})
.catch(done.fail);
});
});
it('hides the environments dropdown list when there is no environments', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
},
store,
});
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
metricsGroupsAPIResponse,
);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayload,
it('hides the group panels when showPanels is false', done => {
createMountedWrapper(
{ hasMetrics: true, showPanels: false },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
Vue.nextTick()
setupComponentStore(wrapper);
wrapper.vm
.$nextTick()
.then(() => {
const dropdownMenuEnvironments = component.$el.querySelectorAll(
'.js-environments-dropdown .dropdown-item',
);
expect(wrapper.vm.showEmptyState).toEqual(false);
expect(wrapper.vm.$el.querySelector('.prometheus-panel')).toEqual(null);
// TODO: The last expectation doesn't belong here, it belongs in a `group_group_spec.js` file
// Issue: https://gitlab.com/gitlab-org/gitlab/issues/118780
// expect(wrapper.vm.$el.querySelector('.prometheus-graph-group')).toBeTruthy();
expect(dropdownMenuEnvironments.length).toEqual(0);
done();
})
.catch(done.fail);
});
it('renders the datetimepicker dropdown', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
showPanels: false,
},
store,
});
it('fetches the metrics data with proper time window', done => {
const getTimeDiffSpy = jest.spyOn(monitoringUtils, 'getTimeDiff');
jest.spyOn(store, 'dispatch');
createMountedWrapper(
{ hasMetrics: true },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
setupComponentStore(component);
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
environmentData,
);
Vue.nextTick()
wrapper.vm
.$nextTick()
.then(() => {
expect(component.$el.querySelector('.js-time-window-dropdown')).not.toBeNull();
expect(store.dispatch).toHaveBeenCalled();
expect(getTimeDiffSpy).toHaveBeenCalled();
done();
})
.catch(done.fail);
});
});
it('fetches the metrics data with proper time window', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
showPanels: false,
},
store,
});
spyOn(component.$store, 'dispatch').and.stub();
const getTimeDiffSpy = spyOnDependency(Dashboard, 'getTimeDiff').and.callThrough();
describe('when all requests have been commited by the store', () => {
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(statusCodes.OK, metricsGroupsAPIResponse);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
environmentData,
createMountedWrapper(
{ hasMetrics: true },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
component.$mount();
setupComponentStore(wrapper);
});
afterEach(() => {
wrapper.destroy();
});
Vue.nextTick()
it('renders the environments dropdown with a number of environments', done => {
wrapper.vm
.$nextTick()
.then(() => {
expect(component.$store.dispatch).toHaveBeenCalled();
expect(getTimeDiffSpy).toHaveBeenCalled();
const environmentDropdownItems = wrapper
.find('.js-environments-dropdown')
.findAll(GlDropdownItem);
expect(wrapper.vm.environments.length).toEqual(environmentData.length);
expect(environmentDropdownItems.length).toEqual(wrapper.vm.environments.length);
environmentDropdownItems.wrappers.forEach((itemWrapper, index) => {
const anchorEl = itemWrapper.find('a');
if (anchorEl.exists() && environmentData[index].metrics_path) {
const href = anchorEl.attributes('href');
expect(href).toBe(environmentData[index].metrics_path);
}
});
done();
})
.catch(done.fail);
});
it('shows a specific time window selected from the url params', done => {
const start = '2019-10-01T18:27:47.000Z';
const end = '2019-10-01T18:57:47.000Z';
spyOnDependency(Dashboard, 'getTimeDiff').and.returnValue({
start,
end,
});
spyOnDependency(Dashboard, 'getParameterValues').and.callFake(param => {
if (param === 'start') return [start];
if (param === 'end') return [end];
return [];
});
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData, hasMetrics: true },
store,
sync: false,
});
setupComponentStore(component);
Vue.nextTick()
it('renders the environments dropdown with a single active element', done => {
wrapper.vm
.$nextTick()
.then(() => {
const selectedTimeWindow = component.$el.querySelector(
'.js-time-window-dropdown .active',
const environmentDropdownItems = wrapper
.find('.js-environments-dropdown')
.findAll(GlDropdownItem);
const activeItem = environmentDropdownItems.wrappers.filter(itemWrapper =>
itemWrapper.find('.active').exists(),
);
expect(selectedTimeWindow.textContent.trim()).toEqual('30 minutes');
expect(activeItem.length).toBe(1);
done();
})
.catch(done.fail);
});
});
it('shows an error message if invalid url parameters are passed', done => {
spyOnDependency(Dashboard, 'getParameterValues').and.returnValue([
'<script>alert("XSS")</script>',
]);
it('hides the environments dropdown list when there is no environments', done => {
createMountedWrapper(
{ hasMetrics: true },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
metricsGroupsAPIResponse,
);
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayload,
);
wrapper.vm
.$nextTick()
.then(() => {
const environmentDropdownItems = wrapper
.find('.js-environments-dropdown')
.findAll(GlDropdownItem);
expect(environmentDropdownItems.length).toEqual(0);
done();
})
.catch(done.fail);
});
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData, hasMetrics: true },
store,
});
it('renders the datetimepicker dropdown', done => {
createMountedWrapper(
{ hasMetrics: true },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
spy = spyOn(component, 'showInvalidDateError');
component.$mount();
setupComponentStore(wrapper);
component.$nextTick(() => {
expect(component.showInvalidDateError).toHaveBeenCalled();
wrapper.vm
.$nextTick()
.then(() => {
expect(wrapper.find(DateTimePicker).exists()).toBe(true);
done();
});
});
})
.catch(done.fail);
});
describe('when one of the metrics is missing', () => {
beforeEach(() => {
beforeEach(done => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
});
beforeEach(done => {
createComponentWrapper({ hasMetrics: true });
setupComponentStore(wrapper.vm);
createShallowWrapper({ hasMetrics: true }, { attachToDocument: true });
setupComponentStore(wrapper);
wrapper.vm.$nextTick(done);
});
......@@ -432,13 +299,13 @@ describe('Dashboard', () => {
const findRearrangeButton = () => wrapper.find('.js-rearrange-button');
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
mock.onGet(mockApiEndpoint).reply(statusCodes.OK, metricsGroupsAPIResponse);
});
beforeEach(done => {
createComponentWrapper({ hasMetrics: true }, { attachToDocument: true });
createShallowWrapper({ hasMetrics: true }, { attachToDocument: true });
setupComponentStore(wrapper.vm);
setupComponentStore(wrapper);
wrapper.vm.$nextTick(done);
});
......@@ -527,110 +394,23 @@ describe('Dashboard', () => {
});
});
// https://gitlab.com/gitlab-org/gitlab-ce/issues/66922
// eslint-disable-next-line jasmine/no-disabled-tests
xdescribe('link to chart', () => {
const currentDashboard = 'TEST_DASHBOARD';
localVue.use(GlToast);
const link = () => wrapper.find('.js-chart-link');
const clipboardText = () => link().element.dataset.clipboardText;
describe('cluster health', () => {
beforeEach(done => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
createComponentWrapper({ hasMetrics: true, currentDashboard }, { attachToDocument: true });
mock.onGet(propsData.metricsEndpoint).reply(statusCodes.OK, JSON.stringify({}));
createShallowWrapper({ hasMetrics: true });
setTimeout(done);
// all_dashboards is not defined in health dashboards
wrapper.vm.$store.commit(`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, undefined);
wrapper.vm.$nextTick(done);
});
afterEach(() => {
wrapper.destroy();
});
it('adds a copy button to the dropdown', () => {
expect(link().text()).toContain('Generate link to chart');
});
it('contains a link to the dashboard', () => {
expect(clipboardText()).toContain(`dashboard=${currentDashboard}`);
expect(clipboardText()).toContain(`group=`);
expect(clipboardText()).toContain(`title=`);
expect(clipboardText()).toContain(`y_label=`);
});
it('undefined parameter is stripped', done => {
wrapper.setProps({ currentDashboard: undefined });
wrapper.vm.$nextTick(() => {
expect(clipboardText()).not.toContain(`dashboard=`);
expect(clipboardText()).toContain(`y_label=`);
done();
});
});
it('null parameter is stripped', done => {
wrapper.setProps({ currentDashboard: null });
wrapper.vm.$nextTick(() => {
expect(clipboardText()).not.toContain(`dashboard=`);
expect(clipboardText()).toContain(`y_label=`);
done();
});
});
it('creates a toast when clicked', () => {
spyOn(wrapper.vm.$toast, 'show').and.stub();
link().vm.$emit('click');
expect(wrapper.vm.$toast.show).toHaveBeenCalled();
});
});
describe('responds to window resizes', () => {
let promPanel;
let promGroup;
let panelToggle;
let chart;
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
showPanels: true,
},
store,
});
setupComponentStore(component);
return Vue.nextTick().then(() => {
[, promPanel] = component.$el.querySelectorAll('.prometheus-panel');
promGroup = promPanel.querySelector('.prometheus-graph-group');
panelToggle = promPanel.querySelector('.js-graph-group-toggle');
chart = promGroup.querySelector('.position-relative svg');
});
});
it('setting chart size to zero when panel group is hidden', () => {
expect(promGroup.style.display).toBe('');
expect(chart.clientWidth).toBeGreaterThan(0);
panelToggle.click();
return Vue.nextTick().then(() => {
expect(promGroup.style.display).toBe('none');
expect(chart.clientWidth).toBe(0);
promPanel.style.width = '500px';
});
});
it('expanding chart panel group after resize displays chart', () => {
panelToggle.click();
expect(chart.clientWidth).toBeGreaterThan(0);
it('renders correctly', () => {
expect(wrapper.isVueInstance()).toBe(true);
expect(wrapper.exists()).toBe(true);
});
});
......@@ -638,9 +418,9 @@ describe('Dashboard', () => {
const findEditLink = () => wrapper.find('.js-edit-link');
beforeEach(done => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
mock.onGet(mockApiEndpoint).reply(statusCodes.OK, metricsGroupsAPIResponse);
createComponentWrapper({ hasMetrics: true }, { attachToDocument: true });
createShallowWrapper({ hasMetrics: true }, { attachToDocument: true });
wrapper.vm.$store.commit(
`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
......@@ -662,11 +442,42 @@ describe('Dashboard', () => {
const currentDashboard = dashboard.path;
wrapper.setProps({ currentDashboard });
wrapper.vm.$nextTick(() => {
expect(findEditLink().exists()).toBe(true);
expect(findEditLink().attributes('href')).toBe(dashboard.project_blob_path);
done();
});
wrapper.vm
.$nextTick()
.then(() => {
expect(findEditLink().exists()).toBe(true);
expect(findEditLink().attributes('href')).toBe(dashboard.project_blob_path);
done();
})
.catch(done.fail);
});
});
describe('Dashboard dropdown', () => {
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
createMountedWrapper(
{ hasMetrics: true },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
wrapper.vm.$store.commit(
`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
dashboardGitResponse,
);
});
it('shows the dashboard dropdown', done => {
wrapper.vm
.$nextTick()
.then(() => {
const dashboardDropdown = wrapper.find('.js-dashboards-dropdown');
expect(dashboardDropdown.exists()).toBe(true);
done();
})
.catch(done.fail);
});
});
......@@ -674,56 +485,89 @@ describe('Dashboard', () => {
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
createMountedWrapper(
{
hasMetrics: true,
showPanels: false,
showTimeWindowDropdown: false,
externalDashboardUrl: '/mockUrl',
},
store,
});
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
});
it('shows the link', done => {
setTimeout(() => {
expect(component.$el.querySelector('.js-external-dashboard-link').innerText).toContain(
'View full dashboard',
);
done();
});
wrapper.vm
.$nextTick()
.then(() => {
const externalDashboardButton = wrapper.find('.js-external-dashboard-link');
expect(externalDashboardButton.exists()).toBe(true);
expect(externalDashboardButton.is(GlButton)).toBe(true);
expect(externalDashboardButton.text()).toContain('View full dashboard');
done();
})
.catch(done.fail);
});
});
describe('Dashboard dropdown', () => {
beforeEach(() => {
// https://gitlab.com/gitlab-org/gitlab-ce/issues/66922
// eslint-disable-next-line jest/no-disabled-tests
describe.skip('link to chart', () => {
const currentDashboard = 'TEST_DASHBOARD';
localVue.use(GlToast);
const link = () => wrapper.find('.js-chart-link');
const clipboardText = () => link().element.dataset.clipboardText;
beforeEach(done => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
showPanels: false,
},
store,
});
createShallowWrapper({ hasMetrics: true, currentDashboard }, { attachToDocument: true });
component.$store.commit(
`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
dashboardGitResponse,
);
setTimeout(done);
});
it('shows the dashboard dropdown', done => {
setTimeout(() => {
const dashboardDropdown = component.$el.querySelector('.js-dashboards-dropdown');
afterEach(() => {
wrapper.destroy();
});
it('adds a copy button to the dropdown', () => {
expect(link().text()).toContain('Generate link to chart');
});
it('contains a link to the dashboard', () => {
expect(clipboardText()).toContain(`dashboard=${currentDashboard}`);
expect(clipboardText()).toContain(`group=`);
expect(clipboardText()).toContain(`title=`);
expect(clipboardText()).toContain(`y_label=`);
});
expect(dashboardDropdown).not.toEqual(null);
it('undefined parameter is stripped', done => {
wrapper.setProps({ currentDashboard: undefined });
wrapper.vm.$nextTick(() => {
expect(clipboardText()).not.toContain(`dashboard=`);
expect(clipboardText()).toContain(`y_label=`);
done();
});
});
it('null parameter is stripped', done => {
wrapper.setProps({ currentDashboard: null });
wrapper.vm.$nextTick(() => {
expect(clipboardText()).not.toContain(`dashboard=`);
expect(clipboardText()).toContain(`y_label=`);
done();
});
});
it('creates a toast when clicked', () => {
jest.spyOn(wrapper.vm.$toast, 'show').and.stub();
link().vm.$emit('click');
expect(wrapper.vm.$toast.show).toHaveBeenCalled();
});
});
});
import { mount, createLocalVue } from '@vue/test-utils';
import createFlash from '~/flash';
import Dashboard from '~/monitoring/components/dashboard.vue';
import { createStore } from '~/monitoring/stores';
import { propsData } from '../init_utils';
const localVue = createLocalVue();
jest.mock('~/flash');
jest.mock('~/lib/utils/url_utility', () => ({
getParameterValues: jest.fn().mockReturnValue('<script>alert("XSS")</script>'),
}));
describe('dashboard invalid url parameters', () => {
let store;
let wrapper;
const createMountedWrapper = (props = {}, options = {}) => {
wrapper = mount(localVue.extend(Dashboard), {
localVue,
sync: false,
propsData: { ...propsData, ...props },
store,
...options,
});
};
beforeEach(() => {
store = createStore();
});
afterEach(() => {
if (wrapper) {
wrapper.destroy();
}
});
it('shows an error message if invalid url parameters are passed', done => {
createMountedWrapper(
{ hasMetrics: true },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
wrapper.vm
.$nextTick()
.then(() => {
expect(createFlash).toHaveBeenCalled();
done();
})
.catch(done.fail);
});
});
import { mount, createLocalVue } from '@vue/test-utils';
import { GlDropdownItem } from '@gitlab/ui';
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import statusCodes from '~/lib/utils/http_status';
import Dashboard from '~/monitoring/components/dashboard.vue';
import { createStore } from '~/monitoring/stores';
import { propsData, setupComponentStore } from '../init_utils';
import { metricsGroupsAPIResponse, mockApiEndpoint } from '../mock_data';
const localVue = createLocalVue();
jest.mock('~/lib/utils/url_utility', () => ({
getParameterValues: jest.fn().mockImplementation(param => {
if (param === 'start') return ['2019-10-01T18:27:47.000Z'];
if (param === 'end') return ['2019-10-01T18:57:47.000Z'];
return [];
}),
mergeUrlParams: jest.fn().mockReturnValue('#'),
}));
describe('dashboard time window', () => {
let store;
let wrapper;
let mock;
const createComponentWrapperMounted = (props = {}, options = {}) => {
wrapper = mount(localVue.extend(Dashboard), {
localVue,
sync: false,
propsData: { ...propsData, ...props },
store,
...options,
});
};
beforeEach(() => {
store = createStore();
mock = new MockAdapter(axios);
});
afterEach(() => {
if (wrapper) {
wrapper.destroy();
}
mock.restore();
});
it('shows an error message if invalid url parameters are passed', done => {
mock.onGet(mockApiEndpoint).reply(statusCodes.OK, metricsGroupsAPIResponse);
createComponentWrapperMounted(
{ hasMetrics: true },
{ attachToDocument: true, stubs: ['graph-group', 'panel-type'] },
);
setupComponentStore(wrapper);
wrapper.vm
.$nextTick()
.then(() => {
const timeWindowDropdownItems = wrapper
.find('.js-time-window-dropdown')
.findAll(GlDropdownItem);
const activeItem = timeWindowDropdownItems.wrappers.filter(itemWrapper =>
itemWrapper.find('.active').exists(),
);
expect(activeItem.length).toBe(1);
done();
})
.catch(done.fail);
});
});
import * as types from '~/monitoring/stores/mutation_types';
import {
metricsGroupsAPIResponse,
mockedEmptyResult,
mockedQueryResultPayload,
mockedQueryResultPayloadCoresTotal,
mockApiEndpoint,
environmentData,
} from './mock_data';
export const propsData = {
hasMetrics: false,
documentationPath: '/path/to/docs',
settingsPath: '/path/to/settings',
clustersPath: '/path/to/clusters',
tagsPath: '/path/to/tags',
projectPath: '/path/to/project',
metricsEndpoint: mockApiEndpoint,
deploymentsEndpoint: null,
emptyGettingStartedSvgPath: '/path/to/getting-started.svg',
emptyLoadingSvgPath: '/path/to/loading.svg',
emptyNoDataSvgPath: '/path/to/no-data.svg',
emptyNoDataSmallSvgPath: '/path/to/no-data-small.svg',
emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
environmentsEndpoint: '/root/hello-prometheus/environments/35',
currentEnvironmentName: 'production',
customMetricsAvailable: false,
customMetricsPath: '',
validateQueryPath: '',
};
export const setupComponentStore = wrapper => {
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
metricsGroupsAPIResponse,
);
// Load 3 panels to the dashboard, one with an empty result
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedEmptyResult,
);
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayload,
);
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayloadCoresTotal,
);
wrapper.vm.$store.commit(
`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
environmentData,
);
};
import Vue from 'vue';
import { createLocalVue } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import Dashboard from '~/monitoring/components/dashboard.vue';
import * as types from '~/monitoring/stores/mutation_types';
import { createStore } from '~/monitoring/stores';
import axios from '~/lib/utils/axios_utils';
import {
metricsGroupsAPIResponse,
mockedEmptyResult,
mockedQueryResultPayload,
mockedQueryResultPayloadCoresTotal,
mockApiEndpoint,
environmentData,
} from '../mock_data';
const localVue = createLocalVue();
const propsData = {
hasMetrics: false,
documentationPath: '/path/to/docs',
settingsPath: '/path/to/settings',
clustersPath: '/path/to/clusters',
tagsPath: '/path/to/tags',
projectPath: '/path/to/project',
metricsEndpoint: mockApiEndpoint,
deploymentsEndpoint: null,
emptyGettingStartedSvgPath: '/path/to/getting-started.svg',
emptyLoadingSvgPath: '/path/to/loading.svg',
emptyNoDataSvgPath: '/path/to/no-data.svg',
emptyNoDataSmallSvgPath: '/path/to/no-data-small.svg',
emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
environmentsEndpoint: '/root/hello-prometheus/environments/35',
currentEnvironmentName: 'production',
customMetricsAvailable: false,
customMetricsPath: '',
validateQueryPath: '',
};
function setupComponentStore(component) {
// Load 2 panel groups
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
metricsGroupsAPIResponse,
);
// Load 3 panels to the dashboard, one with an empty result
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedEmptyResult,
);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayload,
);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRIC_RESULT_SUCCESS}`,
mockedQueryResultPayloadCoresTotal,
);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
environmentData,
);
}
describe('Dashboard', () => {
let DashboardComponent;
let mock;
let store;
let component;
let wrapper;
beforeEach(() => {
setFixtures(`
<div class="prometheus-graphs"></div>
<div class="layout-page"></div>
`);
store = createStore();
mock = new MockAdapter(axios);
DashboardComponent = localVue.extend(Dashboard);
});
afterEach(() => {
if (component) {
component.$destroy();
}
if (wrapper) {
wrapper.destroy();
}
mock.restore();
});
describe('responds to window resizes', () => {
let promPanel;
let promGroup;
let panelToggle;
let chart;
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
showPanels: true,
},
store,
});
setupComponentStore(component);
return Vue.nextTick().then(() => {
[, promPanel] = component.$el.querySelectorAll('.prometheus-panel');
promGroup = promPanel.querySelector('.prometheus-graph-group');
panelToggle = promPanel.querySelector('.js-graph-group-toggle');
chart = promGroup.querySelector('.position-relative svg');
});
});
it('setting chart size to zero when panel group is hidden', () => {
expect(promGroup.style.display).toBe('');
expect(chart.clientWidth).toBeGreaterThan(0);
panelToggle.click();
return Vue.nextTick().then(() => {
expect(promGroup.style.display).toBe('none');
expect(chart.clientWidth).toBe(0);
promPanel.style.width = '500px';
});
});
it('expanding chart panel group after resize displays chart', () => {
panelToggle.click();
expect(chart.clientWidth).toBeGreaterThan(0);
});
});
});
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