highcharts 如何模拟点击Highchart

niwlg2el  于 2022-11-10  发布在  Highcharts
关注(0)|答案(1)|浏览(238)

这是我的DashboardPage组件:

export const DashboardPage = (props) => {

    const [mounted, setMounted] = useState(false);

    const { index } = props;

    let navigate = useNavigate();

    useEffect(() => {
        if (mounted === false) {
            setMounted(true);
            index();
        }
    }, [mounted, index]);

    const optionNUsersPerCompany = {
        chart: {
            plotBackgroundColor: null,
            plotBorderWidth: null,
            plotShadow: false,
            type: 'pie'
        },
        title: {
            text: 'Utenti per azienda'
        },
        tooltip: {
            pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
        },
        accessibility: {
            point: {
                valueSuffix: '%'
            }
        },
        plotOptions: {
            pie: {
                allowPointSelect: true,
                cursor: 'pointer',
                dataLabels: {
                    enabled: true,
                    format: '<b>{point.name}</b>: {point.percentage:.1f} %'
                },
            }
        },
        series: [{
            name: 'Utenti',
            colorByPoint: true,
            data: getDataUsersPerCompany(props.items),
            point: {
                events: {
                    click: (e) => {
                        console.log(e);
                        props.setCompanyIdInUsersStore(e.target.point.idCompany);
                        return navigate(PATH_USERS);
                    }
                }
            }
        }]
    }

    return (
        <Chart options={optionNUsersPerCompany} />
    )
}

const mapDispatchToProps = (dispatch) => {

    return {
        index: () => dispatch(statsActions.index()),
        setCompanyIdInUsersStore: (id) => dispatch(companiesActions.setCompanyIdInUsersStore(id)),
    };
}

