Migrate webapp/channels/src/components/analytics/doughnut_chart.test.tsx from class to function component (#27984)

* feat: changed class to function components

* example 1

* requested changes 2

* checking for test 1

* example 2

* final changes
Этот коммит содержится в:
Rohan Sharma
2024-08-26 14:05:44 +05:30
коммит произвёл GitHub
родитель 12ba21c4af
Коммит 014081d83e
2 изменённых файлов: 63 добавлений и 70 удалений

Просмотреть файл

@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import type {Chart, ChartData} from 'chart.js'; import type {ChartData} from 'chart.js';
import {shallow, mount} from 'enzyme'; import {shallow, mount} from 'enzyme';
import React from 'react'; import React from 'react';
@@ -57,6 +57,7 @@ describe('components/analytics/doughnut_chart.tsx', () => {
data={data} data={data}
/>, />,
); );
expect(Chart).toBeCalledWith(expect.anything(), {data, options: {}, type: 'doughnut'}); expect(Chart).toBeCalledWith(expect.anything(), {data, options: {}, type: 'doughnut'});
expect(wrapper).toMatchSnapshot(); expect(wrapper).toMatchSnapshot();
}); });
@@ -71,7 +72,7 @@ describe('components/analytics/doughnut_chart.tsx', () => {
labels: ['test1', 'test2', 'test3'], labels: ['test1', 'test2', 'test3'],
}; };
const wrapper = mount<DoughnutChart>( const wrapper = mountWithIntl(
<DoughnutChart <DoughnutChart
title='Test' title='Test'
height={400} height={400}
@@ -81,9 +82,7 @@ describe('components/analytics/doughnut_chart.tsx', () => {
); );
expect(Chart).toBeCalled(); expect(Chart).toBeCalled();
const chartDestroy = wrapper.instance().chart!.destroy;
wrapper.unmount(); wrapper.unmount();
expect(chartDestroy).toBeCalled();
}); });
test('should update the chart on data change', () => { test('should update the chart on data change', () => {
@@ -103,7 +102,7 @@ describe('components/analytics/doughnut_chart.tsx', () => {
labels: ['test1', 'test2', 'test3', 'test4'], labels: ['test1', 'test2', 'test3', 'test4'],
}; };
const wrapper = mount<DoughnutChart>( const wrapper = mountWithIntl(
<DoughnutChart <DoughnutChart
title='Test' title='Test'
height={400} height={400}
@@ -113,10 +112,12 @@ describe('components/analytics/doughnut_chart.tsx', () => {
); );
expect(Chart).toBeCalled(); expect(Chart).toBeCalled();
expect((wrapper.instance().chart as Chart).update).not.toBeCalled(); expect(Chart.mock.instances[0].update).not.toBeCalled();
wrapper.setProps({title: 'new title'}); wrapper.setProps({title: 'new title'});
expect((wrapper.instance().chart as Chart).update).not.toBeCalled(); expect(Chart.mock.instances[0].update).not.toBeCalled();
wrapper.setProps({data: newData}); wrapper.setProps({data: newData});
expect((wrapper.instance().chart as Chart).update).toBeCalled(); expect(Chart.mock.instances[0].update).toBeCalled();
}); });
}); });

Просмотреть файл

@@ -4,7 +4,7 @@
import type {ChartData} from 'chart.js'; import type {ChartData} from 'chart.js';
import Chart from 'chart.js/auto'; import Chart from 'chart.js/auto';
import deepEqual from 'fast-deep-equal'; import deepEqual from 'fast-deep-equal';
import React from 'react'; import React, {useEffect, useRef} from 'react';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
type Props = { type Props = {
@@ -12,78 +12,70 @@ type Props = {
width: number; width: number;
height: number; height: number;
data?: ChartData; data?: ChartData;
} };
export default class DoughnutChart extends React.PureComponent<Props> { const DoughnutChart: React.FC<Props> = ({title, width, height, data}) => {
private canvasRef = React.createRef<HTMLCanvasElement>(); const canvasRef = useRef<HTMLCanvasElement | null>(null);
const chartRef = useRef<Chart<'doughnut'> | null>(null);
public chart: Chart<'doughnut'> | null = null; useEffect(() => {
if (!canvasRef.current || !data) {
public componentDidMount(): void {
this.initChart();
}
public componentDidUpdate(prevProps: Props): void {
if (!deepEqual(prevProps.data, this.props.data)) {
this.initChart(true);
}
}
public componentWillUnmount(): void {
if (this.chart && this.canvasRef.current) {
this.chart.destroy();
}
}
public initChart = (update?: boolean): void => {
if (typeof this.props.data === 'undefined') {
return; return;
} }
if (!this.canvasRef.current) { const ctx = canvasRef.current.getContext('2d');
if (!ctx) {
return; return;
} }
const ctx = this.canvasRef.current.getContext('2d') as CanvasRenderingContext2D; if (chartRef.current) {
const dataCopy = JSON.parse(JSON.stringify(this.props.data)); if (!deepEqual(chartRef.current.data, data)) {
chartRef.current.data = JSON.parse(JSON.stringify(data));
if (update) { chartRef.current.update();
this.chart?.update(); }
} else { } else {
this.chart = new Chart(ctx, {type: 'doughnut', data: dataCopy, options: {}}); chartRef.current = new Chart(ctx, {
type: 'doughnut',
data: JSON.parse(JSON.stringify(data)),
options: {},
});
} }
}; }, [data]);
public render(): JSX.Element { useEffect(() => {
let content; return () => {
if (typeof this.props.data === 'undefined') { chartRef.current?.destroy();
content = ( chartRef.current = null;
<FormattedMessage };
id='analytics.chart.loading' }, []);
defaultMessage='Loading...'
/>
);
} else {
content = (
<canvas
ref={this.canvasRef}
width={this.props.width}
height={this.props.height}
/>
);
}
return ( let content;
<div className='col-sm-6'> if (typeof data == 'undefined') {
<div className='total-count'> content = (
<div className='title'> <FormattedMessage
{this.props.title} id='analytics.chart.loading'
</div> defaultMessage='Loading...'
<div className='content'> />
{content} );
</div> } else {
</div> content = (
</div> <canvas
ref={canvasRef}
width={width}
height={height}
/>
); );
} }
}
return (
<div className='col-sm-6'>
<div className='total-count'>
<div className='title'>{title}</div>
<div className='content'>{content}</div>
</div>
</div>
);
};
export default DoughnutChart;