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