I have an issue when testing a component that renders a couple of text fields, an icon and a chart.
I'm rendering the chart on a <canvas> and for that I use the react hook useRef and all works beautiful.
My problem is when I try to render the component in my unit test. For that purpose I'm using jest and enzyme, so these are the files involved in this process:
React Component
import React, { useEffect, useRef } from 'react';
import Chart from 'chart.js';
import { useWidgetConfiguration } from '../utils/SummitHooks';
const styles = {
canvas: { padding: '30px 30px' },
};
const widgetProperties = {
title: { type: 'string', default: '' },
percent: { type: 'number' },
};
const DougnutWithTextWidget = props => {
const { widgetConf } = props;
const chartRef = useRef();
const widgetDisplayValues = useWidgetConfiguration(
widgetProperties,
widgetConf,
);
useEffect(() => {
if (chartRef.current) {
new Chart(chartRef.current.getContext('2d'), {
type: 'doughnut',
data: {
labels: ['', widgetDisplayValues.title],
datasets: [
{
data: [
parseInt(100 - parseInt(widgetDisplayValues.percent)),
parseInt(widgetDisplayValues.percent),
],
backgroundColor: ['#f4f4f4', '#377d28'],
},
],
text: widgetDisplayValues.title,
},
options: {
animation: {
animateScale: true,
animateRotate: true,
},
cutoutPercentage: 75,
tooltips: false,
},
});
}
}, [widgetDisplayValues, chartRef]);
Chart.defaults.global.legend = false;
return (
<div className='uk-container-expand'>
<div className='widget-account-health-outer'>
<div className='widget-account-health-inner'>
<h1 className='uk-text-center'>{widgetDisplayValues.percent}%</h1>
<span className='uk-h5 uk-text-bold'>
{widgetDisplayValues.title}
</span>
</div>
<canvas
ref={chartRef}
height='400'
width='400'
style={styles.canvas}
></canvas>
</div>
</div>
);
};
export default DougnutWithTextWidget;
Test File
import React from 'react';
import { mount } from 'enzyme';
import DougnutWithTextWidget from '../components/organisms/DougnutWithTextWidget';
describe('Testing the Atomic Component <AccountBarChartWidget />', () => {
let atomicComponent;
const widgetConf = {
title: 'GOALS HEALTH',
percent: 57,
chartType: 'doughnut',
linkTo: '',
};
beforeAll(() => {
atomicComponent = mount(<DougnutWithTextWidget widgetConf={widgetConf} />);
});
afterAll(() => {
atomicComponent.unmount();
});
describe('Validate that the Atomic Component is displaying the data provided as wdgetConf', () => {
it('Ensure that the right amount has been displayed', () => {
// A simple test just for making sure the component is rendering without any problem
expect(2 + 2).toEqual(4);
});
});
});
At this moment, when I use either shallow or render the test works fine, but my goal is to actually mount the component to make sure that the chart has been drawn.
This is the error I'm getting:
Testing the Atomic Component <AccountBarChartWidget />
Validate that the Atomic Component is displaying the data provided as wdgetConf
✕ Ensure that the right amount has been displayed (3ms)
● Testing the Atomic Component <AccountBarChartWidget /> › Validate that the Atomic Component is displaying the data provided as wdgetConf › Ensure that the right amount has been displayed
TypeError: Cannot read property 'length' of null
24 | useEffect(() => {
25 | if (chartRef.current) {
> 26 | new Chart(chartRef.current.getContext('2d'), {
| ^
27 | type: 'doughnut',
28 | data: {
29 | labels: ['', widgetDisplayValues.title],
at Object.acquireContext (node_modules/chart.js/dist/Chart.js:7739:19)
at Chart.construct (node_modules/chart.js/dist/Chart.js:9307:26)
at new Chart (node_modules/chart.js/dist/Chart.js:9294:7)
at DougnutWithTextWidget (src/components/organisms/DougnutWithTextWidget.js:26:7)
at commitHookEffectList (node_modules/react-dom/cjs/react-dom.development.js:22030:26)
at commitPassiveHookEffects (node_modules/react-dom/cjs/react-dom.development.js:22064:11)
at HTMLUnknownElement.callCallback (node_modules/react-dom/cjs/react-dom.development.js:336:14)
at Object.invokeGuardedCallbackDev (node_modules/react-dom/cjs/react-dom.development.js:385:16)
at invokeGuardedCallback (node_modules/react-dom/cjs/react-dom.development.js:440:31)
at flushPassiveEffectsImpl (node_modules/react-dom/cjs/react-dom.development.js:25392:7)
at unstable_runWithPriority (node_modules/scheduler/cjs/scheduler.development.js:697:12)
at runWithPriority$2 (node_modules/react-dom/cjs/react-dom.development.js:12149:10)
at flushPassiveEffects (node_modules/react-dom/cjs/react-dom.development.js:25361:12)
at Object.<anonymous>.flushWork (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1041:10)
at Object.act (node_modules/react-dom/cjs/react-dom-test-utils.development.js:1155:9)
at wrapAct (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:354:13)
at Object.render (node_modules/enzyme-adapter-react-16/src/ReactSixteenAdapter.js:423:16)
at new ReactWrapper (node_modules/enzyme/src/ReactWrapper.js:115:16)
at mount (node_modules/enzyme/src/mount.js:10:10)
at Object.beforeAll (src/__tests__/dougutWithTextWidget.test.js:16:23)
Has anybody tried to test something similar and can point me in the right direction?