summaryrefslogtreecommitdiff
path: root/spec/frontend/monitoring
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-07 12:09:13 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-07 12:09:13 +0000
commit211a8c3361ccf4eb92f36edbdcf15c98fcdcc8b7 (patch)
tree0ad37172721a39b0d57240bb1b4e70f200a0d93e /spec/frontend/monitoring
parent456a7247f9e88fc2518b69a1a00e905c6db6d775 (diff)
downloadgitlab-ce-211a8c3361ccf4eb92f36edbdcf15c98fcdcc8b7.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/monitoring')
-rw-r--r--spec/frontend/monitoring/components/charts/time_series_spec.js59
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js40
-rw-r--r--spec/frontend/monitoring/components/dashboard_url_time_spec.js59
-rw-r--r--spec/frontend/monitoring/embed/embed_spec.js21
-rw-r--r--spec/frontend/monitoring/init_utils.js1
-rw-r--r--spec/frontend/monitoring/panel_type_spec.js146
-rw-r--r--spec/frontend/monitoring/store/mutations_spec.js10
7 files changed, 252 insertions, 84 deletions
diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js
index d4f197a708f..0a7e3dca183 100644
--- a/spec/frontend/monitoring/components/charts/time_series_spec.js
+++ b/spec/frontend/monitoring/components/charts/time_series_spec.js
@@ -18,6 +18,15 @@ import * as iconUtils from '~/lib/utils/icon_utils';
const mockWidgets = 'mockWidgets';
const mockSvgPathContent = 'mockSvgPathContent';
+
+jest.mock('lodash/throttle', () =>
+ // this throttle mock executes immediately
+ jest.fn(func => {
+ // eslint-disable-next-line no-param-reassign
+ func.cancel = jest.fn();
+ return func;
+ }),
+);
jest.mock('~/lib/utils/icon_utils', () => ({
getSvgIconPathContent: jest.fn().mockImplementation(() => Promise.resolve(mockSvgPathContent)),
}));
@@ -94,6 +103,56 @@ describe('Time series component', () => {
});
});
+ describe('events', () => {
+ describe('datazoom', () => {
+ let eChartMock;
+ let startValue;
+ let endValue;
+
+ const findChart = () => timeSeriesChart.find({ ref: 'chart' });
+
+ beforeEach(done => {
+ eChartMock = {
+ handlers: {},
+ getOption: () => ({
+ dataZoom: [
+ {
+ startValue,
+ endValue,
+ },
+ ],
+ }),
+ off: jest.fn(eChartEvent => {
+ delete eChartMock.handlers[eChartEvent];
+ }),
+ on: jest.fn((eChartEvent, fn) => {
+ eChartMock.handlers[eChartEvent] = fn;
+ }),
+ };
+
+ timeSeriesChart = makeTimeSeriesChart(mockGraphData);
+ timeSeriesChart.vm.$nextTick(() => {
+ findChart().vm.$emit('created', eChartMock);
+ done();
+ });
+ });
+
+ it('handles datazoom event from chart', () => {
+ startValue = 1577836800000; // 2020-01-01T00:00:00.000Z
+ endValue = 1577840400000; // 2020-01-01T01:00:00.000Z
+ eChartMock.handlers.datazoom();
+
+ expect(timeSeriesChart.emitted('datazoom')).toHaveLength(1);
+ expect(timeSeriesChart.emitted('datazoom')[0]).toEqual([
+ {
+ start: new Date(startValue).toISOString(),
+ end: new Date(endValue).toISOString(),
+ },
+ ]);
+ });
+ });
+ });
+
describe('methods', () => {
describe('formatTooltipText', () => {
let mockDate;
diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js
index 31266b4f6d4..70b2c9cf527 100644
--- a/spec/frontend/monitoring/components/dashboard_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_spec.js
@@ -73,12 +73,20 @@ describe('Dashboard', () => {
describe('no metrics are available yet', () => {
beforeEach(() => {
+ jest.spyOn(store, 'dispatch');
createShallowWrapper();
});
it('shows the environment selector', () => {
expect(findEnvironmentsDropdown().exists()).toBe(true);
});
+
+ it('sets endpoints: logs path', () => {
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'monitoringDashboard/setEndpoints',
+ expect.objectContaining({ logsPath: propsData.logsPath }),
+ );
+ });
});
describe('no data found', () => {
@@ -94,6 +102,21 @@ describe('Dashboard', () => {
});
describe('request information to the server', () => {
+ it('calls to set time range and fetch data', () => {
+ jest.spyOn(store, 'dispatch');
+
+ createShallowWrapper({ hasMetrics: true }, { methods: {} });
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'monitoringDashboard/setTimeRange',
+ expect.any(Object),
+ );
+
+ expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/fetchData', undefined);
+ });
+ });
+
it('shows up a loading state', done => {
createShallowWrapper({ hasMetrics: true }, { methods: {} });
@@ -126,7 +149,7 @@ describe('Dashboard', () => {
.catch(done.fail);
});
- it('fetches the metrics data with proper time window', done => {
+ it('fetches the metrics data with proper time window', () => {
jest.spyOn(store, 'dispatch');
createMountedWrapper({ hasMetrics: true }, { stubs: ['graph-group', 'panel-type'] });
@@ -136,14 +159,9 @@ describe('Dashboard', () => {
environmentData,
);
- wrapper.vm
- .$nextTick()
- .then(() => {
- expect(store.dispatch).toHaveBeenCalled();
-
- done();
- })
- .catch(done.fail);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(store.dispatch).toHaveBeenCalled();
+ });
});
});
@@ -263,10 +281,6 @@ describe('Dashboard', () => {
return wrapper.vm.$nextTick();
});
- afterEach(() => {
- wrapper.destroy();
- });
-
it('renders a search input', () => {
expect(wrapper.find({ ref: 'monitorEnvironmentsDropdownSearch' }).exists()).toBe(true);
});
diff --git a/spec/frontend/monitoring/components/dashboard_url_time_spec.js b/spec/frontend/monitoring/components/dashboard_url_time_spec.js
index 33fbfac486f..161c64dd74b 100644
--- a/spec/frontend/monitoring/components/dashboard_url_time_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_url_time_spec.js
@@ -7,6 +7,7 @@ import { mockProjectDir } from '../mock_data';
import Dashboard from '~/monitoring/components/dashboard.vue';
import { createStore } from '~/monitoring/stores';
+import { defaultTimeRange } from '~/monitoring/constants';
import { propsData } from '../init_utils';
jest.mock('~/flash');
@@ -17,16 +18,11 @@ describe('dashboard invalid url parameters', () => {
let wrapper;
let mock;
- const fetchDataMock = jest.fn();
-
const createMountedWrapper = (props = { hasMetrics: true }, options = {}) => {
wrapper = mount(Dashboard, {
propsData: { ...propsData, ...props },
store,
stubs: ['graph-group', 'panel-type'],
- methods: {
- fetchData: fetchDataMock,
- },
...options,
});
};
@@ -35,6 +31,8 @@ describe('dashboard invalid url parameters', () => {
beforeEach(() => {
store = createStore();
+ jest.spyOn(store, 'dispatch');
+
mock = new MockAdapter(axios);
});
@@ -43,7 +41,6 @@ describe('dashboard invalid url parameters', () => {
wrapper.destroy();
}
mock.restore();
- fetchDataMock.mockReset();
queryToObject.mockReset();
});
@@ -53,15 +50,13 @@ describe('dashboard invalid url parameters', () => {
createMountedWrapper();
return wrapper.vm.$nextTick().then(() => {
- expect(findDateTimePicker().props('value')).toMatchObject({
- duration: { seconds: 28800 },
- });
+ expect(findDateTimePicker().props('value')).toEqual(defaultTimeRange);
- expect(fetchDataMock).toHaveBeenCalledTimes(1);
- expect(fetchDataMock).toHaveBeenCalledWith({
- start: expect.any(String),
- end: expect.any(String),
- });
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'monitoringDashboard/setTimeRange',
+ expect.any(Object),
+ );
+ expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/fetchData', undefined);
});
});
@@ -78,8 +73,8 @@ describe('dashboard invalid url parameters', () => {
return wrapper.vm.$nextTick().then(() => {
expect(findDateTimePicker().props('value')).toEqual(params);
- expect(fetchDataMock).toHaveBeenCalledTimes(1);
- expect(fetchDataMock).toHaveBeenCalledWith(params);
+ expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/setTimeRange', params);
+ expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/fetchData', undefined);
});
});
@@ -91,15 +86,17 @@ describe('dashboard invalid url parameters', () => {
createMountedWrapper();
return wrapper.vm.$nextTick().then(() => {
- expect(findDateTimePicker().props('value')).toMatchObject({
+ const expectedTimeRange = {
duration: { seconds: 60 * 2 },
- });
+ };
- expect(fetchDataMock).toHaveBeenCalledTimes(1);
- expect(fetchDataMock).toHaveBeenCalledWith({
- start: expect.any(String),
- end: expect.any(String),
- });
+ expect(findDateTimePicker().props('value')).toMatchObject(expectedTimeRange);
+
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'monitoringDashboard/setTimeRange',
+ expectedTimeRange,
+ );
+ expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/fetchData', undefined);
});
});
@@ -114,15 +111,13 @@ describe('dashboard invalid url parameters', () => {
return wrapper.vm.$nextTick().then(() => {
expect(createFlash).toHaveBeenCalled();
- expect(findDateTimePicker().props('value')).toMatchObject({
- duration: { seconds: 28800 },
- });
+ expect(findDateTimePicker().props('value')).toEqual(defaultTimeRange);
- expect(fetchDataMock).toHaveBeenCalledTimes(1);
- expect(fetchDataMock).toHaveBeenCalledWith({
- start: expect.any(String),
- end: expect.any(String),
- });
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'monitoringDashboard/setTimeRange',
+ defaultTimeRange,
+ );
+ expect(store.dispatch).toHaveBeenCalledWith('monitoringDashboard/fetchData', undefined);
});
});
@@ -137,7 +132,7 @@ describe('dashboard invalid url parameters', () => {
duration: { seconds: 120 },
});
- // redirect to plus + new parameters
+ // redirect to with new parameters
expect(mergeUrlParams).toHaveBeenCalledWith({ duration_seconds: '120' }, toUrl);
expect(redirectTo).toHaveBeenCalledTimes(1);
});
diff --git a/spec/frontend/monitoring/embed/embed_spec.js b/spec/frontend/monitoring/embed/embed_spec.js
index 831ab1ed157..3bb70a02bd9 100644
--- a/spec/frontend/monitoring/embed/embed_spec.js
+++ b/spec/frontend/monitoring/embed/embed_spec.js
@@ -26,10 +26,11 @@ describe('Embed', () => {
beforeEach(() => {
actions = {
- setFeatureFlags: () => {},
- setShowErrorBanner: () => {},
- setEndpoints: () => {},
- fetchMetricsData: () => {},
+ setFeatureFlags: jest.fn(),
+ setShowErrorBanner: jest.fn(),
+ setEndpoints: jest.fn(),
+ setTimeRange: jest.fn(),
+ fetchDashboard: jest.fn(),
};
metricsWithDataGetter = jest.fn();
@@ -76,6 +77,18 @@ describe('Embed', () => {
mountComponent();
});
+ it('calls actions to fetch data', () => {
+ const expectedTimeRangePayload = expect.objectContaining({
+ start: expect.any(String),
+ end: expect.any(String),
+ });
+
+ expect(actions.setTimeRange).toHaveBeenCalledTimes(1);
+ expect(actions.setTimeRange.mock.calls[0][1]).toEqual(expectedTimeRangePayload);
+
+ expect(actions.fetchDashboard).toHaveBeenCalled();
+ });
+
it('shows a chart when metrics are present', () => {
expect(wrapper.find('.metrics-embed').exists()).toBe(true);
expect(wrapper.find(PanelType).exists()).toBe(true);
diff --git a/spec/frontend/monitoring/init_utils.js b/spec/frontend/monitoring/init_utils.js
index 30c64a8d885..36c654ba7b3 100644
--- a/spec/frontend/monitoring/init_utils.js
+++ b/spec/frontend/monitoring/init_utils.js
@@ -15,6 +15,7 @@ export const propsData = {
clustersPath: '/path/to/clusters',
tagsPath: '/path/to/tags',
projectPath: '/path/to/project',
+ logsPath: '/path/to/logs',
defaultBranch: 'master',
metricsEndpoint: mockApiEndpoint,
deploymentsEndpoint: null,
diff --git a/spec/frontend/monitoring/panel_type_spec.js b/spec/frontend/monitoring/panel_type_spec.js
index e51b69ef14d..730d67f79d8 100644
--- a/spec/frontend/monitoring/panel_type_spec.js
+++ b/spec/frontend/monitoring/panel_type_spec.js
@@ -1,6 +1,7 @@
import { shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
import { setTestTimeout } from 'helpers/timeout';
+import invalidUrl from '~/lib/utils/invalid_url';
import axios from '~/lib/utils/axios_utils';
import PanelType from '~/monitoring/components/panel_type.vue';
import EmptyChart from '~/monitoring/components/charts/empty_chart.vue';
@@ -16,20 +17,25 @@ global.URL.createObjectURL = jest.fn();
describe('Panel Type component', () => {
let axiosMock;
let store;
- let panelType;
- const dashboardWidth = 100;
+ let state;
+ let wrapper;
const exampleText = 'example_text';
- const createWrapper = props =>
- shallowMount(PanelType, {
+ const createWrapper = props => {
+ wrapper = shallowMount(PanelType, {
propsData: {
...props,
},
store,
});
+ };
beforeEach(() => {
setTestTimeout(1000);
+
+ store = createStore();
+ state = store.state.monitoringDashboard;
+
axiosMock = new AxiosMockAdapter(axios);
});
@@ -44,19 +50,18 @@ describe('Panel Type component', () => {
graphDataNoResult.metrics[0].result = [];
beforeEach(() => {
- panelType = createWrapper({
- dashboardWidth,
+ createWrapper({
graphData: graphDataNoResult,
});
});
afterEach(() => {
- panelType.destroy();
+ wrapper.destroy();
});
describe('Empty Chart component', () => {
beforeEach(() => {
- glEmptyChart = panelType.find(EmptyChart);
+ glEmptyChart = wrapper.find(EmptyChart);
});
it('is a Vue instance', () => {
@@ -66,51 +71,126 @@ describe('Panel Type component', () => {
it('it receives a graph title', () => {
const props = glEmptyChart.props();
- expect(props.graphTitle).toBe(panelType.vm.graphData.title);
+ expect(props.graphTitle).toBe(wrapper.vm.graphData.title);
});
});
});
describe('when graph data is available', () => {
beforeEach(() => {
- store = createStore();
- panelType = createWrapper({
- dashboardWidth,
+ createWrapper({
graphData: graphDataPrometheusQueryRange,
});
});
afterEach(() => {
- panelType.destroy();
+ wrapper.destroy();
});
it('sets no clipboard copy link on dropdown by default', () => {
- const link = () => panelType.find('.js-chart-link');
+ const link = () => wrapper.find('.js-chart-link');
expect(link().exists()).toBe(false);
});
describe('Time Series Chart panel type', () => {
it('is rendered', () => {
- expect(panelType.find(TimeSeriesChart).isVueInstance()).toBe(true);
- expect(panelType.find(TimeSeriesChart).exists()).toBe(true);
+ expect(wrapper.find(TimeSeriesChart).isVueInstance()).toBe(true);
+ expect(wrapper.find(TimeSeriesChart).exists()).toBe(true);
});
it('includes a default group id', () => {
- expect(panelType.vm.groupId).toBe('panel-type-chart');
+ expect(wrapper.vm.groupId).toBe('panel-type-chart');
});
});
describe('Anomaly Chart panel type', () => {
- beforeEach(done => {
- panelType.setProps({
+ beforeEach(() => {
+ wrapper.setProps({
graphData: anomalyMockGraphData,
});
- panelType.vm.$nextTick(done);
+ return wrapper.vm.$nextTick();
});
it('is rendered with an anomaly chart', () => {
- expect(panelType.find(AnomalyChart).isVueInstance()).toBe(true);
- expect(panelType.find(AnomalyChart).exists()).toBe(true);
+ expect(wrapper.find(AnomalyChart).isVueInstance()).toBe(true);
+ expect(wrapper.find(AnomalyChart).exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('View Logs dropdown item', () => {
+ const mockLogsPath = '/path/to/logs';
+ const mockTimeRange = { duration: { seconds: 120 } };
+
+ const findTimeChart = () => wrapper.find({ ref: 'timeChart' });
+ const findViewLogsLink = () => wrapper.find({ ref: 'viewLogsLink' });
+
+ beforeEach(() => {
+ createWrapper({
+ graphData: graphDataPrometheusQueryRange,
+ });
+ return wrapper.vm.$nextTick();
+ });
+
+ it('is not present by default', () =>
+ wrapper.vm.$nextTick(() => {
+ expect(findViewLogsLink().exists()).toBe(false);
+ }));
+
+ it('is not present if a time range is not set', () => {
+ state.logsPath = mockLogsPath;
+ state.timeRange = null;
+
+ return wrapper.vm.$nextTick(() => {
+ expect(findViewLogsLink().exists()).toBe(false);
+ });
+ });
+
+ it('is not present if the logs path is default', () => {
+ state.logsPath = invalidUrl;
+ state.timeRange = mockTimeRange;
+
+ return wrapper.vm.$nextTick(() => {
+ expect(findViewLogsLink().exists()).toBe(false);
+ });
+ });
+
+ it('is not present if the logs path is not set', () => {
+ state.logsPath = null;
+ state.timeRange = mockTimeRange;
+
+ return wrapper.vm.$nextTick(() => {
+ expect(findViewLogsLink().exists()).toBe(false);
+ });
+ });
+
+ it('is present when logs path and time a range is present', () => {
+ state.logsPath = mockLogsPath;
+ state.timeRange = mockTimeRange;
+
+ return wrapper.vm.$nextTick(() => {
+ const href = `${mockLogsPath}?duration_seconds=${mockTimeRange.duration.seconds}`;
+ expect(findViewLogsLink().attributes('href')).toMatch(href);
+ });
+ });
+
+ it('it is overriden when a datazoom event is received', () => {
+ state.logsPath = mockLogsPath;
+ state.timeRange = mockTimeRange;
+
+ const zoomedTimeRange = {
+ start: '2020-01-01T00:00:00.000Z',
+ end: '2020-01-01T01:00:00.000Z',
+ };
+
+ findTimeChart().vm.$emit('datazoom', zoomedTimeRange);
+
+ return wrapper.vm.$nextTick(() => {
+ const start = encodeURIComponent(zoomedTimeRange.start);
+ const end = encodeURIComponent(zoomedTimeRange.end);
+ expect(findViewLogsLink().attributes('href')).toMatch(
+ `${mockLogsPath}?start=${start}&end=${end}`,
+ );
});
});
});
@@ -119,20 +199,18 @@ describe('Panel Type component', () => {
const clipboardText = 'A value to copy.';
beforeEach(() => {
- store = createStore();
- panelType = createWrapper({
+ createWrapper({
clipboardText,
- dashboardWidth,
graphData: graphDataPrometheusQueryRange,
});
});
afterEach(() => {
- panelType.destroy();
+ wrapper.destroy();
});
it('sets clipboard text on the dropdown', () => {
- const link = () => panelType.find('.js-chart-link');
+ const link = () => wrapper.find('.js-chart-link');
expect(link().exists()).toBe(true);
expect(link().element.dataset.clipboardText).toBe(clipboardText);
@@ -140,22 +218,20 @@ describe('Panel Type component', () => {
});
describe('when downloading metrics data as CSV', () => {
- beforeEach(done => {
+ beforeEach(() => {
graphDataPrometheusQueryRange.y_label = 'metric';
- store = createStore();
- panelType = shallowMount(PanelType, {
+ wrapper = shallowMount(PanelType, {
propsData: {
clipboardText: exampleText,
- dashboardWidth,
graphData: graphDataPrometheusQueryRange,
},
store,
});
- panelType.vm.$nextTick(done);
+ return wrapper.vm.$nextTick();
});
afterEach(() => {
- panelType.destroy();
+ wrapper.destroy();
});
describe('csvText', () => {
@@ -165,7 +241,7 @@ describe('Panel Type component', () => {
const firstRow = `${data[0][0]},${data[0][1]}`;
const secondRow = `${data[1][0]},${data[1][1]}`;
- expect(panelType.vm.csvText).toBe(`${header}\r\n${firstRow}\r\n${secondRow}\r\n`);
+ expect(wrapper.vm.csvText).toBe(`${header}\r\n${firstRow}\r\n${secondRow}\r\n`);
});
});
@@ -174,7 +250,7 @@ describe('Panel Type component', () => {
expect(global.URL.createObjectURL).toHaveBeenLastCalledWith(expect.any(Blob));
expect(global.URL.createObjectURL).toHaveBeenLastCalledWith(
expect.objectContaining({
- size: panelType.vm.csvText.length,
+ size: wrapper.vm.csvText.length,
type: 'text/plain',
}),
);
diff --git a/spec/frontend/monitoring/store/mutations_spec.js b/spec/frontend/monitoring/store/mutations_spec.js
index 7f8ced8cf43..b0ac42e0e5f 100644
--- a/spec/frontend/monitoring/store/mutations_spec.js
+++ b/spec/frontend/monitoring/store/mutations_spec.js
@@ -90,6 +90,16 @@ describe('Monitoring mutations', () => {
expect(stateCopy.dashboardEndpoint).toEqual('dashboard.json');
expect(stateCopy.projectPath).toEqual('/gitlab-org/gitlab-foss');
});
+
+ it('should not remove default value of logsPath', () => {
+ const defaultLogsPath = stateCopy.logsPath;
+
+ mutations[types.SET_ENDPOINTS](stateCopy, {
+ dashboardEndpoint: 'dashboard.json',
+ });
+
+ expect(stateCopy.logsPath).toBe(defaultLogsPath);
+ });
});
describe('Individual panel/metric results', () => {
const metricId = '12_system_metrics_kubernetes_container_memory_total';