I wrote a BarChart
in react. Code is given below.
BarChart.tsx
import "chartjs-plugin-datalabels";
import { HorizontalBar } from "react-chartjs-2";
import styled from "styled-components";
import { BRAND } from "../util/constants";
import schema, { colours } from "../util/theme/schema";
import {DivProps} from "../components/styled/common.styled.type"
import { ICharDataSet, IDataSet, IDeafualtProps } from "./barChart-type";
const defaultProps: IDeafualtProps = {
displayTitle: true,
displayLegend: false,
legendPosition: "left",
ticks: false,
stacked: false,
xAxisDisplay: true,
yAxisDisplay: true,
BC_Title_Text: "",
BC_Label: "",
BC_X_Axis_Label: "",
barPercentage: 0,
tooltips: false,
width: "480px",
height: "303px",
left: "18px",
bottom: "64px",
fontFamily: "'RNHouseSans','Arial',sans-serif",
fontSize: 13,
fontColor: "#808191",
fontWeight: 400,
maintainAspectRatio: true,
responsive: true,
borderWidth: 0,
dataLabelsDisplay: false,
datalabelsColor: `${colours[BRAND]["zb-white"]}`,
datalabelsTextAlign: "center",
displayColors: false,
xAxisGridLinesdisplay: false,
xAxisGridLinesDrawBorder: false,
xAxisGridLinesDrawOnChartArea: false,
xAxisGridLinesDrawTicks: false,
};
const BarChart = (props: any) => {
props = { ...defaultProps, ...props };
const MONTHS = props.MONTHS;
const ChartData = props.ChartData;
const Color = props.Color;
const borderWidth = props.borderWidth;
const dataSets:IDataSet[] = props.stacked
? [
{
label: props.BC_Label,
data: [...ChartData],
backgroundColor: [...Color],
borderWidth: borderWidth,
},
{
label: "stacked",
data: [100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
backgroundColor: props.stackedColor,
borderWidth: borderWidth,
},
]
: [
{
label: props.BC_Label,
data: [...ChartData],
backgroundColor: [...Color],
borderWidth: borderWidth,
},
];
const chartData: ICharDataSet = {
labels: [...MONTHS],
datasets: dataSets,
};
return (
<BarchartContainer
width={`${props.width}`}
height={`${props.height}`}
top={`${props.top}`}
right={`${props.right}`}
flex={`${props.flex}`}
data-testid="bar-chart"
>
<HorizontalBar
data={chartData}
options={{
responsive: props.responsive,
maintainAspectRatio: props.maintainAspectRatio,
width: !props.maintainAspectRatio ? props.width : "auto",
height: !props.maintainAspectRatio ? props.height : "auto",
tooltips: {
displayColors: props.displayColors,
filter: function (tooltipItem: any) {
if (props.tooltips) return props.filterTooltip(tooltipItem);
},
custom: function (tooltipModel :any) {
if (!props.tooltips) tooltipModel.opacity = 0;
},
callbacks: props.tooltips
? {
title: function (tooltipItem :any) {
return props.customiseTooltipTitle(tooltipItem);
},
label: function (tooltipItem :any) {
return props.customiseTooltipLabel(tooltipItem);
},
}
: {},
titleAlign: "center",
titleFontSize: 12,
titleFontFamily: props.fontFamily,
titleFontStyle: "normal",
bodyAlign: "center",
bodyFontSize: 14,
bodyFontFamily: props.fontFamily,
bodyFontStyle: "bold",
},
scales: {
xAxes: [
{
gridLines: {
display: props.xAxisGridLinesdisplay,
color: props.fontColor,
drawBorder: props.xAxisGridLinesDrawBorder,
drawOnChartArea: props.xAxisGridLinesDrawOnChartArea,
drawTicks: props.xAxisGridLinesDrawTicks,
},
display: props.xAxisDisplay,
barPercentage: props.barPercentage,
ticks: {
fontFamily: props.fontFamily,
fontSize: props.fontSize,
fontColor: props.fontColor,
fontStyle: props.fontWeight,
lineHeight: props.xAxisTicksLineHeight,
},
},
],
yAxes: [
{
gridLines: {
display: false,
},
stacked: props.stacked,
ticks: props.ticks
? {
beginAtZero: props.beginAtZero,
min: props.min,
max: props.max,
stepSize: props.stepSize,
display: props.yAxisDisplay,
fontFamily: props.fontFamily,
fontSize: props.fontSize,
fontColor: props.fontColor,
fontStyle: props.fontWeight,
}
: {
display: props.yAxisDisplay,
fontFamily: props.fontFamily,
fontSize: props.fontSize,
fontColor: props.fontColor,
fontStyle: props.fontWeight,
},
},
],
},
layout: {
padding: {
bottom: -20,
},
},
title: {
display: props.displayTitle,
text: props.BC_Title_Text,
fontSize: 14,
fontStyle: 700,
fontColor: "#424B5A",
position: "left",
},
legend: {
display: props.displayLegend,
position: props.legendPosition,
labels: {
fontSize: 14,
fontStyle: 700,
fontColor: "#424B5A",
boxWidth: 0,
},
},
elements: {
rectangle: {
borderSkipped: "none",
},
},
plugins: {
datalabels: {
display: props.dataLabelsDisplay,
color: props.datalabelsColor,
align: "left",
textAlign: props.datalabelsTextAlign,
font: {
size: "14",
weight: "700",
family: props.fontFamily,
lineHeight: "1.3",
},
formatter: function (value: any, context: any) {
return props.customiseDataLabel(value, context);
},
},
},
}}
/>
<X_Axis_Label_Container left={`${props.left}`} bottom={`${props.bottom}`}>
<X_Axis_Label>{props.BC_X_Axis_Label}</X_Axis_Label>
</X_Axis_Label_Container>
</BarchartContainer>
);
};
const BarchartContainer = styled.div <DivProps>`
position: relative;
width: ${(props) => props.width || "100%"};
height: ${(props) => props.height || "100%"};
color: ${schema[BRAND].colors.loginPage.pageSubtitleColor};
top: ${(props) => props.top || "auto"};
right: ${(props) => props.right || "auto"};
flex: ${(props) => props.flex || "auto"};
`;
const X_Axis_Label_Container = styled.div<DivProps>`
position: absolute;
left: ${(props) => props.left || "auto"};
bottom: ${(props) => props.bottom || "auto"};
color: ${schema[BRAND].colors.pageTitle};
`;
const X_Axis_Label = styled.h3`
font-size: 13px;
// color: #808191;
font-weight: 400;
line-height: 18px !important;
`;
export default BarChart;
BarChart.test.tsx
import { render } from "../util/test-utils";
import BarChart from "./BarChart";
describe("barchart test", () => {
it("should show barchart", () => {
const { getByTestId } = render(<BarChart />);
const barchart = getByTestId("bar-chart");
expect(barchart).toBeInTheDocument();
})
})
When I run the test code, I get undefined
error.
TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
67 | {
68 | label: props.BC_Label,
> 69 | data: [...ChartData],
| ^
70 | backgroundColor: [...Color],
71 | borderWidth: borderWidth,
72 | },
What am I missing? How can I fix it?
2
Answers
The error you get is correct. You can not do this with undefined values:
data: [...ChartData]
. The Spread operator throws the error you described.const ChartData = props.ChartData;
– this is undefinedprops.CharData is undefined because you do not pass it as prop
render(<BarChart />)
and it is not initialized in the default props as wellIn your
BarChart
component you have not definedChartData
in yourdefaultProps
. I am assuming yourIDeafualtProps
interface does not haveChartData
property or defined asoptional/undefined
. I would suggest addingChartData
as an empty array indefaultProps
.