使用Enzyme测试`React.createRef` API

7
我想测试以下类,该类使用React.createRef api。
快速搜索没有显示任何这样的示例。有人成功过吗?我该如何模拟引用?
理想情况下,我想使用shallow
class Main extends React.Component<Props, State> {

  constructor(props) {
    super(props);
    this.state = {
      contentY: 0,
    };

    this.domRef = React.createRef();
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
    handleScroll();
  }

  componentWillUnmount() {
   window.removeEventListener('scroll', this.handleScroll);
  }

  handleScroll = () => {
    const el = this.domRef.current;
    const contentY = el.offsetTop;
    this.setState({ contentY });
  };

  render() {
    return (
      <Wrapper innerRef={this.domRef}>
        <MainRender contentY={this.state.contentY} {...this.props} />
      </Wrapper>
    );
  }
}

更新

我可以使用回调引用来测试这个,具体如下:

 setRef = (ref) => {
   this.domRef = ref;
 }

 handleScroll = () => {
   const el = this.domRef;
   if (el) {
     const contentY = el.offsetTop;
     this.setState({ contentY });
   }
 };

 render() {
   return (
     <Wrapper ref={this.setRef}>
       <MainRender contentY={this.state.contentY} {...this.props} />
     </Wrapper>
   );
 }
}

那么测试类似于

it("adds an event listener and sets currentY to offsetTop", () => {
    window.addEventListener = jest.fn();
    const component = shallow(<ScrollLis />)
    const mockRef = { offsetTop: 100 };
    component.instance().setRef(mockRef);
    component.instance().componentDidMount();
    expect(window.addEventListener).toBeCalled();
    component.update();
    const mainRender = component.find(MainRender);
    expect(mainRender.props().contentY).toBe(mockRef.offsetTop);
  }); 

1个回答

8

没有特定的测试参考文献的例程。引用只是具有current键的对象。

如果在 componentDidMount 中早期访问它,生命周期挂钩需要禁用进行测试。应该测试组件最初是否有引用,然后可以模拟。

const wrapper = shallow(<Comp/>, { disableLifecycleMethods: true });
expect(wrapper.instance().domRef).toEqual({ current: null });
wrapper.instance().domRef.current = mockRef;
wrapper.instance().componentDidMount();

由于 ref 作为 prop 传递给另一个组件,因此可以测试它是否提供了正确的 ref:

expect(wrapper.find(Wrapper).dive().props().innerRef).toBe(wrapper.instance().domRef);

然后在Wrapper测试中,可以测试ref current键是否被分配了正确的对象。

我的意思是Wrapper被测试,就像这样:const ref = { current: null }; const wrapperWrapper = shallow(<Wrapper innerRef={ref}; expect(ref.current).toBe(wrapperWrapper.instance())。我不确定offsetTop在哪里涉及到了。 - Estus Flask
React 确保在调用 handleScroll 时,this.domRef.current 引用 DOM 节点,因此可以访问其所有属性,其中我使用了 offsetTop。我想要的是如何模拟由 React.createRef() 设置的 DOM 节点。 - Tom
这个问题没有展示为什么会触发滚动事件。但是在单元测试中,DOM事件不应该被触发,特别是像滚动这样的全局事件。如果需要,可以使用Stub addEventListener和removeEventListener。无论如何,在handleScroll测试中,您需要使用一个具有offsetTop属性的对象来模拟ref。 - Estus Flask
我已经切换回回调 API,所以我可以手动调用回调函数。虽然这样可行,但我仍然想知道是否可能使用 React.createRef API 来实现这一点 :) - Tom
我不确定你的意思。React.createRef并没有什么神奇的地方。它只是以一种声明式的方式创建了一个{current: null}对象。如果您想使用真正的DOM引用,那么我建议不要在Enzyme单元测试中这样做。 - Estus Flask
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接