Reactjs 用Jest测试Recharts折线图的方法

Reactjs 用Jest测试Recharts折线图的方法,reactjs,redux,jestjs,mocking,recharts,Reactjs,Redux,Jestjs,Mocking,Recharts,我对反应相当陌生,但对开玩笑也完全陌生。我正在测试我认识的其他人已经开发的recharts折线图,与真正的TDD相反。我正在寻找一种方法来使用下面的图表代码。我想做的是模拟来自MainapResponseReducer的数据存储,并将其用作数据部分的驱动程序,我还想测试recharts的组件和此代码按钮组件、折线图渲染和工具提示渲染,并具有正确的数据,但目前可以跳过X轴和Y轴以及线条,最大的问题是使用数据和工具提示进行图表渲染。最好的方法是什么?任何开始使用的示例代码都非常感谢,因为我几乎不知道

我对反应相当陌生,但对开玩笑也完全陌生。我正在测试我认识的其他人已经开发的recharts折线图,与真正的TDD相反。我正在寻找一种方法来使用下面的图表代码。我想做的是模拟来自MainapResponseReducer的数据存储,并将其用作数据部分的驱动程序,我还想测试recharts的组件和此代码按钮组件、折线图渲染和工具提示渲染,并具有正确的数据,但目前可以跳过X轴和Y轴以及线条,最大的问题是使用数据和工具提示进行图表渲染。最好的方法是什么?任何开始使用的示例代码都非常感谢,因为我几乎不知道如何使用它:谢谢。代码如下:

