使用官方推荐的库来测react hook组件

最近写单元测试的时候遇见了一些问题,当我使用使用jest测React. useRef,  React. useEffect时,总是测不到,

然后我去查阅了一下官方文档,它推荐了使用下面这个库

@testing-library/react

我来试了哈,还是不得行,于是根据这个库我在npm里头找到了相关的库,就是下面这个,专门用来测Hook的   @testing-library/react-hooks

 
下面开始示范我的用法,如有不对请稍加修改
这是我的组件BarChart
注意: handleSortByReject 是一个处理函数,我没有把代码贴出来,可以忽略掉这个方法
( 节省时间小tips ,主要关注63-75行的内容,目的是测React.useRef和React.useEffect )
 
  1 import * as React from "react";
  2 import {Chart} from "react-chartjs-2";
  3 import {Chart as ChartJS, Title, Tooltip, Legend, CategoryScale, BarController, BarElement} from "chart.js";
  4 import {IChartDataList} from "./IChartDataList";
  5 import {ILinkPosition} from "./common";
  6 import {ILink} from "./ILink";
  7 import {IDatasetWithDetectionId} from "./IDatasetWithDetectionId";
  8 import {ItemWithLoading} from "./ItemWithLoading";
  9 
 10 // Register the elements to display ChartJs. Enables tree-shaking reducing bundle size.
 11 // See https://www.chartjs.org/docs/latest/getting-started/integration.html#bundlers-webpack-rollup-etc
 12 ChartJS.register(Title, Tooltip, Legend, CategoryScale, BarController, BarElement);
 13 
 14 export interface ISum {
 15   subscript: number;
 16   totalReject: number[];
 17   label: string;
 18   sumOfTotalReject?: number;
 19 }
 20 
 21 export interface IBarChartProps {
 22   /** The state of showing loading icon while sending request */
 23   showLoading: boolean;
 24   /** height of chart */
 25   chartHeight: number;
 26   /** current bar data */
 27   itemData: IChartDataList;
 28   /** sort data by label or total reject, if true, sort by total reject */
 29   sortByReject: boolean;
 30 }
 31 
 32 export const BarChart: React.FC<IBarChartProps> = (props: IBarChartProps) => {
 33   const chartRef = React.useRef<ChartJS>(null);
 34 
 35   /**
 36    * @returns options property or bar chart
 37    */
 38   const getOptionBarChart = (titleKey?: string) => {
 39     return {
 40       maintainAspectRatio: false,
 41       scales: {
 42         x: {
 43           stacked: true,
 44         },
 45         y: {
 46           stacked: true,
 47         },
 48       },
 49       plugins: {
 50         title: {
 51           display: true,
 52           text: titleKey,
 53         },
 54       },
 55     };
 56   };
 57 
 58   /**
 59    * use official function to update chart, more detail you can see
 60    * 1. [update.html](https://www.chartjs.org/docs/latest/developers/updates.html)
 61    * 2. [chartRef-demo](https://react-chartjs-2.netlify.app/examples/chart-ref/)
 62    */
 63   const updateChartData = (chart) => {
 64     if (chart.data !== null && chart.data !== undefined) {
 65       chart = handleSortByReject(chart);
 66       chart.update();
 67     }
 68   };
 69 
 70   React.useEffect(() => {
 71     const chart = chartRef.current;
 72     if (chart !== null) {
 73       updateChartData(chart);
 74     }
 75   }, [props.sortByReject, props.itemData.chartData.labels, props.showLoading, props.chartHeight]);
 76 
 77   return (
 78     <>
 79       {/* * before get response of backend, show loading
 80        * if backend return empty list, show 'no data'
 81        * otherwise, render bar chart */}
 82       <ItemWithLoading
 83         height={props.chartHeight}
 84         showLoading={props.showLoading}
 85         ele={
 86           props.itemData.chartData !== undefined &&
 87           props.itemData.chartData.labels &&
 88           props.itemData.chartData.labels.length !== 0 &&
 89           props.itemData.chartData.datasets.length !== 0 && (
 90             /** about ref of bar chart, more detail you can see
 91              * [chartRef-demo](https://react-chartjs-2.netlify.app/examples/chart-ref/)
 92              */
 93             <Chart
 94               type="bar"
 95               ref={chartRef}
 96               height={props.chartHeight}
 97               data={props.itemData.chartData}
 98               options={getOptionBarChart(props.itemData.titleKey)}
 99             />
100           )
101         }
102       />
103     </>
104   );
105 };
BarChart

这是我的组件ItemWithLoading

