/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ import React from 'react'; import { Partition, SeriesIdentifier, Settings, NodeColorAccessor, ShapeTreeNode, HierarchyOfArrays, } from '@elastic/charts'; import { shallow } from 'enzyme'; import { LensMultiTable } from '../types'; import { PieComponent } from './render_function'; import { PieExpressionArgs } from './types'; import { EmptyPlaceholder } from '../shared_components'; import { chartPluginMock } from '../../../../../src/plugins/charts/public/mocks'; import { LensIconChartDonut } from '../assets/chart_donut'; const chartsThemeService = chartPluginMock.createSetupContract().theme; describe('PieVisualization component', () => { let getFormatSpy: jest.Mock; let convertSpy: jest.Mock; beforeEach(() => { convertSpy = jest.fn((x) => x); getFormatSpy = jest.fn(); getFormatSpy.mockReturnValue({ convert: convertSpy }); }); describe('legend options', () => { const data: LensMultiTable = { type: 'lens_multitable', tables: { first: { type: 'datatable', columns: [ { id: 'a', name: 'a', meta: { type: 'number' } }, { id: 'b', name: 'b', meta: { type: 'number' } }, { id: 'c', name: 'c', meta: { type: 'string' } }, ], rows: [ { a: 6, b: 2, c: 'I', d: 'Row 1' }, { a: 1, b: 5, c: 'J', d: 'Row 2' }, ], }, }, }; const args: PieExpressionArgs = { shape: 'pie', groups: ['a', 'b'], metric: 'c', numberDisplay: 'hidden', categoryDisplay: 'default', legendDisplay: 'default', nestedLegend: false, percentDecimals: 3, hideLabels: false, palette: { name: 'mock', type: 'palette' }, }; function getDefaultArgs() { return { data, formatFactory: getFormatSpy, onClickValue: jest.fn(), chartsThemeService, paletteService: chartPluginMock.createPaletteRegistry(), renderMode: 'display' as const, syncColors: false, }; } test('it shows legend on correct side', () => { const component = shallow( ); expect(component.find(Settings).prop('legendPosition')).toEqual('top'); }); test('it shows legend for 2 groups using default legendDisplay', () => { const component = shallow(); expect(component.find(Settings).prop('showLegend')).toEqual(true); }); test('it hides legend for 1 group using default legendDisplay', () => { const component = shallow( ); expect(component.find(Settings).prop('showLegend')).toEqual(false); }); test('it hides legend that would show otherwise in preview mode', () => { const component = shallow( ); expect(component.find(Settings).prop('showLegend')).toEqual(false); }); test('it calls the color function with the right series layers', () => { const defaultArgs = getDefaultArgs(); const component = shallow( ); (component.find(Partition).prop('layers')![1].shape!.fillColor as NodeColorAccessor)( ({ dataName: 'third', depth: 2, parent: { children: [ ['first', {}], ['second', {}], ['third', {}], ], depth: 1, value: 200, dataName: 'css', parent: { children: [ ['empty', {}], ['css', {}], ['gz', {}], ], depth: 0, sortIndex: 0, value: 500, }, sortIndex: 1, }, value: 41, sortIndex: 2, } as unknown) as ShapeTreeNode, 0, [] as HierarchyOfArrays ); expect(defaultArgs.paletteService.get('mock').getColor).toHaveBeenCalledWith( [ { name: 'css', rankAtDepth: 1, totalSeriesAtDepth: 3, }, { name: 'third', rankAtDepth: 2, totalSeriesAtDepth: 3, }, ], { maxDepth: 2, totalSeries: 5, syncColors: false, behindText: true, }, undefined ); }); test('it hides legend with 2 groups for treemap', () => { const component = shallow( ); expect(component.find(Settings).prop('showLegend')).toEqual(false); }); test('it shows treemap legend only when forced on', () => { const component = shallow( ); expect(component.find(Settings).prop('showLegend')).toEqual(true); }); test('it defaults to 1-level legend depth', () => { const component = shallow(); expect(component.find(Settings).prop('legendMaxDepth')).toEqual(1); }); test('it shows nested legend only when forced on', () => { const component = shallow( ); expect(component.find(Settings).prop('legendMaxDepth')).toBeUndefined(); }); test('it calls filter callback with the given context', () => { const defaultArgs = getDefaultArgs(); const component = shallow(); component.find(Settings).first().prop('onElementClick')!([ [ [{ groupByRollup: 6, value: 6, depth: 1, path: [], sortIndex: 1 }], {} as SeriesIdentifier, ], ]); expect(defaultArgs.onClickValue.mock.calls[0][0]).toMatchInlineSnapshot(` Object { "data": Array [ Object { "column": 0, "row": 0, "table": Object { "columns": Array [ Object { "id": "a", "meta": Object { "type": "number", }, "name": "a", }, Object { "id": "b", "meta": Object { "type": "number", }, "name": "b", }, Object { "id": "c", "meta": Object { "type": "string", }, "name": "c", }, ], "rows": Array [ Object { "a": 6, "b": 2, "c": "I", "d": "Row 1", }, Object { "a": 1, "b": 5, "c": "J", "d": "Row 2", }, ], "type": "datatable", }, "value": 6, }, ], } `); }); test('does not set click listener on noInteractivity render mode', () => { const defaultArgs = getDefaultArgs(); const component = shallow( ); expect(component.find(Settings).first().prop('onElementClick')).toBeUndefined(); }); test('it shows emptyPlaceholder for undefined grouped data', () => { const defaultData = getDefaultArgs().data; const emptyData: LensMultiTable = { ...defaultData, tables: { first: { ...defaultData.tables.first, rows: [ { a: undefined, b: undefined, c: 'I', d: 'Row 1' }, { a: undefined, b: undefined, c: 'J', d: 'Row 2' }, ], }, }, }; const component = shallow( ); expect(component.find(EmptyPlaceholder).prop('icon')).toEqual(LensIconChartDonut); }); }); });