Commit 24b51f5c authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '214458-reduce-panel-type-code' into 'master'

Refactor test code for panel type

See merge request gitlab-org/gitlab!29677
parents 3660169a cebbda09
......@@ -3,12 +3,6 @@ import chartEmptyStateIllustration from '@gitlab/svgs/dist/illustrations/chart-e
import { chartHeight } from '../../constants';
export default {
props: {
graphTitle: {
type: String,
required: true,
},
},
data() {
return {
height: chartHeight,
......
......@@ -4,6 +4,7 @@ import { pickBy } from 'lodash';
import invalidUrl from '~/lib/utils/invalid_url';
import {
GlResizeObserverDirective,
GlIcon,
GlLoadingIcon,
GlDropdown,
GlDropdownItem,
......@@ -13,7 +14,6 @@ import {
GlTooltipDirective,
} from '@gitlab/ui';
import { __, n__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import MonitorTimeSeriesChart from './charts/time_series.vue';
import MonitorAnomalyChart from './charts/anomaly.vue';
import MonitorSingleStatChart from './charts/single_stat.vue';
......@@ -37,7 +37,7 @@ export default {
MonitorHeatmapChart,
MonitorStackedColumnChart,
MonitorEmptyChart,
Icon,
GlIcon,
GlLoadingIcon,
GlTooltip,
GlDropdown,
......@@ -227,7 +227,7 @@ export default {
</div>
<div
v-if="isContextualMenuShown"
class="js-graph-widgets"
ref="contextualMenu"
data-qa-selector="prometheus_graph_widgets"
>
<div class="d-flex align-items-center">
......@@ -240,7 +240,7 @@ export default {
:title="__('More actions')"
>
<template slot="button-content">
<icon name="ellipsis_v" class="text-secondary" />
<gl-icon name="ellipsis_v" class="text-secondary" />
</template>
<gl-dropdown-item
v-if="editCustomMetricLink"
......@@ -319,6 +319,6 @@ export default {
:group-id="groupId"
@datazoom="onDatazoom"
/>
<monitor-empty-chart v-else :graph-title="title" v-bind="$attrs" v-on="$listeners" />
<monitor-empty-chart v-else v-bind="$attrs" v-on="$listeners" />
</div>
</template>
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import { shallowMount } from '@vue/test-utils';
import { GlDropdownItem } from '@gitlab/ui';
import { monitoringDashboard } from '~/monitoring/stores';
import PanelType from 'ee/monitoring/components/panel_type.vue';
import AlertWidget from 'ee/monitoring/components/alert_widget.vue';
import { graphDataPrometheusQueryRange } from 'jest/monitoring/mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
import { graphData } from 'jest/monitoring/fixture_data';
global.URL.createObjectURL = jest.fn();
......@@ -23,7 +19,7 @@ describe('Panel Type', () => {
wrapper.findAll(GlDropdownItem).filter(i => i.text() === 'Alerts');
const mockPropsData = {
graphData: graphDataPrometheusQueryRange,
graphData,
clipboardText: 'example_text',
alertsEndpoint: '/endpoint',
prometheusAlertsAvailable: true,
......@@ -36,7 +32,6 @@ describe('Panel Type', () => {
...propsData,
},
store,
localVue,
});
};
......@@ -54,8 +49,8 @@ describe('Panel Type', () => {
describe.each`
desc | metricsSavedToDb | propsData | isShown
${'with license and no metrics in db'} | ${[]} | ${{}} | ${false}
${'with license and related metrics in db'} | ${[graphDataPrometheusQueryRange.metrics[0].metricId]} | ${{}} | ${true}
${'without license and related metrics in db'} | ${[graphDataPrometheusQueryRange.metrics[0].metricId]} | ${{ prometheusAlertsAvailable: false }} | ${false}
${'with license and related metrics in db'} | ${[graphData.metrics[0].metricId]} | ${{}} | ${true}
${'without license and related metrics in db'} | ${[graphData.metrics[0].metricId]} | ${{ prometheusAlertsAvailable: false }} | ${false}
${'with license and unrelated metrics in db'} | ${['another_metric_id']} | ${{}} | ${false}
`('$desc', ({ metricsSavedToDb, isShown, propsData }) => {
const showsDesc = isShown ? 'shows' : 'does not show';
......
......@@ -10,17 +10,17 @@ import TimeSeriesChart from '~/monitoring/components/charts/time_series.vue';
import AnomalyChart from '~/monitoring/components/charts/anomaly.vue';
import {
anomalyMockGraphData,
graphDataPrometheusQueryRange,
mockLogsHref,
mockLogsPath,
mockNamespace,
mockNamespacedData,
mockTimeRange,
} from 'jest/monitoring/mock_data';
} from '../mock_data';
import { graphData, graphDataEmpty } from '../fixture_data';
import { createStore, monitoringDashboard } from '~/monitoring/stores';
import { createStore as createEmbedGroupStore } from '~/monitoring/stores/embed_group';
global.IS_EE = true;
global.URL.createObjectURL = jest.fn();
const mocks = {
......@@ -39,10 +39,13 @@ describe('Panel Type component', () => {
const findCopyLink = () => wrapper.find({ ref: 'copyChartLink' });
const findTimeChart = () => wrapper.find({ ref: 'timeChart' });
const findTitle = () => wrapper.find({ ref: 'graphTitle' });
const findContextualMenu = () => wrapper.find({ ref: 'contextualMenu' });
const createWrapper = props => {
wrapper = shallowMount(PanelType, {
propsData: {
graphData,
...props,
},
store,
......@@ -64,14 +67,9 @@ describe('Panel Type component', () => {
});
describe('When no graphData is available', () => {
let glEmptyChart;
// Deep clone object before modifying
const graphDataNoResult = JSON.parse(JSON.stringify(graphDataPrometheusQueryRange));
graphDataNoResult.metrics[0].result = [];
beforeEach(() => {
createWrapper({
graphData: graphDataNoResult,
graphData: graphDataEmpty,
});
});
......@@ -80,12 +78,8 @@ describe('Panel Type component', () => {
});
describe('Empty Chart component', () => {
beforeEach(() => {
glEmptyChart = wrapper.find(EmptyChart);
});
it('renders the chart title', () => {
expect(wrapper.find({ ref: 'graphTitle' }).text()).toBe(graphDataNoResult.title);
expect(findTitle().text()).toBe(graphDataEmpty.title);
});
it('renders the no download csv link', () => {
......@@ -93,26 +87,19 @@ describe('Panel Type component', () => {
});
it('does not contain graph widgets', () => {
expect(wrapper.find('.js-graph-widgets').exists()).toBe(false);
expect(findContextualMenu().exists()).toBe(false);
});
it('is a Vue instance', () => {
expect(glEmptyChart.isVueInstance()).toBe(true);
});
it('it receives a graph title', () => {
const props = glEmptyChart.props();
expect(props.graphTitle).toBe(wrapper.vm.graphData.title);
expect(wrapper.find(EmptyChart).exists()).toBe(true);
expect(wrapper.find(EmptyChart).isVueInstance()).toBe(true);
});
});
});
describe('when graph data is available', () => {
beforeEach(() => {
createWrapper({
graphData: graphDataPrometheusQueryRange,
});
createWrapper();
});
afterEach(() => {
......@@ -120,11 +107,11 @@ describe('Panel Type component', () => {
});
it('renders the chart title', () => {
expect(wrapper.find({ ref: 'graphTitle' }).text()).toBe(graphDataPrometheusQueryRange.title);
expect(findTitle().text()).toBe(graphData.title);
});
it('contains graph widgets', () => {
expect(wrapper.find('.js-graph-widgets').exists()).toBe(true);
expect(findContextualMenu().exists()).toBe(true);
expect(wrapper.find({ ref: 'downloadCsvLink' }).exists()).toBe(true);
});
......@@ -177,11 +164,7 @@ describe('Panel Type component', () => {
const findEditCustomMetricLink = () => wrapper.find({ ref: 'editMetricLink' });
beforeEach(() => {
createWrapper({
graphData: {
...graphDataPrometheusQueryRange,
},
});
createWrapper();
return wrapper.vm.$nextTick();
});
......@@ -193,10 +176,10 @@ describe('Panel Type component', () => {
it('is present when the panel contains an edit_path property', () => {
wrapper.setProps({
graphData: {
...graphDataPrometheusQueryRange,
...graphData,
metrics: [
{
...graphDataPrometheusQueryRange.metrics[0],
...graphData.metrics[0],
edit_path: '/root/kubernetes-gke-project/prometheus/metrics/23/edit',
},
],
......@@ -205,23 +188,6 @@ describe('Panel Type component', () => {
return wrapper.vm.$nextTick(() => {
expect(findEditCustomMetricLink().exists()).toBe(true);
});
});
it('shows an "Edit metric" link for a panel with a single metric', () => {
wrapper.setProps({
graphData: {
...graphDataPrometheusQueryRange,
metrics: [
{
...graphDataPrometheusQueryRange.metrics[0],
edit_path: '/root/kubernetes-gke-project/prometheus/metrics/23/edit',
},
],
},
});
return wrapper.vm.$nextTick(() => {
expect(findEditCustomMetricLink().text()).toBe('Edit metric');
});
});
......@@ -229,14 +195,14 @@ describe('Panel Type component', () => {
it('shows an "Edit metrics" link for a panel with multiple metrics', () => {
wrapper.setProps({
graphData: {
...graphDataPrometheusQueryRange,
...graphData,
metrics: [
{
...graphDataPrometheusQueryRange.metrics[0],
...graphData.metrics[0],
edit_path: '/root/kubernetes-gke-project/prometheus/metrics/23/edit',
},
{
...graphDataPrometheusQueryRange.metrics[0],
...graphData.metrics[0],
edit_path: '/root/kubernetes-gke-project/prometheus/metrics/23/edit',
},
],
......@@ -253,9 +219,7 @@ describe('Panel Type component', () => {
const findViewLogsLink = () => wrapper.find({ ref: 'viewLogsLink' });
beforeEach(() => {
createWrapper({
graphData: graphDataPrometheusQueryRange,
});
createWrapper();
return wrapper.vm.$nextTick();
});
......@@ -327,7 +291,6 @@ describe('Panel Type component', () => {
beforeEach(() => {
createWrapper({
clipboardText,
graphData: graphDataPrometheusQueryRange,
});
});
......@@ -353,11 +316,13 @@ describe('Panel Type component', () => {
describe('when downloading metrics data as CSV', () => {
beforeEach(() => {
graphDataPrometheusQueryRange.y_label = 'metric';
wrapper = shallowMount(PanelType, {
propsData: {
clipboardText: exampleText,
graphData: graphDataPrometheusQueryRange,
graphData: {
y_label: 'metric',
...graphData,
},
},
store,
});
......@@ -370,12 +335,12 @@ describe('Panel Type component', () => {
describe('csvText', () => {
it('converts metrics data from json to csv', () => {
const header = `timestamp,${graphDataPrometheusQueryRange.y_label}`;
const data = graphDataPrometheusQueryRange.metrics[0].result[0].values;
const header = `timestamp,${graphData.y_label}`;
const data = graphData.metrics[0].result[0].values;
const firstRow = `${data[0][0]},${data[0][1]}`;
const secondRow = `${data[1][0]},${data[1][1]}`;
expect(wrapper.vm.csvText).toBe(`${header}\r\n${firstRow}\r\n${secondRow}\r\n`);
expect(wrapper.vm.csvText).toMatch(`${header}\r\n${firstRow}\r\n${secondRow}\r\n`);
});
});
......@@ -402,7 +367,7 @@ describe('Panel Type component', () => {
wrapper = shallowMount(PanelType, {
propsData: {
graphData: graphDataPrometheusQueryRange,
graphData,
namespace: mockNamespace,
},
store,
......
import { mapToDashboardViewModel } from '~/monitoring/stores/utils';
import { metricStates } from '~/monitoring/constants';
import { metricsResult } from './mock_data';
// Use globally available `getJSONFixture` so this file can be imported by both karma and jest specs
......@@ -23,3 +25,25 @@ export const metricResultEmpty = {
metricId: 'NO_DB_response_metrics_nginx_ingress_16_throughput_status_code',
result: [],
};
// Graph data
const firstPanel = metricsDashboardViewModel.panelGroups[0].panels[0];
export const graphData = {
...firstPanel,
metrics: firstPanel.metrics.map(metric => ({
...metric,
result: metricsResult,
state: metricStates.OK,
})),
};
export const graphDataEmpty = {
...firstPanel,
metrics: firstPanel.metrics.map(metric => ({
...metric,
result: [],
state: metricStates.NO_DATA,
})),
};
......@@ -268,38 +268,6 @@ export const annotationsData = [
},
];
export const metricsNewGroupsAPIResponse = [
{
group: 'System metrics (Kubernetes)',
priority: 5,
panels: [
{
title: 'Memory Usage (Pod average)',
type: 'area-chart',
y_label: 'Memory Used per Pod',
weight: 2,
metrics: [
{
id: 'system_metrics_kubernetes_container_memory_average',
query_range:
'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) / count(avg(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-([^c].*|c([^a]|a([^n]|n([^a]|a([^r]|r[^y])))).*|)-(.*)",namespace="%{kube_namespace}"}) without (job)) /1024/1024',
label: 'Pod average',
unit: 'MB',
metric_id: 17,
prometheus_endpoint_path:
'/root/autodevops-deploy/environments/32/prometheus/api/v1/query_range?query=avg%28sum%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+by+%28job%29%29+without+%28job%29+%2F+count%28avg%28container_memory_usage_bytes%7Bcontainer_name%21%3D%22POD%22%2Cpod_name%3D~%22%5E%25%7Bci_environment_slug%7D-%28%5B%5Ec%5D.%2A%7Cc%28%5B%5Ea%5D%7Ca%28%5B%5En%5D%7Cn%28%5B%5Ea%5D%7Ca%28%5B%5Er%5D%7Cr%5B%5Ey%5D%29%29%29%29.%2A%7C%29-%28.%2A%29%22%2Cnamespace%3D%22%25%7Bkube_namespace%7D%22%7D%29+without+%28job%29%29+%2F1024%2F1024',
appearance: {
line: {
width: 2,
},
},
},
],
},
],
},
];
const extraEnvironmentData = new Array(15).fill(null).map((_, idx) => ({
id: `gid://gitlab/Environments/${150 + idx}`,
name: `no-deployment/noop-branch-${idx}`,
......@@ -369,34 +337,6 @@ export const metricsResult = [
[1563272125.589, '10.333984375'],
[1563272185.589, '10.333984375'],
[1563272245.589, '10.333984375'],
[1563272305.589, '10.333984375'],
[1563272365.589, '10.333984375'],
[1563272425.589, '10.38671875'],
[1563272485.589, '10.333984375'],
[1563272545.589, '10.333984375'],
[1563272605.589, '10.333984375'],
[1563272665.589, '10.333984375'],
[1563272725.589, '10.333984375'],
[1563272785.589, '10.396484375'],
[1563272845.589, '10.333984375'],
[1563272905.589, '10.333984375'],
[1563272965.589, '10.3984375'],
[1563273025.589, '10.337890625'],
[1563273085.589, '10.34765625'],
[1563273145.589, '10.337890625'],
[1563273205.589, '10.337890625'],
[1563273265.589, '10.337890625'],
[1563273325.589, '10.337890625'],
[1563273385.589, '10.337890625'],
[1563273445.589, '10.337890625'],
[1563273505.589, '10.337890625'],
[1563273565.589, '10.337890625'],
[1563273625.589, '10.337890625'],
[1563273685.589, '10.337890625'],
[1563273745.589, '10.337890625'],
[1563273805.589, '10.337890625'],
[1563273865.589, '10.390625'],
[1563273925.589, '10.390625'],
],
},
];
......@@ -425,29 +365,6 @@ export const graphDataPrometheusQuery = {
],
};
export const graphDataPrometheusQueryRange = {
title: 'Super Chart A1',
type: 'area-chart',
weight: 2,
metrics: [
{
metricId: '2_metric_a',
query_range:
'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024',
unit: 'MB',
label: 'Total Consumption',
prometheus_endpoint_path:
'/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
result: [
{
metric: {},
values: [[1495700554.925, '8.0390625'], [1495700614.925, '8.0390625']],
},
],
},
],
};
export const graphDataPrometheusQueryRangeMultiTrack = {
title: 'Super Chart A3',
type: 'heatmap',
......
......@@ -4,10 +4,10 @@ import { TEST_HOST } from 'jest/helpers/test_constants';
import {
mockProjectDir,
graphDataPrometheusQuery,
graphDataPrometheusQueryRange,
anomalyMockGraphData,
barMockData,
} from './mock_data';
import { graphData } from './fixture_data';
jest.mock('~/lib/utils/url_utility');
......@@ -101,10 +101,7 @@ describe('monitoring/utils', () => {
* the validator will look for the `values` key instead of `value`
*/
it('validates data with the query_range format', () => {
const validGraphData = monitoringUtils.graphDataValidatorForValues(
false,
graphDataPrometheusQueryRange,
);
const validGraphData = monitoringUtils.graphDataValidatorForValues(false, graphData);
expect(validGraphData).toBe(true);
});
......
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