Thursday, 9 November 2023

Issue in creaating react jest test case when using chart.js

I have below test case. Please dont read entire code. (Its not necessary). what i am trying to say i wrote atleast 100times, checked with chatgpt, google bard still not able to make this test case successful. for all the other component all the test cases are becoming successful. below is my code.(just for reference).

import React, { useEffect, useRef, useState } from 'react';
import { Chart, ChartConfiguration, registerables } from 'chart.js';
import './EmailLineChart.styles.css';
import { useUser } from '../../common/context/context';

const DataLineChart: React.FC = () => {
    const chartRef = useRef<HTMLCanvasElement>(null);
    const chartInstanceRef = useRef<Chart | null>(null);
    const [data, setData] = useState<{ month: string; success: number; failed: number; processing?: number }[]>([]);
    const [downloadFormat, setDownloadFormat] = useState<string>('chart');
    const [filterMonth, setFilterMonth] = useState<string>('');
    const [chartType, setChartType] = useState<'line'|'bar'>('line');

   
    const baseUrl = process.env.REACT_APP_BASE_URL;

    let url = `${baseUrl}/email/reports/count?type=year&tag=${tag}&service_name=${servicename}`;
    const tenantData = useUser();
  

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                const apiData = await response.json();
                const monthlyReports = apiData.monthlyReports;
            

                if (!monthlyReports) {
                    console.error('No monthlyReports data in API response');
                    return;  // Early return if no monthlyReports data
                }

                const chartData = Object.keys(monthlyReports).map((month) => ({
                    month,
                    success: monthlyReports[month].SUCCESS,
                    failed: monthlyReports[month].FAILED,
                    processing: monthlyReports[month].PROCESSING || 0,
                }));
                // Sort data by month
                chartData.sort((a, b) => new Date(a.month).getTime() - new Date(b.month).getTime());
                setData(chartData);
            } catch (error) {
                console.error('Error fetching data:', error);
            }
        };
        fetchData();
    }, []);
    useEffect(() => {
        if (chartInstanceRef.current) {
            chartInstanceRef.current.destroy();
        }
        if (chartRef.current && downloadFormat === 'chart') {
            Chart.register(...registerables);
            const ctx = chartRef.current.getContext('2d');
            const filteredData = filterMonth ? data.filter((item) => item.month === filterMonth) : data;
            if (ctx) {
                const gradient1 = ctx.createLinearGradient(0, 0, 0, 400);
                gradient1.addColorStop(0, 'rgba(75, 192, 192, 0.6)');
                gradient1.addColorStop(1, 'rgba(75, 192, 192, 0)');
              
                const gradient2 = ctx.createLinearGradient(0, 0, 0, 400);
                gradient2.addColorStop(0, 'rgba(255, 99, 132, 0.6)');
                gradient2.addColorStop(1, 'rgba(255, 99, 132, 0)');
                
                const config: ChartConfiguration<'line'|'bar'> = {
                    type: chartType,
                    data: {
                        labels: filteredData.map((item) => item.month),
                        datasets: [
                            {
                                label: 'Success',
                                data:  filteredData.map((item) => item.success),
                                borderColor:  'rgba(75, 192,198, 0.9)',
                                fill: true,
                                backgroundColor:'rgba(75, 192, 192, 0.3)',
                                pointBackgroundColor: 'rgba(75, 192, 192, 0.9)',
                                pointBorderColor:'rgba(75, 250, 192, 0.9)',
                                pointHoverBackgroundColor: 'rgba(75, 350, 192, 0.9)',
                                pointHoverBorderColor: 'rgba(75, 350, 192, 0.9)',
                                pointHoverRadius: 8,
                                pointHoverBorderWidth: 5,
                                tension: 0.1,
                            },
                            {
                                label: 'Failed',
                                data:  filteredData.map((item) => item.failed),
                                borderColor: 'rgba(255, 99, 132, 0.4)',
                                fill: true,
                                backgroundColor: 'rgba(255, 99, 132, 0.2)',
                                pointBackgroundColor: 'rgba(255, 99, 132, 0.3)',
                                pointBorderColor: 'rgba(255, 99, 132, 0.9)',
                                pointHoverBackgroundColor: 'rgba(255, 99, 132, 0.3)',
                                pointHoverBorderColor: 'rgba(255, 99, 132, 0.3)',
                                pointHoverRadius: 8,
                                pointHoverBorderWidth: 5,
                                tension: 0.1,
                            },
                        ],
                    },
                    options: {
                        responsive: true,
                        animation: {
                            duration: 2000,
                            easing: 'easeInOutBounce',
                        },
                        scales: {
                            x: {
                                title: {
                                    display: true,
                                    text: 'Month',
                                },
                                grid: {
                                    color: 'gray', // change this as needed
                                    display: false,
                                },
                                ticks: {
                                    color: 'black', // change this as needed
                                    font: {
                                        size: 10,
                                    }
                                },
                                stacked:true
                            },
                            y: {
                                title: {
                                    display: true,
                                    text: 'Number of Emails',
                                },
                                ticks: {
                                    color: 'black', // change this as needed
                                    font: {
                                        size: 10,
                                    }
                                },
                                grid: {
                                    color: 'gray', // change this as needed
                                    display: false,
                                },
                                stacked:true,
                            },
                        }
                    }
                    ,                      
                };
                chartInstanceRef.current = new Chart(ctx, config);
            }
        }
          
          
    }, [downloadFormat, data, filterMonth]); 
  
    useEffect(() => {
        if (chartInstanceRef.current) {
            const chart = chartInstanceRef.current;
            chart.data.labels = data.map((item) => item.month);
            chart.data.datasets[0].data = data.map((item) => item.success||0);
            chart.data.datasets[1].data = data.map((item) => item.failed||0);
            chart.update();
        }
    }, [data]);


    
    const filteredData = filterMonth ? data.filter((item) => item.month === filterMonth) : data;
    const isChartSelected = downloadFormat === 'chart';


    return (
        <div className='chart'>
                <canvas ref={chartRef} className='chart-wrapper'></canvas>           
        </div>
    );
};
export default DataLineChart;

Since my code uses custom hook and chart.js so became difficult to write the case, but it is giving error on render only. I could not move forward at all.

I wrote below test case.

import React from 'react';
import { render } from '@testing-library/react';
import { Chart, registerables } from 'chart.js'; // Import Chart.js as usual
import DataLineChart from './DataLineChart';

jest.mock('../../common/context/context', () => ({
  useUser: jest.fn(() => ({ tenantData: { tenantId: 'mockedTenantId' } })),
}));

jest.mock('chart.js')

describe('DataLineChart', () => {
  it('renders without errors', () => {
    render(<DataLineChart />);
  });
});

but error is coming

"TypeError: undefined is not iterable (cannot read property Symbol(symbol.iterator)"

Basically error comes in this line . Chart.register(...registerables); . can anyone of you guide how to mock chart.js. how to do testing of these type of component? I have 95% code coverage and struggling badly for last 10 days. I used many ways to mock chart.js but nothing worked. chart.js I am using 3.9.1 version. if any suggestion to modify code or test case that would be really helpful. I am using jest. i can also provide full version of code if it is helpful in anyway.



from Issue in creaating react jest test case when using chart.js

No comments:

Post a Comment