Невозможно найти элемент svg для модульного тестирования компонента d3 в React с использованием фермента и cheerio. - PullRequest
0 голосов
/ 23 сентября 2019

У меня есть компонент React, который отображает элемент div, d3 в другом классе используется для добавления элемента svg к указанному выше элементу div.

Во время модульного тестирования с помощью фермента метод find ()невозможно обнаружить элемент svg внутри div.Этот элемент svg не имеет id, так как он был создан с помощью d3.Я сослался на это https://github.com/airbnb/enzyme/issues/1510, но это не помогло.

Я сослался на другой пример, который использует cheerio для обнаружения html-элементов, но это тоже не сработало.https://medium.com/successivetech/unit-testing-react-d3-with-enzyme-and-jest-108735046535

Ниже приведен код из тестового файла.Первый тест пройден, т.е. элемент div визуализируется, но второй тест не пройден.

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
})
})

Файл Helper.js выглядит следующим образом

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;
}

Сообщение об ошибке

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 | }

Ниже представлен компонент, который визуализирует 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>
     )
   }
}

, где d3Class присутствует весь код d3.

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)


         ...
         ...
     }
    }

Любая помощь будет оценена.

1 Ответ

0 голосов
/ 24 сентября 2019

Ваша проблема вызвана тем, что ваш svg добавляется к целевому элементу в componentDidMount, что происходит после того, как ваш тест уже завершен.Обычно достаточно вызвать wrapper.update() для запуска повторного рендеринга, но поскольку ваш код d3 модифицирует DOM вне мира компонентов React, изменения, которые он вызывает, не будут регистрироваться механизмом сравнения.

Одним из способов решения этой проблемы является предоставление обратного вызова к вашему коду d3class, который будет вызываться после его запуска.Вы можете использовать это для обновления какого-либо состояния вашего родительского компонента, чтобы он заново отображал новое содержимое, когда вы вызываете .update()

export default class d3Class {
    constructor(element, product, onComplete) {
        const bars = rects.enter()

          // snip //

          bars.append("svg:title")
          .text(d => d.productName);

           onComplete && onComplete()

С другого конца вы бы подключили его следующим образом:

class d3Component extends Component {

    componentDidMount(){
         new d3class(this.refs.mostConChart, this.props.products, ()=>this.setState({isMounted:true}))
     }

    render() {
        return (
            <div id={'mostConvProds'} className={style.container} 
             ref='mostConChart'> </div>
         )
    }
}
...