我的项目是采用react + ts来写的,项目中要写单元测试,于是采用了Jest库, 主要用的package有
react-test-renderer react-test-renderer/shallow @jest/globals
这里展示shallow的用法,主要用来测导航栏组件

1 import {createRenderer} from "react-test-renderer/shallow"; 2 import {afterEach, beforeEach, describe, expect, it} from "@jest/globals"; 3 import * as React from "react"; 4 5 6 describe("render element", () => { 7 //创建renderer 8 const wrapper = createRenderer(); 9 let elements: JSX.Element; 10 let leftEle: JSX.Element; 11 let linkContainerEle: JSX.Element; 12 beforeEach(() => { 13 //浅渲染组件 14 wrapper.render(renderFrame()); 15 16 //获取到最外层的某个元素 17 elements = wrapper.getRenderOutput(); 18 19 20 21 //get element 22 leftEle = elements.props.children[0]; 23 24 25 26 //get element 27 linkContainerEle = elements.props.children[1]; 28 }); 29 30 31 32 afterEach(() => { 33 wrapper.unmount(); 34 }); 35 36 37 //这里是测渲染,(Link的to属性) 38 it("the link of logo icon connect to 'testNav'", () => { 39 //get element 40 const logoIconEle = leftEle.props.children[0]; 41 expect(logoIconEle.props.to).toBe("testNav"); 42 }); 43 44 // 这里测事件---这个方法可行,但是原理我不是很明白 45 it("when click 'icon', hidden/display box", () => { 46 // mock event 47 const event: {nativeEvent: {stopImmediatePropagation: () => void}} = { 48 nativeEvent: { 49 stopImmediatePropagation: () => { 50 // do nothing 51 }, 52 }, 53 }; 54 // simulate user action, click icon 55 //不直接找到icon元素,调用它的点击事件,而是找到点击事件对应的函数,直接调这个函数 56 wrapper.getMountedInstance()["changeShowBox"](event); 57 58 59 60 // so state showBox become true 61 expect(wrapper.getMountedInstance()["state"]["showBox"]).toBeTruthy; 62 }); 63 64 65 66 67 });
上述两个方法只能说可行,具体的用法可能不太正确
下面展示react-test-renderer测导航栏组件的用法(个人比较推荐)
1 describe("TopNavigationBar - lineFilter", () => { 2 //渲染导航栏父组件 3 const renderFrames = (lineFilterArr?: string[]) => ( 4 <HashRouter> 5 <TopNavigationBar 6 routePath={routePath} 7 history={history} 8 location={location} 9 match={match} 10 lineFilters={lineFilterArr ? lineFilterArr : ["line1", "line2"]} 11 /> 12 </HashRouter> 13 ); 14 15 let newFrame: ReactTestRenderer; 16 let topNavComponent: ReactTestInstance; 17 beforeEach(() => { 18 //调用渲染方法 19 newFrame = create(renderFrames()); 20 // 找到导航栏组件 21 topNavComponent = newFrame.root.findByType(TopNavigationBar); 22 }); 23 afterEach(() => { 24 newFrame.unmount(); 25 }); 26 27 it("render state 'lineFilter'", () => { 28 //找到state中对应的值 29 const stateLineFilters = topNavComponent.instance.state.lineFilters; 30 const received: ILineFilter[] = [ 31 { 32 text: "line1", 33 selected: false, 34 }, 35 { 36 text: "line2", 37 selected: false, 38 }, 39 ]; 40 // render state lineFilter 41 expect(JSON.stringify(stateLineFilters)).toEqual(JSON.stringify(received)); 42 }); 43 44 it("when select on item, change state 'lineFilter'", () => { 45 // simulate select one item 46 const selectedLine: ILineFilter = { 47 text: "line1", 48 selected: false, 49 }; 50 //找到该元素,调用元素绑定的onClick方法 51 topNavComponent.findAllByProps({className: "tes-topNavBar-line"})[0].props.onClick(selectedLine); 52 53 const lineFilterArr: ILineFilter[] = topNavComponent.instance.state.lineFilters; 54 lineFilterArr.forEach((e) => { 55 // so this item 'selected' property changed 56 if (e.text === selectedLine.text) expect(e.selected).toBeTruthy; 57 }); 58 }); 59 60 it("when props 'lineFilters' changed, change state 'lineFilters'", () => { 61 // 修改父级传入的API lineFilters 62 newFrame.update(renderFrames(["11", "22"])); 63 const topNav = newFrame.root.findByType(TopNavigationBar); 64 const stateLineFilters = topNav.instance.state.lineFilters; 65 const receivedArr: ILineFilter[] = [ 66 { 67 text: "11", 68 selected: false, 69 }, 70 { 71 text: "22", 72 selected: false, 73 }, 74 ]; 75 //测试state,渲染对应的值 76 expect(JSON.stringify(stateLineFilters)).toEqual(JSON.stringify(receivedArr)); 77 }); 78 });