const mapStateToProps = (state) => {

    return {
        items: state.stats.items,
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage);

这是简单的 highcharts 组件:

import React, { useState } from "react";

import HighchartsReact from "highcharts-react-official";
import Highcharts from 'highcharts';

export default React.memo(function Chart(props) {

    const [currentOptions, setCurrentOptions] = useState({});

    /**
     * Questo controllo serve a non re-draware per due volte di seguito i containers
     */
    if (JSON.stringify(props.options) !== JSON.stringify(currentOptions)) {
        setCurrentOptions(props.options);
    }

    return (
        <HighchartsReact
            highcharts={Highcharts}
            options={currentOptions}
            immutable={true}
        />
    );
});

我想在React Highcharts中用Jest测试plotOptions上的点击。这是从Jest得到的HTML页面:

<div>
    <div
      data-highcharts-chart="1"
      style="overflow: hidden;"
    >
      <div
        class="highcharts-container "
        dir="ltr"
        id="highcharts-r3a94y8-149"
        style="position: relative; overflow: hidden; width: 600px; height: 400px; text-align: left; line-height: normal; z-index: 0; user-select: none; outline: none;"
      >
        <svg
          class="highcharts-root"
          height="400"
          style="font-family: \"Lucida Grande\", \"Lucida Sans Unicode\", Arial, Helvetica, sans-serif; font-size: 12px;"
          version="1.1"
          viewBox="0 0 600 400"
          width="600"
          xmlns="http://www.w3.org/2000/svg"
        >
          <desc>
            Created with Highcharts 10.1.0
          </desc>
          <defs>
            <clippath
              id="highcharts-r3a94y8-151-"
            >
              <rect
                fill="none"
                height="375"
                width="580"
                x="0"
                y="0"
              />
            </clippath>
          </defs>
          <rect
            class="highcharts-background"
            fill="#ffffff"
            height="400"
            rx="0"
            ry="0"
            width="600"
            x="0"
            y="0"
          />
          <rect
            class="highcharts-plot-background"
            fill="none"
            height="375"
            width="580"
            x="10"
            y="10"
          />
          <rect
            class="highcharts-plot-border"
            data-z-index="1"
            fill="none"
            height="375"
            width="580"
            x="10"
            y="10"
          />
          <g
            class="highcharts-series-group"
            data-z-index="3"
          >
            <g
              class="highcharts-series highcharts-series-0 highcharts-pie-series highcharts-tracker"
              data-z-index="0.1"
              opacity="1"
              style="cursor: pointer;"
              transform="translate(10,10) scale(1 1)"
            >
              <path
                class="highcharts-point highcharts-color-0"
                d="M 290 175 A 0 0 0 0 1 290 175 L 290 175 A 0 0 0 0 0 290 175 Z"
                fill="#7cb5ec"
                opacity="1"
                stroke="#ffffff"
                stroke-linejoin="round"
                stroke-width="1"
                transform="translate(0,0)"
              />
            </g>
            <g
              class="highcharts-markers highcharts-series-0 highcharts-pie-series"
              data-z-index="0.1"
              opacity="1"
              transform="translate(10,10) scale(1 1)"
            />
          </g>
          <text
            class="highcharts-title"
            data-z-index="4"
            style="color: rgb(51, 51, 51); font-size: 18px; fill: #333333;"
            text-anchor="middle"
            x="300"
            y="24"
          >
            Utenti per azienda
          </text>
          <text
            class="highcharts-subtitle"
            data-z-index="4"
            style="color: rgb(102, 102, 102); fill: #666666;"
            text-anchor="middle"
            x="300"
            y="10"
          />
          <text
            class="highcharts-caption"
            data-z-index="4"
            style="color: rgb(102, 102, 102); fill: #666666;"
            text-anchor="start"
            x="10"
            y="397"
          />
          <g
            class="highcharts-data-labels highcharts-series-0 highcharts-pie-series highcharts-tracker"
            data-z-index="6"
            opacity="0"
            style="cursor: pointer;"
            transform="translate(10,10) scale(1 1)"
          >
            <path
              class="highcharts-data-label-connector highcharts-color-0"
              d="M 295 370 C 290 370 290 352 290 346 L 290 340"
              fill="none"
              stroke="#7cb5ec"
              stroke-width="1"
            />
            <g
              class="highcharts-label highcharts-data-label highcharts-data-label-color-0"
              data-z-index="1"
              style="cursor: pointer;"
              transform="translate(300,360)"
            >
              <text
                data-z-index="1"
                style="color: rgb(0, 0, 0); font-size: 11px; font-weight: bold; fill: #000000;"
                x="5"
                y="16"
              >
                <tspan
                  style="font-weight: bold;"
                >
                  acme
                </tspan>
                : 100.0 %
              </text>
            </g>
          </g>
          <g
            class="highcharts-legend highcharts-no-tooltip"
            data-z-index="7"
          >
            <rect
              class="highcharts-legend-box"
              fill="none"
              height="8"
              rx="0"
              ry="0"
              visibility="hidden"
              width="8"
              x="0"
              y="0"
            />
            <g
              data-z-index="1"
            >
              <g />
            </g>
          </g>
          <text
            class="highcharts-credits"
            data-z-index="8"
            style="cursor: pointer; color: rgb(153, 153, 153); font-size: 9px; fill: #999999;"
            text-anchor="end"
            x="590"
            y="395"
          >
            Highcharts.com
          </text>
        </svg>
      </div>
    </div>
  </div>
  • 我想获取g元素并单击它
render(<BrowserRouter><DashboardPage store={store} /></BrowserRouter>);
        const company = screen.getAllByRole('g');

但我得到了:

TestingLibraryElementError: Unable to find an accessible element with the role "g"

    There are no accessible roles. But there might be some inaccessible roles. If you wish to access them, then set the `hidden` option to `true`. Learn more about this here: https://testing-library.com/docs/dom-testing-library/api-queries#byrole
  • 我尝试通过类名获取元素:
it('Can handle handleOnUserClick on Chart', async () => {

    let initialState = {
        stats: {
            items: {
                nUsersPerCompany: [
                    {
                        company: "demolitori", 
                        qty: 5, 
                        id: 16
                    }
                ]
            }
        },
        setCompanyIdInUsersStore: () => {},
    };

    let store = mockStore(initialState);

    const { container } = render(<BrowserRouter><DashboardPage store={store} /></BrowserRouter>);
    // This console.log outputs the previous HTML code
    console.log(prettyDOM(container));
    const company = await container.getElementsByClassName("highcharts-label");
    console.log(company);
    fireEvent.click(company);

});

但是对于上一个console.log(company),我得到了一个空的HTML集合:

HTMLCollection {}

我也试着删除async/await模式,但没有运气。
我试着用途:

const {container} = render(<BrowserRouter><DashboardPage store={store} /></BrowserRouter>);
console.log(prettyDOM(container))
const path = container.getElementsByClassName("highcharts-color-0");
console.log(prettyDOM(path[0]))
fireEvent.click(path[0]);

测试本身工作,但覆盖率抱怨缺少点击e中的箭头功能

point: {
    events: {
        click: (e) => {
            props.setCompanyIdInUsersStore(e.target.point.idCompany);
            return navigate(PATH_USERS);
        }
    }
}
8nuwlpux

8nuwlpux1#

覆盖率统计信息是正确的,因为Highcharts使用SVG和其他组件呈现元素(path、rect等),它们不支持通过DOM模拟单击事件。如果您用mouseOver替换click,您的测试覆盖率将达到100%,Highcharts团队可能正在做一些自定义实现来实现点击处理程序,我们需要利用它来解决您的用例。@波塔切克指出了正确的做法。
代码修改:

  • 假设DashboardPage组件接受可选属性onAfterChartCreated.
  • 它将该属性作为回调的值传递给图表组件。
import { useState, useEffect, useRef } from "react";
import {useNavigate} from 'react-router-dom';
import Chart from "./Chart";
import {connect} from 'react-redux';

export const DashboardPage = (props) => {

    // previous code
    return (
        <Chart options={optionNUsersPerCompany} callback={props.onAfterChartCreated} />
    )
}

// follow up code

export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage);
  • 图表组件应修改为:
import React, { useState } from "react";

import HighchartsReact from "highcharts-react-official";
import Highcharts from 'highcharts';

export default React.memo(function Chart(props) {

    const [currentOptions, setCurrentOptions] = useState({});

    /**
     * Questo controllo serve a non re-draware per due volte di seguito i containers
     */
    if (JSON.stringify(props.options) !== JSON.stringify(currentOptions)) {
        setCurrentOptions(props.options);
    }

    return (
        <HighchartsReact
            highcharts={Highcharts}
            options={currentOptions}
            immutable={true}
            callback={props.callback}
        />
    );
});

callback是HighCharts react wrapper上的一个属性,它在呈现图表时执行,并返回图表的示例。
现在我们修改DashboardPage组件的测试用例,如下所示:

const afterChartCreatedCallback = (chart) => {
  // We can now trigger click on any data point using Highcharts API
  chart.series[0].data[0].firePointEvent('click');
}

render(<DashboardPage onAfterChartCreated={afterChartCreatedCallback} />);

因此,我们在测试中只使用回调函数来提高覆盖率。这应该会将DashboardPage组件的覆盖率提高到100%。

相关问题