这是我的 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);
这是简单的 Highchart 组件:
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); } } }
最佳答案
覆盖率统计数据是正确的,因为 Highcharts 使用 SVG 和其他不支持 DOM 模拟点击事件的组件(路径、矩形等)渲染元素。如果您用 mouseOver 替换 click,您的测试覆盖率将达到 100%,因为它是受支持的。 Highcharts 团队可能会进行一些自定义实现来实现点击处理程序,我们需要利用它来解决您的用例。 @ppotaczek 指出了正确的做法。
代码修改:
- 假设 DashboardPage 组件接受可选属性 onAfterChartCreated。
- 它将该属性作为回调值传递给 Chart 组件。
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}
/>
);
});
回调是 HighCharts react 包装器上的一个 Prop ,它在渲染图表时执行并返回图表的实例。您可以引用他们的文档以获取更多信息或查看 How do i access highcharts api after component renders?
现在我们修改 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%。
关于javascript - 如何模拟 Highchart 上的点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72576640/