summaryrefslogtreecommitdiff
path: root/spec/javascripts/monitoring/components/dashboard_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/javascripts/monitoring/components/dashboard_spec.js')
-rw-r--r--spec/javascripts/monitoring/components/dashboard_spec.js432
1 files changed, 232 insertions, 200 deletions
diff --git a/spec/javascripts/monitoring/components/dashboard_spec.js b/spec/javascripts/monitoring/components/dashboard_spec.js
index 75df2ce3103..0f20171726c 100644
--- a/spec/javascripts/monitoring/components/dashboard_spec.js
+++ b/spec/javascripts/monitoring/components/dashboard_spec.js
@@ -7,11 +7,12 @@ 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 MonitoringMock, {
+import {
metricsGroupsAPIResponse,
+ mockedQueryResultPayload,
+ mockedQueryResultPayloadCoresTotal,
mockApiEndpoint,
environmentData,
- singleGroupResponse,
dashboardGitResponse,
} from '../mock_data';
@@ -44,12 +45,33 @@ const resetSpy = spy => {
export default propsData;
+function setupComponentStore(component) {
+ component.$store.commit(
+ `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
+ metricsGroupsAPIResponse,
+ );
+
+ // Load 2 panels to the dashboard
+ component.$store.commit(
+ `monitoringDashboard/${types.SET_QUERY_RESULT}`,
+ mockedQueryResultPayload,
+ );
+ component.$store.commit(
+ `monitoringDashboard/${types.SET_QUERY_RESULT}`,
+ mockedQueryResultPayloadCoresTotal,
+ );
+
+ component.$store.commit(
+ `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
+ environmentData,
+ );
+}
+
describe('Dashboard', () => {
let DashboardComponent;
let mock;
let store;
let component;
- let mockGraphData;
beforeEach(() => {
setFixtures(`
@@ -100,6 +122,32 @@ describe('Dashboard', () => {
});
});
+ describe('cluster health', () => {
+ let wrapper;
+
+ beforeEach(done => {
+ wrapper = shallowMount(DashboardComponent, {
+ localVue,
+ sync: false,
+ propsData: { ...propsData, hasMetrics: true },
+ store,
+ });
+
+ // 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('renders correctly', () => {
+ expect(wrapper.isVueInstance()).toBe(true);
+ expect(wrapper.exists()).toBe(true);
+ });
+ });
+
describe('requests information to the server', () => {
let spy;
beforeEach(() => {
@@ -123,25 +171,6 @@ describe('Dashboard', () => {
});
});
- it('hides the legend when showLegend is false', done => {
- component = new DashboardComponent({
- el: document.querySelector('.prometheus-graphs'),
- propsData: {
- ...propsData,
- hasMetrics: true,
- showLegend: false,
- },
- store,
- });
-
- setTimeout(() => {
- expect(component.showEmptyState).toEqual(false);
- expect(component.$el.querySelector('.legend-group')).toEqual(null);
- expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy();
- done();
- });
- });
-
it('hides the group panels when showPanels is false', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
@@ -153,52 +182,66 @@ describe('Dashboard', () => {
store,
});
- setTimeout(() => {
- expect(component.showEmptyState).toEqual(false);
- expect(component.$el.querySelector('.prometheus-panel')).toEqual(null);
- expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy();
- done();
- });
+ setupComponentStore(component);
+
+ Vue.nextTick()
+ .then(() => {
+ expect(component.showEmptyState).toEqual(false);
+ expect(component.$el.querySelector('.prometheus-panel')).toEqual(null);
+ expect(component.$el.querySelector('.prometheus-graph-group')).toBeTruthy();
+
+ done();
+ })
+ .catch(done.fail);
});
- it('renders the environments dropdown with a number of environments', done => {
- component = new DashboardComponent({
- el: document.querySelector('.prometheus-graphs'),
- propsData: {
- ...propsData,
- hasMetrics: true,
- showPanels: false,
- },
- store,
+ 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);
});
- component.$store.commit(
- `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
- environmentData,
- );
- component.$store.commit(
- `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
- singleGroupResponse,
- );
+ it('renders the environments dropdown with a number of environments', done => {
+ Vue.nextTick()
+ .then(() => {
+ const dropdownMenuEnvironments = component.$el.querySelectorAll(
+ '.js-environments-dropdown .dropdown-item',
+ );
- 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);
- 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);
+ }
+ });
- Array.from(dropdownMenuEnvironments).forEach((value, index) => {
- if (environmentData[index].metrics_path) {
- expect(value).toHaveAttr('href', environmentData[index].metrics_path);
- }
- });
+ done();
+ })
+ .catch(done.fail);
+ });
- 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 => {
@@ -207,15 +250,17 @@ describe('Dashboard', () => {
propsData: {
...propsData,
hasMetrics: true,
- showPanels: false,
},
store,
});
- component.$store.commit(`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`, []);
component.$store.commit(
`monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
- singleGroupResponse,
+ metricsGroupsAPIResponse,
+ );
+ component.$store.commit(
+ `monitoringDashboard/${types.SET_QUERY_RESULT}`,
+ mockedQueryResultPayload,
);
Vue.nextTick()
@@ -230,7 +275,7 @@ describe('Dashboard', () => {
.catch(done.fail);
});
- it('renders the environments dropdown with a single active element', done => {
+ it('renders the datetimepicker dropdown', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
@@ -241,64 +286,16 @@ describe('Dashboard', () => {
store,
});
- component.$store.commit(
- `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
- environmentData,
- );
- component.$store.commit(
- `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
- singleGroupResponse,
- );
+ setupComponentStore(component);
Vue.nextTick()
.then(() => {
- const dropdownItems = component.$el.querySelectorAll(
- '.js-environments-dropdown .dropdown-item.active',
- );
-
- expect(dropdownItems.length).toEqual(1);
+ expect(component.$el.querySelector('.js-time-window-dropdown')).not.toBeNull();
done();
})
.catch(done.fail);
});
- it('hides the dropdown', done => {
- component = new DashboardComponent({
- el: document.querySelector('.prometheus-graphs'),
- propsData: {
- ...propsData,
- hasMetrics: true,
- showPanels: false,
- environmentsEndpoint: '',
- },
- store,
- });
-
- Vue.nextTick(() => {
- const dropdownIsActiveElement = component.$el.querySelectorAll('.environments');
-
- expect(dropdownIsActiveElement.length).toEqual(0);
- done();
- });
- });
-
- it('renders the datetimepicker dropdown', done => {
- component = new DashboardComponent({
- el: document.querySelector('.prometheus-graphs'),
- propsData: {
- ...propsData,
- hasMetrics: true,
- showPanels: false,
- },
- store,
- });
-
- setTimeout(() => {
- expect(component.$el.querySelector('.js-time-window-dropdown')).not.toBeNull();
- done();
- });
- });
-
it('fetches the metrics data with proper time window', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
@@ -347,14 +344,21 @@ describe('Dashboard', () => {
el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData, hasMetrics: true },
store,
+ sync: false,
});
- setTimeout(() => {
- const selectedTimeWindow = component.$el.querySelector('.js-time-window-dropdown .active');
+ setupComponentStore(component);
- expect(selectedTimeWindow.textContent.trim()).toEqual('30 minutes');
- done();
- });
+ Vue.nextTick()
+ .then(() => {
+ const selectedTimeWindow = component.$el.querySelector(
+ '.js-time-window-dropdown .active',
+ );
+
+ expect(selectedTimeWindow.textContent.trim()).toEqual('30 minutes');
+ done();
+ })
+ .catch(done.fail);
});
it('shows an error message if invalid url parameters are passed', done => {
@@ -381,29 +385,36 @@ describe('Dashboard', () => {
describe('drag and drop function', () => {
let wrapper;
let expectedPanelCount; // also called metrics, naming to be improved: https://gitlab.com/gitlab-org/gitlab/issues/31565
+
const findDraggables = () => wrapper.findAll(VueDraggable);
const findEnabledDraggables = () => findDraggables().filter(f => !f.attributes('disabled'));
const findDraggablePanels = () => wrapper.findAll('.js-draggable-panel');
const findRearrangeButton = () => wrapper.find('.js-rearrange-button');
- beforeEach(done => {
+ beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
- expectedPanelCount = metricsGroupsAPIResponse.data.reduce(
- (acc, d) => d.metrics.length + acc,
+ expectedPanelCount = metricsGroupsAPIResponse.reduce(
+ (acc, group) => group.panels.length + acc,
0,
);
- store.dispatch('monitoringDashboard/setFeatureFlags', { additionalPanelTypesEnabled: true });
+ });
+ beforeEach(done => {
wrapper = shallowMount(DashboardComponent, {
localVue,
sync: false,
propsData: { ...propsData, hasMetrics: true },
store,
+ attachToDocument: true,
});
- // not using $nextTicket becuase we must wait for the dashboard
- // to be populated with the mock data results.
- setTimeout(done);
+ setupComponentStore(wrapper.vm);
+
+ wrapper.vm.$nextTick(done);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
});
it('wraps vuedraggable', () => {
@@ -442,6 +453,28 @@ describe('Dashboard', () => {
expect(findEnabledDraggables()).toEqual(findDraggables());
});
+ it('metrics can be swapped', done => {
+ const firstDraggable = findDraggables().at(0);
+ const mockMetrics = [...metricsGroupsAPIResponse[0].panels];
+ const value = () => firstDraggable.props('value');
+
+ expect(value().length).toBe(mockMetrics.length);
+ value().forEach((metric, i) => {
+ expect(metric.title).toBe(mockMetrics[i].title);
+ });
+
+ // swap two elements and `input` them
+ [mockMetrics[0], mockMetrics[1]] = [mockMetrics[1], mockMetrics[0]];
+ firstDraggable.vm.$emit('input', mockMetrics);
+
+ firstDraggable.vm.$nextTick(() => {
+ value().forEach((metric, i) => {
+ expect(metric.title).toBe(mockMetrics[i].title);
+ });
+ done();
+ });
+ });
+
it('shows a remove button, which removes a panel', done => {
expect(findFirstDraggableRemoveButton().isEmpty()).toBe(false);
@@ -449,8 +482,6 @@ describe('Dashboard', () => {
findFirstDraggableRemoveButton().trigger('click');
wrapper.vm.$nextTick(() => {
- // At present graphs will not be removed in backend
- // See https://gitlab.com/gitlab-org/gitlab/issues/27835
expect(findDraggablePanels().length).toEqual(expectedPanelCount - 1);
done();
});
@@ -466,10 +497,6 @@ describe('Dashboard', () => {
});
});
});
-
- afterEach(() => {
- wrapper.destroy();
- });
});
// https://gitlab.com/gitlab-org/gitlab-ce/issues/66922
@@ -539,42 +566,93 @@ describe('Dashboard', () => {
});
});
- describe('when the window resizes', () => {
+ describe('responds to window resizes', () => {
+ let promPanel;
+ let promGroup;
+ let panelToggle;
+ let chart;
beforeEach(() => {
mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
- jasmine.clock().install();
- });
- afterEach(() => {
- jasmine.clock().uninstall();
- });
-
- it('sets elWidth to page width when the sidebar is resized', done => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: {
...propsData,
hasMetrics: true,
- showPanels: false,
+ showPanels: true,
},
store,
});
- expect(component.elWidth).toEqual(0);
+ setupComponentStore(component);
- const pageLayoutEl = document.querySelector('.layout-page');
- pageLayoutEl.classList.add('page-with-icon-sidebar');
+ return Vue.nextTick().then(() => {
+ promPanel = component.$el.querySelector('.prometheus-panel');
+ promGroup = promPanel.querySelector('.prometheus-graph-group');
+ panelToggle = promPanel.querySelector('.js-graph-group-toggle');
+ chart = promGroup.querySelector('.position-relative svg');
+ });
+ });
- Vue.nextTick()
- .then(() => {
- jasmine.clock().tick(1000);
- return Vue.nextTick();
- })
- .then(() => {
- expect(component.elWidth).toEqual(pageLayoutEl.clientWidth);
- done();
- })
- .catch(done.fail);
+ 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);
+ });
+ });
+
+ describe('dashboard edit link', () => {
+ let wrapper;
+ const findEditLink = () => wrapper.find('.js-edit-link');
+
+ beforeEach(done => {
+ mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
+
+ wrapper = shallowMount(DashboardComponent, {
+ localVue,
+ sync: false,
+ attachToDocument: true,
+ propsData: { ...propsData, hasMetrics: true },
+ store,
+ });
+
+ wrapper.vm.$store.commit(
+ `monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
+ dashboardGitResponse,
+ );
+ wrapper.vm.$nextTick(done);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('is not present for the default dashboard', () => {
+ expect(findEditLink().exists()).toBe(false);
+ });
+
+ it('is present for a custom dashboard, and links to its edit_path', done => {
+ const dashboard = dashboardGitResponse[1]; // non-default 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();
+ });
});
});
@@ -619,20 +697,6 @@ describe('Dashboard', () => {
store,
});
- component.$store.dispatch('monitoringDashboard/setFeatureFlags', {
- prometheusEndpoint: false,
- });
-
- component.$store.commit(
- `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
- environmentData,
- );
-
- component.$store.commit(
- `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
- singleGroupResponse,
- );
-
component.$store.commit(
`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
dashboardGitResponse,
@@ -648,36 +712,4 @@ describe('Dashboard', () => {
});
});
});
-
- describe('when downloading metrics data as CSV', () => {
- beforeEach(() => {
- component = new DashboardComponent({
- propsData: {
- ...propsData,
- },
- store,
- });
- store.commit(
- `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
- MonitoringMock.data,
- );
- [mockGraphData] = component.$store.state.monitoringDashboard.groups[0].metrics;
- });
-
- describe('csvText', () => {
- it('converts metrics data from json to csv', () => {
- const header = `timestamp,${mockGraphData.y_label}`;
- const data = mockGraphData.queries[0].result[0].values;
- const firstRow = `${data[0][0]},${data[0][1]}`;
-
- expect(component.csvText(mockGraphData)).toMatch(`^${header}\r\n${firstRow}`);
- });
- });
-
- describe('downloadCsv', () => {
- it('produces a link with a Blob', () => {
- expect(component.downloadCsv(mockGraphData)).toContain(`blob:`);
- });
- });
- });
});