Reactjs 如何编写一个单元测试来检查在单击某个链接后是否显示modal

Reactjs 如何编写一个单元测试来检查在单击某个链接后是否显示modal,reactjs,redux,jestjs,enzyme,Reactjs,Redux,Jestjs,Enzyme,我只是在学习Jest/酶的单元测试-专门针对React/Redux。 我正在尝试编写一个测试,从用户的角度(这是正确的方法吗?…)检查是否在单击某个链接后出现模态。 接下来,我想测试点击shadewrapper覆盖modal是否关闭modal 模式状态(打开/关闭)由Redux控制 基于Redux中的当前状态-modal获得适当的样式:modal或InvisibleModel 我曾试图通过模仿Redux商店来实现这一点,但我觉得应该在没有它的情况下实现——我认为测试未连接的组件会更好,但如果我错

我只是在学习Jest/酶的单元测试-专门针对React/Redux。 我正在尝试编写一个测试,从用户的角度(这是正确的方法吗?…)检查是否在单击某个链接后出现模态。 接下来,我想测试点击
shade
wrapper覆盖
modal
是否关闭
modal

模式状态(打开/关闭)由Redux控制

基于Redux中的当前状态-modal获得适当的样式:
modal
InvisibleModel

我曾试图通过模仿Redux商店来实现这一点,但我觉得应该在没有它的情况下实现——我认为测试未连接的组件会更好,但如果我错了,请纠正我

迄今为止的测试:

const mockFn = jest.fn();

describe('Contact components', ()=>{
    it('<ContactModal /> renders correctly', ()=>{
        shallow(<ContactModal />)
    })

    it('<ContactForm /> renders correctly', ()=>{
        shallow(<ContactForm toggleContactModal={mockFn} />)
    })

});

describe('In contact form link',()=>{
    const link = shallow(<ContactForm toggleContactModal={mockFn}/>)
    const modalWrapper = shallow(<ContactModal />);

    it('toggleContactModal function is called upon clicking ContactForm',()=>{
        expect(modalWrapper.find('#modal').hasClass('modal')).toBe(false);
        link.simulate('click');

        expect(mockFn.mock.calls.length).toBe(1);
    })
})
提前感谢。

来自Redux文档:

…有时您只想测试组件的呈现,而不需要Redux存储

为了能够在不必处理装饰程序的情况下测试应用程序组件本身,我们建议您也导出未装饰的组件

是的,导出未连接的组件并直接测试它是推荐的方法


对于您的组件,您只需要根据
contactModal
prop以及单击和按键处理程序测试UI更改

下面是一个稍微简化的工作示例,让您开始:

import * as React from 'react';
import { shallow } from 'enzyme';

const ContactModal = props => {
  return (
    <>
      <div
        id='modal'
        className={props.contactModal ? 'modal': 'invisibleModal'}
      >
        hello from modal
          </div>
      <div
        id='shade'
        className={props.contactModal ? 'shade' : 'invisibleShade'}
        onClick={props.toggleContactModal}
        onKeyDown={props.toggleContactModal}
      />
    </>
  );
};

