Commit cebbda09 authored by Miguel Rincon's avatar Miguel Rincon

Refactor test code for panel type

Specs for panel type don't need certain mock data so it can be removed.

This clean up allows for better maintainance for the component.
parent 6381f19a
......@@ -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,
});
};
......@@ -52,11 +47,11 @@ describe('Panel Type', () => {
describe('panel type alerts', () => {
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 unrelated metrics in db'} | ${['another_metric_id']} | ${{}} | ${false}
desc | metricsSavedToDb | propsData | isShown
${'with license and no metrics in db'} | ${[]} | ${{}} | ${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