注意:(节省时间小tips, 可以不关注这个组件)

 1 import * as React from "react";
 2 import {AppContext} from "../app/IAppContext";
 3 import {Loading} from "../app/Loading";
 4 import "../public/style/datalight/ItemWithLoading.scss";
 5 
 6 export interface IItemWithLoadingProps {
 7   height: number;
 8   /** if true, show loading icon */
 9   showLoading: boolean;
10   ele?: JSX.Element | boolean;
11 }
12 
13 /** render no data */
14 export const ItemWithLoading: React.FC<IItemWithLoadingProps> = (props: IItemWithLoadingProps) => (
15   // before render element, show loading
16   <AppContext.Consumer>
17     {(ctx) =>
18       props.showLoading ? (
19         <Loading />
20       ) : props.ele ? (
21         props.ele
22       ) : (
23         //  if ele not available, show 'no data'
24         <div className="tes-datalight-noData" style={{height: props.height}}>
25           {ctx.translator.translate("tes_fe_gallery_filter_nodata")}
26         </div>
27       )
28     }
29   </AppContext.Consumer>
30 );
View Code

 

这是测试

注意: 前面三个测试采用了react-test-renderer库的create方法来测渲染
第四个测试采用了renderHook方法来测update方法有没有被调用,配合jest.spyOn和jest.fn方法
(节省时间小tips, 主要关注第四个测试 )

 

 

 1 import * as React from "react";
 2 import * as TypeMoq from "typemoq";
 3 import {describe, expect, it, jest} from "@jest/globals";
 4 import {ActiveElement, ChartEvent} from "chart.js";
 5 import {hotChartData, hotData, mcalMultiChartData, mxChartData, mxData} from "./panel2MockData";
 6 import {create} from "react-test-renderer";
 7 import {IChartDataList} from "../../datalight/IChartDataList";
 8 import {ILinkPosition} from "../../datalight/common";
 9 import {ILink} from "../../datalight/ILink";
10 import {BarChart, IBarChartProps} from "../../datalight/BarChart";
11 import {ItemWithLoading} from "../../datalight/ItemWithLoading";
12 import {Chart} from "react-chartjs-2";
13 import {renderHook} from "@testing-library/react-hooks";
14 
15 // define props of bar chart
16 const barChartProps: IBarChartProps = {
17   showLoading: true,
18   chartHeight: 300,
19   itemData: mxData,
20   sortByReject: true,
21 };
22 
23 /**
24  *
25  * @param height height of chart
26  * @param sortByReject true means sort by total reject. false means sort by label
27  * @returns render component with given property
28  */
29 const renderFrame = (height?: number, sortByReject = false, chartData?: IChartDataList, showLoading = false) => (
30   <BarChart
31     showLoading={showLoading ? showLoading : false}
32     chartHeight={height ? height : 320}
33     itemData={chartData ? chartData : hotData}
34     sortByReject={sortByReject}
35   />
36 );
37 
38 describe("render bar chart", () => {
39   it("bar height depend on props 'chartHeight'", () => {
40     const chartHeight = 200;
41     const wrappers = create(renderFrame(chartHeight, false));
42     expect(wrappers.root.findByType(ItemWithLoading).props.height).toBe(chartHeight);
43     wrappers.unmount();
44   });
45 
46   it("bar showLoading depend on props 'showLoading'", () => {
47     // render component with property 'showLoading' as true
48     const wrapper = create(renderFrame(undefined, undefined, undefined, true));
49     expect(wrapper.root.findByType(ItemWithLoading).props.showLoading).toBeTruthy();
50     wrapper.unmount();
51   });
52 
53   it("when props data is empty", () => {
54     const emptyData: IChartDataList = {
55       titleKey: "empty list",
56       detectionArr: [],
57       chartData: {labels: [], datasets: []},
58     };
59     // render component with empty data
60     const frame = create(renderFrame(undefined, undefined, emptyData));
61     expect(frame.root.findByType(ItemWithLoading).props.ele).toBeFalsy();
62     frame.unmount();
63   });
64 
65 
66   it("when props 'sortByReject' is false, test render hot chart", () => {
67     const newRef = {
68       current: {
69         update: jest.fn(),
70         // hot data has one items
71         data: hotChartData,
72       },
73     };
74     jest.spyOn(React, "useRef").mockReturnValueOnce(newRef);
75     /** render hooks
76      * more detail you can see [react-hooks-testing](https://react-hooks-testing-library.com/)
77      */
78     renderHook(() => BarChart(barChartProps));
79     expect(newRef.current.update).toHaveBeenCalledTimes(1);
80   });
81 });
BarChart.test.tsx

 

 

 

 

posted @ 2021-12-07 11:12  芋圆小宝  阅读(296)  评论(0)    收藏  举报