From 54c47afb0c519fe8d500d993069e4c660c04550e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B0=D0=B5=D0=B2=20=D0=95=D0=B2=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B9?= Date: Thu, 8 Dec 2022 12:00:14 +0300 Subject: [PATCH] feat: useWidgetData fixes --- jest.config.ts | 4 ++ src/plugins/index.ts | 2 +- src/plugins/yagr/__stories__/mocks/line10.ts | 2 - src/plugins/yagr/__tests__/utils.test.ts | 29 +++++++++ .../yagr/renderer/tooltip/renderTooltip.ts | 4 +- src/plugins/yagr/renderer/useWidgetData.ts | 48 ++------------- src/plugins/yagr/renderer/utils.ts | 59 ++++++++++++++++++- src/plugins/yagr/types.ts | 5 +- src/types/widget.ts | 3 +- test-utils/globals.mock.ts | 12 ++++ test-utils/style.mock.ts | 1 + 11 files changed, 116 insertions(+), 53 deletions(-) create mode 100644 src/plugins/yagr/__tests__/utils.test.ts create mode 100644 test-utils/globals.mock.ts create mode 100644 test-utils/style.mock.ts diff --git a/jest.config.ts b/jest.config.ts index 49abaefb..3cb521dd 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -5,6 +5,10 @@ const cfg: Config.InitialOptions = { preset: 'ts-jest', testEnvironment: 'jsdom', modulePathIgnorePatterns: ['/build/', '/node_modules/'], + moduleNameMapper: { + '^.+\\.(css|scss)$': '/test-utils/style.mock.ts', + }, + setupFiles: ['/test-utils/globals.mock.ts'], }; export default cfg; diff --git a/src/plugins/index.ts b/src/plugins/index.ts index 7285deac..527e1fb4 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -1,5 +1,5 @@ export {YagrPlugin} from './yagr'; -export type {Yagr, YagrWidgetData} from './yagr/types'; +export * from './yagr/types'; export {IndicatorPlugin} from './indicator'; export type {IndicatorWidgetData} from './indicator/types'; export {HighchartsPlugin} from './highcharts'; diff --git a/src/plugins/yagr/__stories__/mocks/line10.ts b/src/plugins/yagr/__stories__/mocks/line10.ts index c9d7a20b..bc0d7097 100644 --- a/src/plugins/yagr/__stories__/mocks/line10.ts +++ b/src/plugins/yagr/__stories__/mocks/line10.ts @@ -57,9 +57,7 @@ export const line10: YagrWidgetData = { }, tooltip: { show: true, - boundClassName: '.wrapper', tracking: 'sticky', - className: 'chartkit-theme_common', }, legend: {}, processing: {}, diff --git a/src/plugins/yagr/__tests__/utils.test.ts b/src/plugins/yagr/__tests__/utils.test.ts new file mode 100644 index 00000000..23ddb221 --- /dev/null +++ b/src/plugins/yagr/__tests__/utils.test.ts @@ -0,0 +1,29 @@ +import {shapeYagrConfig} from '../renderer/utils'; +import type {YagrWidgetData, MinimalValidConfig} from '../types'; + +const DATA: YagrWidgetData['data'] = { + timeline: [1], + graphs: [{data: [45]}], +}; + +describe('plugins/yagr/utils', () => { + describe('shapeYagrConfig > check chart property', () => { + test.each<[Partial, Partial]>([ + [{}, {appereance: {locale: 'en', theme: 'dark'}}], + [{appereance: {locale: 'ru'}}, {appereance: {locale: 'ru', theme: 'dark'}}], + [{appereance: {theme: 'light'}}, {appereance: {locale: 'en', theme: 'light'}}], + [ + {series: {type: 'dots'}, select: {zoom: false}, timeMultiplier: 1}, + { + appereance: {locale: 'en', theme: 'dark'}, + series: {type: 'dots'}, + select: {zoom: false}, + timeMultiplier: 1, + }, + ], + ])('(args: %j)', (chart, expected) => { + const config = shapeYagrConfig({data: DATA, libraryConfig: {chart}, theme: 'dark'}); + expect(config.chart).toEqual(expected); + }); + }); +}); diff --git a/src/plugins/yagr/renderer/tooltip/renderTooltip.ts b/src/plugins/yagr/renderer/tooltip/renderTooltip.ts index ffe89371..5732dc72 100644 --- a/src/plugins/yagr/renderer/tooltip/renderTooltip.ts +++ b/src/plugins/yagr/renderer/tooltip/renderTooltip.ts @@ -1,7 +1,7 @@ import moment from 'moment'; -import {TooltipRow, TooltipRenderOptions, ValueFormatter} from 'yagr'; -import {formatTooltip} from './tooltip'; +import type {TooltipRow, TooltipRenderOptions, ValueFormatter} from '../../types'; import type {TooltipData, TooltipLine} from './types'; +import {formatTooltip} from './tooltip'; const calcOption = (d: T | {[key in string]: T} | undefined) => { return typeof d === 'object' diff --git a/src/plugins/yagr/renderer/useWidgetData.ts b/src/plugins/yagr/renderer/useWidgetData.ts index 22217f3b..8f8b258b 100644 --- a/src/plugins/yagr/renderer/useWidgetData.ts +++ b/src/plugins/yagr/renderer/useWidgetData.ts @@ -1,54 +1,18 @@ import React from 'react'; import {useThemeType} from '@gravity-ui/uikit'; -import {defaults} from 'yagr'; -import type {YagrConfig, YagrTheme, MinimalValidConfig} from 'yagr'; import type {YagrChartProps} from 'yagr/dist/react'; -import {settings} from '../../../libs'; -import type {YagrWidgetData} from '../types'; -import {renderTooltip} from './tooltip'; -import {getXAxisFormatter} from './utils'; +import type {YagrWidgetData, YagrTheme, MinimalValidConfig} from '../types'; +import {shapeYagrConfig} from './utils'; export const useWidgetData = ( args: YagrWidgetData & {id: string}, ): {config: MinimalValidConfig; debug: YagrChartProps['debug']} => { const {id, data, sources, libraryConfig} = args; const theme = useThemeType() as YagrTheme; - const config: Partial & MinimalValidConfig = React.useMemo(() => { - const result: Partial & MinimalValidConfig = { - ...libraryConfig, - timeline: data.timeline, - series: data.graphs, - }; - - result.chart = { - appereance: { - locale: settings.get('lang'), - theme, - ...result.chart?.appereance, - }, - ...result.chart, - }; - - if (result.tooltip?.show !== false) { - result.tooltip = result.tooltip || {}; - result.tooltip.render = result.tooltip?.render || renderTooltip; - } - - result.axes = result.axes || {}; - const xAxis = result.axes[defaults.DEFAULT_X_SCALE]; - - if (xAxis && !xAxis.values) { - xAxis.values = getXAxisFormatter(result.chart.timeMultiplier); - } - - if (!xAxis) { - result.axes[defaults.DEFAULT_X_SCALE] = { - values: getXAxisFormatter(result.chart.timeMultiplier), - }; - } - - return result; - }, [data, libraryConfig, theme]); + const config: MinimalValidConfig = React.useMemo( + () => shapeYagrConfig({data, libraryConfig, theme}), + [data, libraryConfig, theme], + ); const debug: YagrChartProps['debug'] = React.useMemo(() => { const filename = sources ? Object.values(sources) diff --git a/src/plugins/yagr/renderer/utils.ts b/src/plugins/yagr/renderer/utils.ts index 8208c300..546c0f38 100644 --- a/src/plugins/yagr/renderer/utils.ts +++ b/src/plugins/yagr/renderer/utils.ts @@ -1,9 +1,19 @@ import moment from 'moment'; -import type {default as Yagr} from 'yagr'; +import merge from 'lodash/merge'; +import {defaults} from 'yagr'; +import {settings} from '../../../libs'; +import type {Yagr, YagrWidgetData, YagrTheme, YagrChartOptions, MinimalValidConfig} from '../types'; +import {renderTooltip} from './tooltip'; const TOOLTIP_HEADER_CLASS_NAME = '_tooltip-header'; const TOOLTIP_LIST_CLASS_NAME = '_tooltip-list'; +type ShapeYagrConfigArgs = { + data: YagrWidgetData['data']; + libraryConfig: YagrWidgetData['libraryConfig']; + theme: YagrTheme; +}; + export const synchronizeTooltipTablesCellsWidth = (tooltipContainer: HTMLElement) => { const tHeadNode = tooltipContainer.querySelector(`.${TOOLTIP_HEADER_CLASS_NAME}`); const tBodyNode = tooltipContainer.querySelector(`.${TOOLTIP_LIST_CLASS_NAME}`); @@ -105,7 +115,7 @@ export const detectClickOutside = } }; -export const getXAxisFormatter = +const getXAxisFormatter = (msm = 1) => (_: unknown, ticks: number[]) => { const range = (ticks[ticks.length - 1] - ticks[0]) / msm; @@ -119,3 +129,48 @@ export const getXAxisFormatter = return d.format(range < 300 ? 'HH:mm:ss' : 'HH:mm'); }); }; + +export const shapeYagrConfig = (args: ShapeYagrConfigArgs): MinimalValidConfig => { + const {data, libraryConfig, theme} = args; + const config: MinimalValidConfig = { + ...libraryConfig, + timeline: data.timeline, + series: data.graphs, + }; + + const chart: YagrChartOptions = { + appereance: { + locale: settings.get('lang'), + theme, + }, + }; + + merge(chart, config.chart); + + config.chart = chart; + + if (config.tooltip?.show) { + config.tooltip = config.tooltip || {}; + config.tooltip.render = config.tooltip?.render || renderTooltip; + + if (!config.tooltip.className) { + // "className" property prevent default yagr styles adding + config.tooltip.className = 'chartkit-yagr-tooltip'; + } + } + + config.axes = config.axes || {}; + const xAxis = config.axes[defaults.DEFAULT_X_SCALE]; + + if (xAxis && !xAxis.values) { + xAxis.values = getXAxisFormatter(config.chart.timeMultiplier); + } + + if (!xAxis) { + config.axes[defaults.DEFAULT_X_SCALE] = { + values: getXAxisFormatter(config.chart.timeMultiplier), + }; + } + + return config; +}; diff --git a/src/plugins/yagr/types.ts b/src/plugins/yagr/types.ts index aa01795d..cd849ef4 100644 --- a/src/plugins/yagr/types.ts +++ b/src/plugins/yagr/types.ts @@ -1,6 +1,7 @@ -import type {default as YagrLib, RawSerieData, YagrConfig} from 'yagr'; +import type {RawSerieData, YagrConfig} from 'yagr'; -export type Yagr = YagrLib; +export type {default as Yagr} from 'yagr'; +export * from 'yagr/dist/types'; export type YagrWidgetData = { data: { diff --git a/src/types/widget.ts b/src/types/widget.ts index 74ee5eb7..54277574 100644 --- a/src/types/widget.ts +++ b/src/types/widget.ts @@ -1,5 +1,4 @@ -import type Yagr from 'yagr'; -import type {YagrWidgetData} from '../plugins/yagr/types'; +import type {Yagr, YagrWidgetData} from '../plugins/yagr/types'; import type {IndicatorWidgetData} from '../plugins/indicator/types'; import type {Highcharts, HighchartsWidgetData, StringParams} from '../plugins/highcharts/types'; diff --git a/test-utils/globals.mock.ts b/test-utils/globals.mock.ts new file mode 100644 index 00000000..89d53618 --- /dev/null +++ b/test-utils/globals.mock.ts @@ -0,0 +1,12 @@ +// https://stackoverflow.com/a/42685938 +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); diff --git a/test-utils/style.mock.ts b/test-utils/style.mock.ts new file mode 100644 index 00000000..f053ebf7 --- /dev/null +++ b/test-utils/style.mock.ts @@ -0,0 +1 @@ +module.exports = {};