From b864442717d82af903c1027a06cdb2ebb145f7a5 Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Fri, 20 May 2022 10:51:11 +0100 Subject: [PATCH] Gauge: convert tests to RTL (#49251) * Move logic into utils file, add EXTREMELY basic RTL test * initialise array with value --- .betterer.results | 5 +- .../src/components/Gauge/Gauge.test.tsx | 90 ++++++------------- .../grafana-ui/src/components/Gauge/Gauge.tsx | 79 +--------------- .../src/components/Gauge/utils.test.ts | 55 ++++++++++++ .../grafana-ui/src/components/Gauge/utils.ts | 86 ++++++++++++++++++ 5 files changed, 172 insertions(+), 143 deletions(-) create mode 100644 packages/grafana-ui/src/components/Gauge/utils.test.ts create mode 100644 packages/grafana-ui/src/components/Gauge/utils.ts diff --git a/.betterer.results b/.betterer.results index e6260144960..e4df49386e2 100644 --- a/.betterer.results +++ b/.betterer.results @@ -1,5 +1,5 @@ // BETTERER RESULTS V2. -// +// // If this file contains merge conflicts, use `betterer merge` to automatically resolve them: // https://phenomnomnominal.github.io/betterer/docs/results-file/#merge // @@ -11,9 +11,6 @@ exports[`no enzyme tests`] = { "packages/grafana-ui/src/components/Forms/Legacy/Input/Input.test.tsx:3129955645": [ [0, 19, 13, "RegExp match", "2409514259"] ], - "packages/grafana-ui/src/components/Gauge/Gauge.test.tsx:2525939157": [ - [0, 19, 13, "RegExp match", "2409514259"] - ], "packages/grafana-ui/src/components/Graph/Graph.test.tsx:1664091255": [ [0, 17, 13, "RegExp match", "2409514259"] ], diff --git a/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx b/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx index 9a1e0ebdd80..19a0ede4b44 100644 --- a/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx +++ b/packages/grafana-ui/src/components/Gauge/Gauge.test.tsx @@ -1,4 +1,4 @@ -import { shallow } from 'enzyme'; +import { render } from '@testing-library/react'; import React from 'react'; import { ThresholdsMode, FieldConfig, FieldColorModeId } from '@grafana/data'; @@ -11,71 +11,33 @@ jest.mock('jquery', () => ({ plot: jest.fn(), })); -const setup = (propOverrides?: FieldConfig) => { - const field: FieldConfig = { - min: 0, - max: 100, - color: { - mode: FieldColorModeId.Thresholds, - }, - thresholds: { - mode: ThresholdsMode.Absolute, - steps: [{ value: -Infinity, color: '#7EB26D' }], - }, - }; - Object.assign(field, propOverrides); - - const props: Props = { - showThresholdMarkers: true, - showThresholdLabels: false, - field, - width: 300, - height: 300, - value: { - text: '25', - numeric: 25, - }, - theme: getTheme(), - }; - - const wrapper = shallow(); - const instance = wrapper.instance() as Gauge; - - return { - instance, - wrapper, - }; +const field: FieldConfig = { + min: 0, + max: 100, + color: { + mode: FieldColorModeId.Thresholds, + }, + thresholds: { + mode: ThresholdsMode.Absolute, + steps: [{ value: -Infinity, color: '#7EB26D' }], + }, }; -describe('Get thresholds formatted', () => { - it('should return first thresholds color for min and max', () => { - const { instance } = setup({ - thresholds: { mode: ThresholdsMode.Absolute, steps: [{ value: -Infinity, color: '#7EB26D' }] }, - }); +const props: Props = { + showThresholdMarkers: true, + showThresholdLabels: false, + field, + width: 300, + height: 300, + value: { + text: '25', + numeric: 25, + }, + theme: getTheme(), +}; - expect(instance.getFormattedThresholds(2)).toEqual([ - { value: 0, color: '#7EB26D' }, - { value: 100, color: '#7EB26D' }, - ]); - }); - - it('should get the correct formatted values when thresholds are added', () => { - const { instance } = setup({ - thresholds: { - mode: ThresholdsMode.Absolute, - steps: [ - { value: -Infinity, color: '#7EB26D' }, - { value: 50, color: '#EAB839' }, - { value: 75, color: '#6ED0E0' }, - ], - }, - }); - - expect(instance.getFormattedThresholds(2)).toEqual([ - { value: 0, color: '#7EB26D' }, - { value: 50, color: '#7EB26D' }, - { value: 75, color: '#EAB839' }, - { value: 100, color: '#6ED0E0' }, - ]); +describe('Gauge', () => { + it('should render without blowing up', () => { + expect(() => render()).not.toThrow(); }); }); diff --git a/packages/grafana-ui/src/components/Gauge/Gauge.tsx b/packages/grafana-ui/src/components/Gauge/Gauge.tsx index f35c53901f7..709cd81ea09 100644 --- a/packages/grafana-ui/src/components/Gauge/Gauge.tsx +++ b/packages/grafana-ui/src/components/Gauge/Gauge.tsx @@ -8,17 +8,14 @@ import { ThresholdsMode, GAUGE_DEFAULT_MAXIMUM, GAUGE_DEFAULT_MINIMUM, - getActiveThreshold, - Threshold, - getColorForTheme, - FieldColorModeId, - FALLBACK_COLOR, TextDisplayOptions, } from '@grafana/data'; import { Themeable } from '../../types'; import { calculateFontSize } from '../../utils/measureText'; +import { calculateGaugeAutoProps, DEFAULT_THRESHOLDS, getFormattedThresholds } from './utils'; + export interface Props extends Themeable { height: number; field: FieldConfig; @@ -40,13 +37,7 @@ export class Gauge extends PureComponent { field: { min: 0, max: 100, - thresholds: { - mode: ThresholdsMode.Absolute, - steps: [ - { value: -Infinity, color: 'green' }, - { value: 80, color: 'red' }, - ], - }, + thresholds: DEFAULT_THRESHOLDS, }, }; @@ -58,48 +49,6 @@ export class Gauge extends PureComponent { this.draw(); } - getFormattedThresholds(decimals: number): Threshold[] { - const { field, theme, value } = this.props; - - if (field.color?.mode !== FieldColorModeId.Thresholds) { - return [{ value: field.min ?? GAUGE_DEFAULT_MINIMUM, color: value.color ?? FALLBACK_COLOR }]; - } - - const thresholds = field.thresholds ?? Gauge.defaultProps.field?.thresholds!; - const isPercent = thresholds.mode === ThresholdsMode.Percentage; - const steps = thresholds.steps; - - let min = field.min ?? GAUGE_DEFAULT_MINIMUM; - let max = field.max ?? GAUGE_DEFAULT_MAXIMUM; - - if (isPercent) { - min = 0; - max = 100; - } - - const first = getActiveThreshold(min, steps); - const last = getActiveThreshold(max, steps); - const formatted: Threshold[] = []; - formatted.push({ value: +min.toFixed(decimals), color: getColorForTheme(first.color, theme) }); - let skip = true; - for (let i = 0; i < steps.length; i++) { - const step = steps[i]; - if (skip) { - if (first === step) { - skip = false; - } - continue; - } - const prev = steps[i - 1]; - formatted.push({ value: step.value, color: getColorForTheme(prev!.color, theme) }); - if (step === last) { - break; - } - } - formatted.push({ value: +max.toFixed(decimals), color: getColorForTheme(last.color, theme) }); - return formatted; - } - draw() { const { field, showThresholdLabels, showThresholdMarkers, width, height, theme, value } = this.props; @@ -157,7 +106,7 @@ export class Gauge extends PureComponent { layout: { margin: 0, thresholdWidth: 0, vMargin: 0 }, cell: { border: { width: 0 } }, threshold: { - values: this.getFormattedThresholds(decimals), + values: getFormattedThresholds(decimals, field, value, theme), label: { show: showThresholdLabels, margin: thresholdMarkersWidth + 1, @@ -240,23 +189,3 @@ export class Gauge extends PureComponent { ); } } - -interface GaugeAutoProps { - titleFontSize: number; - gaugeHeight: number; - showLabel: boolean; -} - -function calculateGaugeAutoProps(width: number, height: number, title: string | undefined): GaugeAutoProps { - const showLabel = title !== null && title !== undefined; - const titleFontSize = Math.min((width * 0.15) / 1.5, 20); // 20% of height * line-height, max 40px - const titleHeight = titleFontSize * 1.5; - const availableHeight = showLabel ? height - titleHeight : height; - const gaugeHeight = Math.min(availableHeight, width); - - return { - showLabel, - gaugeHeight, - titleFontSize, - }; -} diff --git a/packages/grafana-ui/src/components/Gauge/utils.test.ts b/packages/grafana-ui/src/components/Gauge/utils.test.ts new file mode 100644 index 00000000000..45720c01a3c --- /dev/null +++ b/packages/grafana-ui/src/components/Gauge/utils.test.ts @@ -0,0 +1,55 @@ +import { FieldColorModeId, FieldConfig, ThresholdsMode } from '@grafana/data'; + +import { getTheme } from '../../themes'; + +import { getFormattedThresholds } from './utils'; + +describe('getFormattedThresholds', () => { + const value = { + text: '25', + numeric: 25, + }; + const theme = getTheme(); + let field: FieldConfig; + + beforeEach(() => { + field = { + min: 0, + max: 100, + color: { + mode: FieldColorModeId.Thresholds, + }, + thresholds: { + mode: ThresholdsMode.Absolute, + steps: [{ value: -Infinity, color: '#7EB26D' }], + }, + }; + }); + + it('should return first thresholds color for min and max', () => { + field.thresholds = { mode: ThresholdsMode.Absolute, steps: [{ value: -Infinity, color: '#7EB26D' }] }; + + expect(getFormattedThresholds(2, field, value, theme)).toEqual([ + { value: 0, color: '#7EB26D' }, + { value: 100, color: '#7EB26D' }, + ]); + }); + + it('should get the correct formatted values when thresholds are added', () => { + field.thresholds = { + mode: ThresholdsMode.Absolute, + steps: [ + { value: -Infinity, color: '#7EB26D' }, + { value: 50, color: '#EAB839' }, + { value: 75, color: '#6ED0E0' }, + ], + }; + + expect(getFormattedThresholds(2, field, value, theme)).toEqual([ + { value: 0, color: '#7EB26D' }, + { value: 50, color: '#7EB26D' }, + { value: 75, color: '#EAB839' }, + { value: 100, color: '#6ED0E0' }, + ]); + }); +}); diff --git a/packages/grafana-ui/src/components/Gauge/utils.ts b/packages/grafana-ui/src/components/Gauge/utils.ts new file mode 100644 index 00000000000..84750c5274e --- /dev/null +++ b/packages/grafana-ui/src/components/Gauge/utils.ts @@ -0,0 +1,86 @@ +import { + DisplayValue, + FALLBACK_COLOR, + FieldColorModeId, + FieldConfig, + GAUGE_DEFAULT_MAXIMUM, + GAUGE_DEFAULT_MINIMUM, + getActiveThreshold, + getColorForTheme, + GrafanaTheme, + Threshold, + ThresholdsConfig, + ThresholdsMode, +} from '@grafana/data'; + +interface GaugeAutoProps { + titleFontSize: number; + gaugeHeight: number; + showLabel: boolean; +} + +export const DEFAULT_THRESHOLDS: ThresholdsConfig = { + mode: ThresholdsMode.Absolute, + steps: [ + { value: -Infinity, color: 'green' }, + { value: 80, color: 'red' }, + ], +}; + +export function calculateGaugeAutoProps(width: number, height: number, title: string | undefined): GaugeAutoProps { + const showLabel = title !== null && title !== undefined; + const titleFontSize = Math.min((width * 0.15) / 1.5, 20); // 20% of height * line-height, max 40px + const titleHeight = titleFontSize * 1.5; + const availableHeight = showLabel ? height - titleHeight : height; + const gaugeHeight = Math.min(availableHeight, width); + + return { + showLabel, + gaugeHeight, + titleFontSize, + }; +} + +export function getFormattedThresholds( + decimals: number, + field: FieldConfig, + value: DisplayValue, + theme: GrafanaTheme +): Threshold[] { + if (field.color?.mode !== FieldColorModeId.Thresholds) { + return [{ value: field.min ?? GAUGE_DEFAULT_MINIMUM, color: value.color ?? FALLBACK_COLOR }]; + } + + const thresholds = field.thresholds ?? DEFAULT_THRESHOLDS; + const isPercent = thresholds.mode === ThresholdsMode.Percentage; + const steps = thresholds.steps; + + let min = field.min ?? GAUGE_DEFAULT_MINIMUM; + let max = field.max ?? GAUGE_DEFAULT_MAXIMUM; + + if (isPercent) { + min = 0; + max = 100; + } + + const first = getActiveThreshold(min, steps); + const last = getActiveThreshold(max, steps); + const formatted: Threshold[] = [{ value: +min.toFixed(decimals), color: getColorForTheme(first.color, theme) }]; + let skip = true; + for (let i = 0; i < steps.length; i++) { + const step = steps[i]; + if (skip) { + if (first === step) { + skip = false; + } + continue; + } + const prev = steps[i - 1]; + formatted.push({ value: step.value, color: getColorForTheme(prev!.color, theme) }); + if (step === last) { + break; + } + } + formatted.push({ value: +max.toFixed(decimals), color: getColorForTheme(last.color, theme) }); + return formatted; +}