Ad

Unable To Find Svg Element For Unit-testing Of D3 Component In React Using Enzyme And Cheerio

- 1 answer

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.

Ad

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.

Ad
source: stackoverflow.com
Ad