describe('ContactModal', () => {
  it('should render as expected when contactModal is true', () => {
    const wrapper = shallow(<ContactModal contactModal={true} />);
    expect(wrapper.find('#modal').prop('className')).toBe('modal');  // Success!
    expect(wrapper.find('#shade').prop('className')).toBe('shade');  // Success!
  });
  it('should render as expected when contactModal is false', () => {
    const wrapper = shallow(<ContactModal contactModal={false} />);
    expect(wrapper.find('#modal').prop('className')).toBe('invisibleModal');  // Success!
    expect(wrapper.find('#shade').prop('className')).toBe('invisibleShade');  // Success!
  });
  it('should call props.toggleContactModal on click', () => {
    const spy = jest.fn();
    const wrapper = shallow(<ContactModal contactModal={true} toggleContactModal={spy} />);
    wrapper.find('#shade').prop('onClick')();
    expect(spy).toHaveBeenCalled();  // Success!
  });
  it('should call props.toggleContactModal on keydown', () => {
    const spy = jest.fn();
    const wrapper = shallow(<ContactModal contactModal={true} toggleContactModal={spy} />);
    wrapper.find('#shade').prop('onKeyDown')();
    expect(spy).toHaveBeenCalled();  // Success!
  });
});
import*as React from'React';
从“酶”导入{shall};
const ContactModal=props=>{
返回(
莫代尔你好
);
};
描述('ContactModal',()=>{
它('当contactModal为true时应按预期呈现',()=>{
常量包装器=浅();
expect(wrapper.find('#modal').prop('className')).toBe('modal');//成功!
expect(wrapper.find('#shade').prop('className')).toBe('shade');//成功!
});
它('当contactModal为false时应按预期呈现',()=>{
常量包装器=浅();
expect(wrapper.find('#modal').prop('className')).toBe('invisibleModal');//成功!
expect(wrapper.find('#shade').prop('className')).toBe('invisibleShade');//成功!
});
它('单击时应调用props.toggleContactModal',()=>{
const spy=jest.fn();
常量包装器=浅();
wrapper.find('#shade').prop('onClick')();
期待(间谍).tohavebeencall();//成功!
});
它('应该在按键时调用props.toggleContactModal',()=>{
const spy=jest.fn();
常量包装器=浅();
wrapper.find(“#shade”).prop('onKeyDown')();
期待(间谍).tohavebeencall();//成功!
});
});

我还建议您看看哪个可以让您使用.Awsome轻松直观地验证您的UI!它真的帮助了我。我尝试了一些方法,但仍然觉得测试对我来说并不完全直观。我还在努力。我将研究快照,但我只是认为在这种情况下它不起作用,因为UI的变化很大程度上取决于模式是否可见。我说的不对吗?我觉得我缺少了一些关于何时决定快照的信息。如果可见性由css样式控制(如
display:none
),它仍将存在于渲染输出中(即使它在浏览器中不可见),因此它也将显示在以
enzyme to json
@ErykLudwin序列化的快照中
export const contactModal = (state=false, action) => {
    switch (action.type){
        case TOGGLE_CONTACT_MODAL:
            return !state;
        default:
            return state
    }
}
import * as React from 'react';
import { shallow } from 'enzyme';

const ContactModal = props => {
  return (
    <>
      <div
        id='modal'
        className={props.contactModal ? 'modal': 'invisibleModal'}
      >
        hello from modal
          </div>
      <div
        id='shade'
        className={props.contactModal ? 'shade' : 'invisibleShade'}
        onClick={props.toggleContactModal}
        onKeyDown={props.toggleContactModal}
      />
    </>
  );
};

describe('ContactModal', () => {
  it('should render as expected when contactModal is true', () => {
    const wrapper = shallow(<ContactModal contactModal={true} />);
    expect(wrapper.find('#modal').prop('className')).toBe('modal');  // Success!
    expect(wrapper.find('#shade').prop('className')).toBe('shade');  // Success!
  });
  it('should render as expected when contactModal is false', () => {
    const wrapper = shallow(<ContactModal contactModal={false} />);
    expect(wrapper.find('#modal').prop('className')).toBe('invisibleModal');  // Success!
    expect(wrapper.find('#shade').prop('className')).toBe('invisibleShade');  // Success!
  });
  it('should call props.toggleContactModal on click', () => {
    const spy = jest.fn();
    const wrapper = shallow(<ContactModal contactModal={true} toggleContactModal={spy} />);
    wrapper.find('#shade').prop('onClick')();
    expect(spy).toHaveBeenCalled();  // Success!
  });
  it('should call props.toggleContactModal on keydown', () => {
    const spy = jest.fn();
    const wrapper = shallow(<ContactModal contactModal={true} toggleContactModal={spy} />);
    wrapper.find('#shade').prop('onKeyDown')();
    expect(spy).toHaveBeenCalled();  // Success!
  });
});