Commit dfe5e20c authored by Miguel Rincon's avatar Miguel Rincon

Define a single file as the chart formatter

Adds a dateformat file that defines defaults and contants to handle
multiple formats for charts timestamps.
parent 922be903
<script>
import { GlResizeObserverDirective } from '@gitlab/ui';
import { GlHeatmap } from '@gitlab/ui/dist/charts';
import dateformat from 'dateformat';
import { graphDataValidatorForValues } from '../../utils';
import { formatDate, timezones, formats } from '../../format_date';
export default {
components: {
......@@ -17,6 +17,11 @@ export default {
required: true,
validator: graphDataValidatorForValues.bind(null, false),
},
timezone: {
type: String,
required: false,
default: timezones.LOCAL,
},
},
data() {
return {
......@@ -43,7 +48,7 @@ export default {
return this.result.values.map(val => {
const [yLabel] = val;
return dateformat(new Date(yLabel), 'HH:MM:ss');
return formatDate(new Date(yLabel), { format: formats.shortTime, timezone: this.timezone });
});
},
result() {
......
......@@ -2,18 +2,19 @@
import { omit, throttle } from 'lodash';
import { GlLink, GlDeprecatedButton, GlTooltip, GlResizeObserverDirective } from '@gitlab/ui';
import { GlAreaChart, GlLineChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
import dateFormat from 'dateformat';
import { s__, __ } from '~/locale';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
import Icon from '~/vue_shared/components/icon.vue';
import { panelTypes, chartHeight, lineTypes, lineWidths, dateFormats } from '../../constants';
import { panelTypes, chartHeight, lineTypes, lineWidths } from '../../constants';
import { getYAxisOptions, getChartGrid, getTooltipFormatter } from './options';
import { annotationsYAxis, generateAnnotationsSeries } from './annotations';
import { makeDataSeries } from '~/helpers/monitor_helper';
import { graphDataValidatorForValues } from '../../utils';
import { formatDate, timezones, formats } from '../../format_date';
export const timestampToISODate = timestamp => new Date(timestamp).toISOString();
const THROTTLED_DATAZOOM_WAIT = 1000; // milliseconds
const timestampToISODate = timestamp => new Date(timestamp).toISOString();
const events = {
datazoom: 'datazoom',
......@@ -89,6 +90,11 @@ export default {
required: false,
default: '',
},
timezone: {
type: String,
required: false,
default: timezones.LOCAL,
},
},
data() {
return {
......@@ -163,7 +169,8 @@ export default {
name: __('Time'),
type: 'time',
axisLabel: {
formatter: date => dateFormat(date, dateFormats.timeOfDay),
formatter: date =>
formatDate(date, { format: formats.shortTime, timezone: this.timezone }),
},
axisPointer: {
snap: true,
......@@ -271,12 +278,13 @@ export default {
*/
formatAnnotationsTooltipText(params) {
return {
title: dateFormat(params.data?.tooltipData?.title, dateFormats.default),
title: formatDate(params.data?.tooltipData?.title, { timezone: this.timezone }),
content: params.data?.tooltipData?.content,
};
},
formatTooltipText(params) {
this.tooltip.title = dateFormat(params.value, dateFormats.default);
this.tooltip.title = formatDate(params.value, { timezone: this.timezone });
this.tooltip.content = [];
params.seriesData.forEach(dataPoint => {
......
......@@ -127,11 +127,6 @@ export const lineWidths = {
default: 2,
};
export const dateFormats = {
timeOfDay: 'h:MM TT',
default: 'dd mmm yyyy, h:MMTT',
};
/**
* These Vuex store properties are allowed to be
* replaced dynamically after component has been created
......
import dateFormat from 'dateformat';
export const timezones = {
/**
* Renders a date with a local timezone
*/
LOCAL: 'LOCAL',
/**
* Renders at date with UTC
*/
UTC: 'UTC',
};
export const formats = {
shortTime: 'h:MM TT',
default: 'dd mmm yyyy, h:MMTT (Z)',
};
/**
* Formats a date for a metric dashboard or chart.
*
* Convenience wrapper of dateFormat with default formats
* and settings.
*
* dateFormat has some limitations and we could use `toLocaleString` instead
* See: https://gitlab.com/gitlab-org/gitlab/-/issues/219246
*
* @param {Date|String|Number} date
* @param {Object} options - Formatting options
* @param {string} options.format - Format or mask from `formats`.
* @param {string} options.timezone - Timezone abbreviation.
* Accepts "LOCAL" for the client local timezone.
*/
export const formatDate = (date, options = {}) => {
const { format = formats.default, timezone = timezones.LOCAL } = options;
const useUTC = timezone === timezones.UTC;
return dateFormat(date, format, useUTC);
};
import { shallowMount } from '@vue/test-utils';
import { GlHeatmap } from '@gitlab/ui/dist/charts';
import timezoneMock from 'timezone-mock';
import Heatmap from '~/monitoring/components/charts/heatmap.vue';
import { graphDataPrometheusQueryRangeMultiTrack } from '../../mock_data';
describe('Heatmap component', () => {
let heatmapChart;
let wrapper;
let store;
beforeEach(() => {
heatmapChart = shallowMount(Heatmap, {
const findChart = () => wrapper.find(GlHeatmap);
const createWrapper = (props = {}) => {
wrapper = shallowMount(Heatmap, {
propsData: {
graphData: graphDataPrometheusQueryRangeMultiTrack,
containerWidth: 100,
...props,
},
store,
});
});
};
afterEach(() => {
heatmapChart.destroy();
});
describe('wrapped chart', () => {
let glHeatmapChart;
describe('wrapped components', () => {
describe('GitLab UI heatmap chart', () => {
let glHeatmapChart;
beforeEach(() => {
createWrapper();
glHeatmapChart = findChart();
});
beforeEach(() => {
glHeatmapChart = heatmapChart.find(GlHeatmap);
});
afterEach(() => {
wrapper.destroy();
});
it('is a Vue instance', () => {
expect(glHeatmapChart.isVueInstance()).toBe(true);
});
it('is a Vue instance', () => {
expect(glHeatmapChart.isVueInstance()).toBe(true);
});
it('should display a label on the x axis', () => {
expect(heatmapChart.vm.xAxisName).toBe(graphDataPrometheusQueryRangeMultiTrack.x_label);
});
it('should display a label on the x axis', () => {
expect(wrapper.vm.xAxisName).toBe(graphDataPrometheusQueryRangeMultiTrack.x_label);
});
it('should display a label on the y axis', () => {
expect(heatmapChart.vm.yAxisName).toBe(graphDataPrometheusQueryRangeMultiTrack.y_label);
});
it('should display a label on the y axis', () => {
expect(wrapper.vm.yAxisName).toBe(graphDataPrometheusQueryRangeMultiTrack.y_label);
});
// According to the echarts docs https://echarts.apache.org/en/option.html#series-heatmap.data
// each row of the heatmap chart is represented by an array inside another parent array
// e.g. [[0, 0, 10]], the format represents the column, the row and finally the value
// corresponding to the cell
// According to the echarts docs https://echarts.apache.org/en/option.html#series-heatmap.data
// each row of the heatmap chart is represented by an array inside another parent array
// e.g. [[0, 0, 10]], the format represents the column, the row and finally the value
// corresponding to the cell
it('should return chartData with a length of x by y, with a length of 3 per array', () => {
const row = heatmapChart.vm.chartData[0];
it('should return chartData with a length of x by y, with a length of 3 per array', () => {
const row = wrapper.vm.chartData[0];
expect(row.length).toBe(3);
expect(heatmapChart.vm.chartData.length).toBe(30);
});
expect(row.length).toBe(3);
expect(wrapper.vm.chartData.length).toBe(30);
});
it('returns a series of labels for the x axis', () => {
const { xAxisLabels } = wrapper.vm;
expect(xAxisLabels.length).toBe(5);
});
it('returns a series of labels for the x axis', () => {
const { xAxisLabels } = heatmapChart.vm;
describe('y axis labels', () => {
const gmtLabels = ['3:00 PM', '4:00 PM', '5:00 PM', '6:00 PM', '7:00 PM', '8:00 PM'];
expect(xAxisLabels.length).toBe(5);
it('y-axis labels are formatted in AM/PM format', () => {
expect(findChart().props('yAxisLabels')).toEqual(gmtLabels);
});
it('returns a series of labels for the y axis', () => {
const { yAxisLabels } = heatmapChart.vm;
describe('when in PT timezone', () => {
const ptLabels = ['8:00 AM', '9:00 AM', '10:00 AM', '11:00 AM', '12:00 PM', '1:00 PM'];
const utcLabels = gmtLabels; // Identical in this case
beforeAll(() => {
timezoneMock.register('US/Pacific');
});
afterAll(() => {
timezoneMock.unregister();
});
it('by default, y-axis is formatted in PT', () => {
createWrapper();
expect(findChart().props('yAxisLabels')).toEqual(ptLabels);
});
it('when the chart uses local timezone, y-axis is formatted in PT', () => {
createWrapper({ timezone: 'LOCAL' });
expect(findChart().props('yAxisLabels')).toEqual(ptLabels);
});
expect(yAxisLabels.length).toBe(6);
it('when the chart uses UTC, y-axis is formatted in UTC', () => {
createWrapper({ timezone: 'UTC' });
expect(findChart().props('yAxisLabels')).toEqual(utcLabels);
});
});
});
});
......
import { mount, shallowMount } from '@vue/test-utils';
import { setTestTimeout } from 'helpers/timeout';
import timezoneMock from 'timezone-mock';
import { GlLink } from '@gitlab/ui';
import { TEST_HOST } from 'jest/helpers/test_constants';
import {
......@@ -39,20 +40,26 @@ jest.mock('~/lib/utils/icon_utils', () => ({
describe('Time series component', () => {
let mockGraphData;
let store;
let wrapper;
const createWrapper = (graphData = mockGraphData, mountingMethod = shallowMount) =>
mountingMethod(TimeSeries, {
const createWrapper = (
{ graphData = mockGraphData, ...props } = {},
mountingMethod = shallowMount,
) => {
wrapper = mountingMethod(TimeSeries, {
propsData: {
graphData,
deploymentData: store.state.monitoringDashboard.deploymentData,
annotations: store.state.monitoringDashboard.annotations,
projectPath: `${TEST_HOST}${mockProjectDir}`,
...props,
},
store,
stubs: {
GlPopover: true,
},
});
};
describe('With a single time series', () => {
beforeEach(() => {
......@@ -76,39 +83,37 @@ describe('Time series component', () => {
});
describe('general functions', () => {
let timeSeriesChart;
const findChart = () => timeSeriesChart.find({ ref: 'chart' });
const findChart = () => wrapper.find({ ref: 'chart' });
beforeEach(() => {
timeSeriesChart = createWrapper(mockGraphData, mount);
return timeSeriesChart.vm.$nextTick();
createWrapper({}, mount);
return wrapper.vm.$nextTick();
});
it('allows user to override max value label text using prop', () => {
timeSeriesChart.setProps({ legendMaxText: 'legendMaxText' });
wrapper.setProps({ legendMaxText: 'legendMaxText' });
return timeSeriesChart.vm.$nextTick().then(() => {
expect(timeSeriesChart.props().legendMaxText).toBe('legendMaxText');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.props().legendMaxText).toBe('legendMaxText');
});
});
it('allows user to override average value label text using prop', () => {
timeSeriesChart.setProps({ legendAverageText: 'averageText' });
wrapper.setProps({ legendAverageText: 'averageText' });
return timeSeriesChart.vm.$nextTick().then(() => {
expect(timeSeriesChart.props().legendAverageText).toBe('averageText');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.props().legendAverageText).toBe('averageText');
});
});
it('chart sets a default height', () => {
const wrapper = createWrapper();
createWrapper();
expect(wrapper.props('height')).toBe(chartHeight);
});
it('chart has a configurable height', () => {
const mockHeight = 599;
const wrapper = createWrapper();
createWrapper();
wrapper.setProps({ height: mockHeight });
return wrapper.vm.$nextTick().then(() => {
......@@ -141,8 +146,8 @@ describe('Time series component', () => {
}),
};
timeSeriesChart = createWrapper(mockGraphData, mount);
timeSeriesChart.vm.$nextTick(() => {
createWrapper({}, mount);
wrapper.vm.$nextTick(() => {
findChart().vm.$emit('created', eChartMock);
done();
});
......@@ -153,8 +158,8 @@ describe('Time series component', () => {
endValue = 1577840400000; // 2020-01-01T01:00:00.000Z
eChartMock.handlers.datazoom();
expect(timeSeriesChart.emitted('datazoom')).toHaveLength(1);
expect(timeSeriesChart.emitted('datazoom')[0]).toEqual([
expect(wrapper.emitted('datazoom')).toHaveLength(1);
expect(wrapper.emitted('datazoom')[0]).toEqual([
{
start: new Date(startValue).toISOString(),
end: new Date(endValue).toISOString(),
......@@ -172,7 +177,7 @@ describe('Time series component', () => {
const mockLineSeriesData = () => ({
seriesData: [
{
seriesName: timeSeriesChart.vm.chartData[0].name,
seriesName: wrapper.vm.chartData[0].name,
componentSubType: 'line',
value: [mockDate, 5.55555],
dataIndex: 0,
......@@ -210,86 +215,118 @@ describe('Time series component', () => {
value: undefined,
})),
};
expect(timeSeriesChart.vm.formatTooltipText(seriesDataWithoutValue)).toBeUndefined();
expect(wrapper.vm.formatTooltipText(seriesDataWithoutValue)).toBeUndefined();
});
describe('when series is of line type', () => {
beforeEach(done => {
timeSeriesChart.vm.formatTooltipText(mockLineSeriesData());
timeSeriesChart.vm.$nextTick(done);
beforeEach(() => {
createWrapper();
wrapper.vm.formatTooltipText(mockLineSeriesData());
return wrapper.vm.$nextTick();
});
it('formats tooltip title', () => {
expect(timeSeriesChart.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM');
expect(wrapper.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM (GMT+0000)');
});
it('formats tooltip content', () => {
const name = 'Status Code';
const value = '5.556';
const dataIndex = 0;
const seriesLabel = timeSeriesChart.find(GlChartSeriesLabel);
const seriesLabel = wrapper.find(GlChartSeriesLabel);
expect(seriesLabel.vm.color).toBe('');
expect(shallowWrapperContainsSlotText(seriesLabel, 'default', name)).toBe(true);
expect(timeSeriesChart.vm.tooltip.content).toEqual([
expect(wrapper.vm.tooltip.content).toEqual([
{ name, value, dataIndex, color: undefined },
]);
expect(
shallowWrapperContainsSlotText(
timeSeriesChart.find(GlAreaChart),
'tooltipContent',
value,
),
shallowWrapperContainsSlotText(wrapper.find(GlAreaChart), 'tooltipContent', value),
).toBe(true);
});
describe('when in PT timezone', () => {
beforeAll(() => {
// Note: node.js env renders (GMT-0700), in the browser we see (PDT)
timezoneMock.register('US/Pacific');
});
afterAll(() => {
timezoneMock.unregister();
});
it('formats tooltip title in local timezone by default', () => {
createWrapper();
wrapper.vm.formatTooltipText(mockLineSeriesData());
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.tooltip.title).toBe('16 Jul 2019, 3:14AM (GMT-0700)');
});
});
it('formats tooltip title in local timezone', () => {
createWrapper({ timezone: 'LOCAL' });
wrapper.vm.formatTooltipText(mockLineSeriesData());
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.tooltip.title).toBe('16 Jul 2019, 3:14AM (GMT-0700)');
});
});
it('formats tooltip title in UTC format', () => {
createWrapper({ timezone: 'UTC' });
wrapper.vm.formatTooltipText(mockLineSeriesData());
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM (UTC)');
});
});
});
});
describe('when series is of scatter type, for deployments', () => {
beforeEach(() => {
timeSeriesChart.vm.formatTooltipText({
wrapper.vm.formatTooltipText({
...mockAnnotationsSeriesData,
seriesData: mockAnnotationsSeriesData.seriesData.map(data => ({
...data,
data: annotationsMetadata,
})),
});
return timeSeriesChart.vm.$nextTick;
return wrapper.vm.$nextTick;
});
it('set tooltip type to deployments', () => {
expect(timeSeriesChart.vm.tooltip.type).toBe('deployments');
expect(wrapper.vm.tooltip.type).toBe('deployments');
});
it('formats tooltip title', () => {
expect(timeSeriesChart.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM');
expect(wrapper.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM (GMT+0000)');
});
it('formats tooltip sha', () => {
expect(timeSeriesChart.vm.tooltip.sha).toBe('f5bcd1d9');
expect(wrapper.vm.tooltip.sha).toBe('f5bcd1d9');
});
it('formats tooltip commit url', () => {
expect(timeSeriesChart.vm.tooltip.commitUrl).toBe(mockCommitUrl);
expect(wrapper.vm.tooltip.commitUrl).toBe(mockCommitUrl);
});
});
describe('when series is of scatter type and deployments data is missing', () => {
beforeEach(() => {
timeSeriesChart.vm.formatTooltipText(mockAnnotationsSeriesData);
return timeSeriesChart.vm.$nextTick;
wrapper.vm.formatTooltipText(mockAnnotationsSeriesData);
return wrapper.vm.$nextTick;
});
it('formats tooltip title', () => {
expect(timeSeriesChart.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM');
expect(wrapper.vm.tooltip.title).toBe('16 Jul 2019, 10:14AM (GMT+0000)');
});
it('formats tooltip sha', () => {
expect(timeSeriesChart.vm.tooltip.sha).toBeUndefined();
expect(wrapper.vm.tooltip.sha).toBeUndefined();
});
it('formats tooltip commit url', () => {
expect(timeSeriesChart.vm.tooltip.commitUrl).toBeUndefined();
expect(wrapper.vm.tooltip.commitUrl).toBeUndefined();
});
});
});
......@@ -313,10 +350,8 @@ describe('Time series component', () => {
};
it('formats tooltip title and sets tooltip content', () => {
const formattedTooltipData = timeSeriesChart.vm.formatAnnotationsTooltipText(
mockMarkPoint,
);
expect(formattedTooltipData.title).toBe('19 Feb 2020, 10:01AM');
const formattedTooltipData = wrapper.vm.formatAnnotationsTooltipText(mockMarkPoint);
expect(formattedTooltipData.title).toBe('19 Feb 2020, 10:01AM (GMT+0000)');
expect(formattedTooltipData.content).toBe(annotationsMetadata.tooltipData.content);
});
});
......@@ -325,8 +360,8 @@ describe('Time series component', () => {
const mockSvgName = 'mockSvgName';
beforeEach(done => {
timeSeriesChart.vm.setSvg(mockSvgName);
timeSeriesChart.vm.$nextTick(done);
wrapper.vm.setSvg(mockSvgName);
wrapper.vm.$nextTick(done);
});
it('gets svg path content', () => {
......@@ -334,14 +369,14 @@ describe('Time series component', () => {
});
it('sets svg path content', () => {
timeSeriesChart.vm.$nextTick(() => {
expect(timeSeriesChart.vm.svgs[mockSvgName]).toBe(`path://${mockSvgPathContent}`);
wrapper.vm.$nextTick(() => {
expect(wrapper.vm.svgs[mockSvgName]).toBe(`path://${mockSvgPathContent}`);
});
});
it('contains an svg object within an array to properly render icon', () => {
timeSeriesChart.vm.$nextTick(() => {
expect(timeSeriesChart.vm.chartOptions.dataZoom).toEqual([
wrapper.vm.$nextTick(() => {
expect(wrapper.vm.chartOptions.dataZoom).toEqual([
{
handleIcon: `path://${mockSvgPathContent}`,
},
......@@ -357,11 +392,11 @@ describe('Time series component', () => {
jest.spyOn(Element.prototype, 'getBoundingClientRect').mockImplementation(() => ({
width: mockWidth,
}));
timeSeriesChart.vm.onResize();
wrapper.vm.onResize();
});
it('sets area chart width', () => {
expect(timeSeriesChart.vm.width).toBe(mockWidth);
expect(wrapper.vm.width).toBe(mockWidth);
});
});
});
......@@ -374,7 +409,7 @@ describe('Time series component', () => {
const seriesData = () => chartData[0];
beforeEach(() => {
({ chartData } = timeSeriesChart.vm);
({ chartData } = wrapper.vm);
});
it('utilizes all data points', () => {
......@@ -408,17 +443,17 @@ describe('Time series component', () => {
};
it('arbitrary options', () => {
timeSeriesChart.setProps({
wrapper.setProps({
option: mockOption,
});
return timeSeriesChart.vm.$nextTick().then(() => {
return wrapper.vm.$nextTick().then(() => {
expect(getChartOptions()).toEqual(expect.objectContaining(mockOption));
});
});
it('additional series', () => {
timeSeriesChart.setProps({
wrapper.setProps({
option: {
series: [
{
......@@ -430,7 +465,7 @@ describe('Time series component', () => {
},
});
return timeSeriesChart.vm.$nextTick().then(() => {
return wrapper.vm.$nextTick().then(() => {
const optionSeries = getChartOptions().series;
expect(optionSeries.length).toEqual(2);
......@@ -446,13 +481,13 @@ describe('Time series component', () => {
},
};
timeSeriesChart.setProps({
wrapper.setProps({
option: {
yAxis: mockCustomYAxisOption,
},
});
return timeSeriesChart.vm.$nextTick().then(() => {
return wrapper.vm.$nextTick().then(() => {
const { yAxis } = getChartOptions();
expect(yAxis[0]).toMatchObject(mockCustomYAxisOption);
......@@ -464,13 +499,13 @@ describe('Time series component', () => {
name: 'Custom x axis label',
};
timeSeriesChart.setProps({
wrapper.setProps({
option: {
xAxis: mockCustomXAxisOption,
},
});
return timeSeriesChart.vm.$nextTick().then(() => {
return wrapper.vm.$nextTick().then(() => {
const { xAxis } = getChartOptions();
expect(xAxis).toMatchObject(mockCustomXAxisOption);
......@@ -499,7 +534,7 @@ describe('Time series component', () => {
describe('annotationSeries', () => {
it('utilizes deployment data', () => {
const annotationSeries = timeSeriesChart.vm.chartOptionSeries[0];
const annotationSeries = wrapper.vm.chartOptionSeries[0];
expect(annotationSeries.yAxisIndex).toBe(1); // same as annotations y axis
expect(annotationSeries.data).toEqual([
expect.objectContaining({
......@@ -518,6 +553,45 @@ describe('Time series component', () => {
});
});
describe('xAxisLabel', () => {
const mockDate = Date.UTC(2020, 4, 26, 20); // 8:00 PM in GMT
const useXAxisFormatter = date => {
const { xAxis } = getChartOptions();
const { formatter } = xAxis.axisLabel;
return formatter(date);
};
it('x-axis is formatted correctly in AM/PM format', () => {
expect(useXAxisFormatter(mockDate)).toEqual('8:00 PM');
});
describe('when in PT timezone', () => {
beforeAll(() => {
timezoneMock.register('US/Pacific');
});
afterAll(() => {
timezoneMock.unregister();
});
it('by default, values are formatted in PT', () => {
createWrapper();
expect(useXAxisFormatter(mockDate)).toEqual('1:00 PM');
});
it('when the chart uses local timezone, y-axis is formatted in PT', () => {
createWrapper({ timezone: 'LOCAL' });
expect(useXAxisFormatter(mockDate)).toEqual('1:00 PM');
});
it('when the chart uses UTC, y-axis is formatted in UTC', () => {
createWrapper({ timezone: 'UTC' });
expect(useXAxisFormatter(mockDate)).toEqual('8:00 PM');
});
});
});
describe('yAxisLabel', () => {
it('y-axis is configured correctly', () => {
const { yAxis } = getChartOptions();
......@@ -544,7 +618,7 @@ describe('Time series component', () => {
});
afterEach(() => {
timeSeriesChart.destroy();
wrapper.destroy();
});
});
......@@ -562,19 +636,14 @@ describe('Time series component', () => {
glChartComponents.forEach(dynamicComponent => {
describe(`GitLab UI: ${dynamicComponent.chartType}`, () => {
let timeSeriesAreaChart;
const findChartComponent = () => timeSeriesAreaChart.find(dynamicComponent.component);
const findChartComponent = () => wrapper.find(dynamicComponent.component);
beforeEach(done => {
timeSeriesAreaChart = createWrapper(
{ ...mockGraphData, type: dynamicComponent.chartType },
createWrapper(
{ graphData: { ...mockGraphData, type: dynamicComponent.chartType } },
mount,
);
timeSeriesAreaChart.vm.$nextTick(done);
});
afterEach(() => {
timeSeriesAreaChart.destroy();
wrapper.vm.$nextTick(done);
});
it('is a Vue instance', () => {
......@@ -585,17 +654,17 @@ describe('Time series component', () => {
it('receives data properties needed for proper chart render', () => {
const props = findChartComponent().props();
expect(props.data).toBe(timeSeriesAreaChart.vm.chartData);
expect(props.option).toBe(timeSeriesAreaChart.vm.chartOptions);
expect(props.formatTooltipText).toBe(timeSeriesAreaChart.vm.formatTooltipText);
expect(props.thresholds).toBe(timeSeriesAreaChart.vm.thresholds);
expect(props.data).toBe(wrapper.vm.chartData);
expect(props.option).toBe(wrapper.vm.chartOptions);
expect(props.formatTooltipText).toBe(wrapper.vm.formatTooltipText);
expect(props.thresholds).toBe(wrapper.vm.thresholds);
});
it('recieves a tooltip title', done => {
const mockTitle = 'mockTitle';
timeSeriesAreaChart.vm.tooltip.title = mockTitle;
wrapper.vm.tooltip.title = mockTitle;
timeSeriesAreaChart.vm.$nextTick(() => {
wrapper.vm.$nextTick(() => {
expect(
shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', mockTitle),
).toBe(true);
......@@ -608,12 +677,12 @@ describe('Time series component', () => {
const commitUrl = `${mockProjectDir}/-/commit/${mockSha}`;
beforeEach(done => {
timeSeriesAreaChart.setData({
wrapper.setData({
tooltip: {
type: 'deployments',
},
});
timeSeriesAreaChart.vm.$nextTick(done);
wrapper.vm.$nextTick(done);
});
it('uses deployment title', () => {
......@@ -623,11 +692,11 @@ describe('Time series component', () => {
});
it('renders clickable commit sha in tooltip content', done => {
timeSeriesAreaChart.vm.tooltip.sha = mockSha;
timeSeriesAreaChart.vm.tooltip.commitUrl = commitUrl;
wrapper.vm.tooltip.sha = mockSha;
wrapper.vm.tooltip.commitUrl = commitUrl;
timeSeriesAreaChart.vm.$nextTick(() => {
const commitLink = timeSeriesAreaChart.find(GlLink);
wrapper.vm.$nextTick(() => {
const commitLink = wrapper.find(GlLink);
expect(shallowWrapperContainsSlotText(commitLink, 'default', mockSha)).toBe(true);
expect(commitLink.attributes('href')).toEqual(commitUrl);
......@@ -642,8 +711,6 @@ describe('Time series component', () => {
describe('with multiple time series', () => {
describe('General functions', () => {
let timeSeriesChart;
beforeEach(done => {
store = createStore();
const graphData = cloneDeep(metricsDashboardViewModel.panelGroups[0].panels[3]);
......@@ -651,21 +718,19 @@ describe('Time series component', () => {
Object.assign(metric, { result: metricResultStatus.result }),
);
timeSeriesChart = createWrapper({ ...graphData, type: 'area-chart' }, mount);
timeSeriesChart.vm.$nextTick(done);
createWrapper({ graphData: { ...graphData, type: 'area-chart' } }, mount);
wrapper.vm.$nextTick(done);
});
afterEach(() => {
timeSeriesChart.destroy();
wrapper.destroy();
});
describe('Color match', () => {
let lineColors;
beforeEach(() => {
lineColors = timeSeriesChart
.find(GlAreaChart)
.vm.series.map(item => item.lineStyle.color);
lineColors = wrapper.find(GlAreaChart).vm.series.map(item => item.lineStyle.color);
});
it('should contain different colors for contiguous time series', () => {
......@@ -675,7 +740,7 @@ describe('Time series component', () => {
});
it('should match series color with tooltip label color', () => {
const labels = timeSeriesChart.findAll(GlChartSeriesLabel);
const labels = wrapper.findAll(GlChartSeriesLabel);
lineColors.forEach((color, index) => {
const labelColor = labels.at(index).props('color');
......@@ -684,7 +749,7 @@ describe('Time series component', () => {
});
it('should match series color with legend color', () => {
const legendColors = timeSeriesChart
const legendColors = wrapper
.find(GlChartLegend)
.props('seriesInfo')
.map(item => item.color);
......
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