Unable To Find Svg Element For Unit-testing Of D3 Component In React Using Enzyme And Cheerio
I have a React component that renders a div element, d3 in another class is used to append a svg element to the above div element.
While unit-testing with enzyme, the find() method is unable to detect the svg element inside the div. This svg element doesn't have any id
as it was created through d3. I referred this https://github.com/airbnb/enzyme/issues/1510 but it didn't help.
I referred to another example which uses cheerio to detect html elements but that didn't work either. https://medium.com/successivetech/unit-testing-react-d3-with-enzyme-and-jest-108735046535
Below is the code from the test file. The first test passes i.e the div element is rendered but the second test fails.
import React from 'react';
import Adapter from 'enzyme-adapter-react-16';
import { configure, mount } from 'enzyme';
import { expect } from 'chai';
import MostConvProds from './MostConvProds';
import { MockedProvider } from "@apollo/react-testing";
import { getDataAndConfig, getHtml, checkSvg } from './Helper';
configure({ adapter: new Adapter() });
const setUp = (props={}) => {
const component = mount(<MockedProvider><MostConvProds {...props}/>
</MockedProvider>);
return component;
};
describe('The component should render according to props', () => {
let component;
beforeEach(() => {
const props = {
count:1,
loading: false,
products: [{productName: 'a', productId: '1', count:10},
{productName: 'b', productId: '2', count:9},
{productName: 'c', productId: '3', count:8},
{productName: 'd', productId: '4', count:7},
{productName: 'e', productId: '5', count:6}
],
}
component = setUp(props);
});
it('Should render the div without any errors', () => {
const wrapper = component.find('#mostConvProds');
expect(wrapper).to.have.length(1);
// const svg = Icons.IconWrapper(props, children);
// const wrapper1 = wrapper.find('svg').html();
//expect(wrapper1.find(<rect> </rect>)).to.have.length(1);
})
it('Should render svg element without any errors', () => {
const wrapper = component.find('#mostConvProds');
expect(getHtml(wrapper, "svg")).to.have.length(1);
//expect(component.find(`svg[viewBox="0 0 440
//150"]`)).to.have.length(1); //didn't work
})
})
The Helper.js file is as follows
const cheerio = require('cheerio');
export const checkSvg = (component) => {
const $ = getHtml(component, 'svg');
const svgHeight = $('svg').attr('height');
const svgWidth = $('svg').attr('width');
return svgHeight == '150' && svgWidth == '440';
}
export const getHtml = (component, tag) => {
const cheerioData = cheerio.load(component.find(tag).html());
return cheerioData;
}
The error message
Method “html” is meant to be run on 1 node. 0 found instead.
9 |
10 | export const getHtml = (component, tag) => {
> 11 | const cheerioData = cheerio.load(component.find(tag).html());
| ^
12 | return cheerioData;
13 | }
Below is the component that renders the div
class d3Component extends Component {
componentDidMount(){
new d3class(this.refs.mostConChart, this.props.products)
}
render() {
return (
<div id={'mostConvProds'} className={style.container}
ref='mostConChart'> </div>
)
}
}
the d3Class
is where all the d3 code is present.
import * as d3 from 'd3'
const HEIGHT = 150;
const WIDTH = 350;
export default class d3Class {
constructor(element, product) {
const svg = d3.select(element)
.append("svg")
.attr("width", WIDTH + 90)
.attr("height", HEIGHT)
.attr("x",0)
.attr("y",0)
...
...
}
}
Any help will be appreciated.
Answer
Ok, so following up Will Jenkins' suggestion that the problem with componentdidMount()
being called after the test. I found a solution using cheerio.
const cheerio = require('cheerio');
Inside the describe()
the below test passes
it('Should render svg element without any errors', () => {
let wrapper = component.find('#mostConvProds');
const $ = cheerio.load(wrapper.html());
expect($('svg')).to.have.length(1);
expect($('rect')).to.have.length(5);
expect($('text')).to.have.length(10);
)}
The d3 elements will now be detected during the tests.
Related Questions
- → Import statement and Babel
- → should I choose reactjs+f7 or f7+vue.js?
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → .tsx webpack compile fails: Unexpected token <
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → React Native with visual studio 2015 IDE
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM
- → How do I determine if a new ReactJS session and/or Browser session has started?
- → Alt @decorators in React-Native
- → How to dynamically add class to parent div of focused input field?