import React, { useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { useDispatch, useSelector } from 'react-redux';

import {
    LineChart,
    Line,
    XAxis,
    YAxis,
    CartesianGrid,
    Tooltip,
    ReferenceLine,
    ResponsiveContainer
} from 'recharts';
import { object } from 'prop-types';
import styles from '../styles.scss';

const useStyles = makeStyles((theme) => ({
    buttonOff: {
        width: '75px',
        height: '24px',
        borderRadius: '50px',
        margin: '2.5px',
        color: 'rgba(8, 8, 59, 1)',
        boxShadow: ' 0px 0px 0px 0px rgba(8, 8, 59, 1)',
        borderStyle: 'solid',
        backgroundColor: 'rgba(8, 8, 59, 0.1)',
        opacity: '0.3'
    },
    buttonRed: {
        width: '75px',
        height: '24px',
        borderRadius: '50px',
        borderColor: '#CD2821',
        margin: '2.5px',
        color: '#BE1710',
        borderStyle: 'solid',
        backgroundColor: '#FAE9E8'

    },
    buttonGreen: {
        width: '75px',
        height: '24px',
        borderRadius: '50px',
        borderColor: '#288179',
        margin: '2.5px',
        color: '#22766F',
        borderStyle: 'solid',
        backgroundColor: '#E9F2F1'

    },
    buttonBlue: {
        width: '75px',
        height: '24px',
        borderRadius: '50px',
        borderColor: '#0E65BC',
        margin: '2.5px',
        color: '#0E65BC',
        borderStyle: 'solid',
        backgroundColor: '#E7F1FA'

    }

}));

const CustomTooltip = (props) => {
    const {
        active, label, payload, temp2
    } = props;

    if (active && payload && payload.length) {
        return (
      <div style={{
          backgroundColor: '#16214F', width: '160px', height: '90px', left: '80px', position: 'relative'
      }}
      >
{typeof payload[0] !== 'undefined'
    && <p style={{ color: '#FFFFFF', paddingTop: '0px', fontSize: '15px' }}>{payload[0].payload.fsc_YR_NBR} - WEEK {payload[0].payload.week_NBR}</p>}
          {typeof payload[2] !== 'undefined'
        && (
<div style={{ color: '#FFFFFF', display: 'inline', marginRight: '20px' }}><button style={{
    backgroundColor: payload[2].stroke, width: '25px', height: '7px', borderRadius: '50px'
}} disabled
/>{` ${payload[2].value.toFixed(2)}  `}

</div>
        ) }
        {typeof payload[1] !== 'undefined'
        && (
<div style={{ color: '#FFFFFF', display: 'inline' }}><button style={{
    backgroundColor: payload[1].stroke, width: '25px', height: '7px', borderRadius: '50px'
}} disabled
/>{` ${payload[1].value.toFixed(2)}`}

</div>
        ) }
        {typeof payload[0] !== 'undefined'
        && (
<div style={{ color: '#FFFFFF' }}><button style={{
    backgroundColor: payload[0].stroke, width: '25px', height: '7px', borderRadius: '50px'
}} disabled
/>{` ${payload[0].value.toFixed(2)}`}

</div>
        ) }
      </div>

        );
    }

    return null;
};

const ForecastGraph = () => {
    const dispatch = useDispatch();
    const mainApiResponse = useSelector((state) => state.mainApiResponseReducer);
    const temp2 = [];
    let i; let
        t1 = 1; let pos;
    let max = 10;
    temp2.push({ week: 0 });

    const data = [];
    if (mainApiResponse.data) {
        if (mainApiResponse.data[0]) var flag = mainApiResponse.data[0].fsc_WK_NBR;
        for (let c = 0; c < mainApiResponse.data.length; c++) {
            if (flag === mainApiResponse.data[c].fsc_WK_NBR) data.push(mainApiResponse.data[c]);
            else {
                data.push({ fsc_WK_NBR: flag }); c--;
            }
            if (flag == 52) flag = 0;
            flag++;
        }
        // console.log('d');
        // console.log(data);

        for (i = 0; i < data.length; i++) {
            if (Object.keys(data[i]).length > 3) {
                pos = i;
                break;
            }

            pos = data.length;
        }
        if (data[i - 1]) {
            console.log(data[i - 1].fsc_YR_NBR);
            var cp = 52 * (mainApiResponse.year - data[i - 1].fsc_YR_NBR) + (mainApiResponse.week - data[i - 1].fsc_WK_NBR);
            console.log(`cp= + ${cp}`);
            const wk = data[i - 1].fsc_WK_NBR;
        }

        console.log(pos);
        if ((pos + cp) < 156) {
            for (var j = 0; j < (156 - pos); j++) {
                temp2.push({ fsc_WK_NBR: t1 });
                t1++;
                if (t1 > 52) t1 = 1;
            }
            pos = 156;
        }
        i = 0;
        console.log('a');
        console.log(temp2);
        let m = 0;
        for (m = (pos + cp - 156); m < data.length; m++) {
            if (t1 > 52) { t1 = 1; }
            if (Object.keys(data[m]).length == 3) {
                temp2.push({
                    fsc_WK_NBR: t1, week_NBR: data[m].fsc_WK_NBR, fsc_YR_NBR: data[m].fsc_YR_NBR, sales_UNITS: data[m].sales_UNITS
                });
                t1++;
                if (max < data[m].sales_UNITS) { max = data[m].sales_UNITS; }
            } else if (Object.keys(data[m]).length > 3) break;
            else { temp2.push({ fsc_WK_NBR: t1 }); t1++; }
        }
        for (let q = 0; q < cp - 1; q++) {
            if (t1 > 52) { t1 = 1; }
            temp2.push({ fsc_WK_NBR: t1 });
            t1++;
            m++;
        }

        for (var j = m; j < data.length; j++) {
            if (t1 > 52) { t1 = 1; }i++;
            if (Object.keys(data[j]).length == 4) {
                temp2.push({
                    fsc_WK_NBR: t1, week_NBR: data[j].fsc_WK_NBR, fsc_YR_NBR: data[j].fsc_YR_NBR, forecast_UNITS_BY: data[j].forecast_UNITS_BY, forecast_UNITS_LIFT: data[j].forecast_UNITS_LIFT
                });
                t1++;
                if (max < data[j].forecast_UNITS_BY) { max = data[j].forecast_UNITS_BY; }
            } else { temp2.push({ fsc_WK_NBR: t1 }); t1++; }
        }
        for (let k = i; k < 52; k++) {
            if (t1 > 52) { t1 = 1; }
            temp2.push({ fsc_WK_NBR: t1 });
            t1++;
        }
    }
    console.log('final');
    console.log(temp2);

    const classes = useStyles();
    const [on1, setButton1] = useState(true);
    const [on2, setButton2] = useState(true);
    const [on3, setButton3] = useState(true);

    const handlebutton1 = () => {
        setButton1(!on1);
    };
    const handlebutton2 = () => {
        setButton2(!on2);
    };
    const handlebutton3 = () => {
        setButton3(!on3);
    };
    const formatXAxis = (tickItems) => (tickItems / 13) * 3;

    return (
        <div className={ styles.graphGrid }>
        <center>
          {on1
            && <button className={ classes.buttonRed } onClick={ handlebutton1 }>Sales</button>
          }
          {!on1
            && (
            <button className={ classes.buttonOff }
            onClick={ handlebutton1 }
        >Sales
</button>
    )
        }

        {on2
      && <button className={ classes.buttonGreen } onClick={ handlebutton2 }>B2</button>
        }
        {!on2
    && (
<button className={ classes.buttonOff }
    onClick={ handlebutton2 }
>BYD
</button>
    )
        }
                {on3
      && <button className={ classes.buttonBlue } onClick={ handlebutton3 }>B3</button>
        }
        {!on3
    && (
<button className={ classes.buttonOff }
    onClick={ handlebutton3 }
>Lowe's
</button>
    )
        }

    <ResponsiveContainer height="50%" width="99%" aspect={ 4 }>
        <LineChart
            width={ 500 }
            height={ 300 }
            data={ temp2 }
            margin={{
                top: 15,
                right: 30,
                left: 20,
                bottom: 5
            }}
        >
        <CartesianGrid vertical={ false } opacity="0.4" />
        <XAxis 
            dataKey="fsc_WK_NBR" 
            xAxisId={ 0 } 
            tickFormatter={ formatXAxis } 
            interval={ 12 } 
            tickLine 
            tickMargin={ 5 } />
        <YAxis 
            type="number" 
            domain={ [0, max] } 
            tickCount={ 7 } 
            axisLine={ false } 
            tickLine={ false } />
        <Tooltip 
            offset="1" 
            content={ <CustomTooltip temp2={ temp2 } /> } />
        <ReferenceLine x={ 52 } />
        <ReferenceLine x={ 104 } />
        <ReferenceLine x={ 156 } stroke="black" />

        {on1 && temp2.length
        && <Line type="monotone" dataKey="sales_UNITS" stroke="red" isAnimationActive={ false } dot={{ r: 0 }} />// red
        }

        {on2 && temp2.length
        && <Line type="monotone" dataKey="forecast_UNITS_BY" stroke="green" isAnimationActive={ false } dot={{ r: 0 }} /> // green
        }

        {on3 && temp2.length
        && <Line type="monotone" dataKey="forecast_UNITS_LIFT" stroke="blue" isAnimationActive={ false } dot={{ r: 0 }} /> // blue
        }

        </LineChart>
    </ResponsiveContainer>
    </center>
    </div>
  );
};

export default ForecastGraph;

我只是想开始看看是否可以呈现这个ForecastGraph组件。下面是我的代码,但我遇到以下错误,不确定如何继续处理元素类型:

ForecastGraph.test.jsx:

/**
 * @jest-environment jsdom
 */
 import React from 'react';
 import { mount } from 'enzyme';
 import {ForecastGraph} from '../../../src/common/components/common/ForecastTab/ForecastGraph';
 
 describe('ForecastGraph/>', () => {

    let wrapper;

    // const data = [
    //     {fsc_WK_NBR: 11, fsc_YR_NBR: 2021, sales_UNITS: 160},
    //     {fsc_WK_NBR: 12, fsc_YR_NBR: 2021, sales_UNITS: 203},
    //     {fsc_WK_NBR: 13, fsc_YR_NBR: 2021, sales_UNITS: 172},
    //     {fsc_WK_NBR: 14, fsc_YR_NBR: 2021, sales_UNITS: 170},
    //     {fsc_WK_NBR: 15, fsc_YR_NBR: 2021, sales_UNITS: 249},
    //     {fsc_WK_NBR: 16, fsc_YR_NBR: 2021, sales_UNITS: 166},
    //     {fsc_WK_NBR: 17, fsc_YR_NBR: 2021, sales_UNITS: 108},
    //     {fsc_WK_NBR: 18, fsc_YR_NBR: 2021, sales_UNITS: 207},
    //     {fsc_WK_NBR: 19, fsc_YR_NBR: 2021, forecast_UNITS_BY: 153 ,forecast_UNITS_LIFT:190}
    // ];
 
    it('rendering ForecastGraph Component', () => {
        wrapper = mount(<ForecastGraph/>).toJSON();
        expect(wrapper).toMatchSnapshot();
    });
 });
测试失败控制台日志:

 FAIL  tests/components/ForecastGraph/ForecastGraph.test.jsx
  ForecastGraph/>
    × rendering ForecastGraph Component (138ms)

  ● ForecastGraph/> › rendering ForecastGraph Component

    Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

    Check the render method of `WrapperComponent`.

      25 |
      26 |     it('rendering ForecastGraph Component', () => {
    > 27 |         wrapper = mount(<ForecastGraph/>).toJSON();
         |                   ^
      28 |         expect(wrapper).toMatchSnapshot();
      29 |     });
      30 |  });

      at createFiberFromTypeAndProps (node_modules/react-dom/cjs/react-dom.development.js:23965:21)
      at Object.<anonymous> (tests/components/ForecastGraph/ForecastGraph.test.jsx:27:19)