简体   繁体   English

如何为 React useEffect 中的代码编写 Jest-enzyme 测试用例,其依赖项在其子组件中更新

[英]How to write a Jest-enzyme test case for code in React useEffect whose dependencies are updated in its child component

I have a parent component for filtering functionality我有一个用于过滤功能的父组件

export const FilterComponent = ({data}) {
  const [priceRange, setPriceRange] = React.useState({});
  const [amenities, setAmenities] = React.useState([]);

  React.useEffect(() => {
    if (priceRange.min) {
      // code to filter based on priceRange
    }

    if(amenities.length) {
      // code to filter based on amenities
    },[priceRange, amenities])

  return (
          <select id="price" value={priceRange} onChange={(event) => setPriceRange(JSON.parse(event.target.value))}>
            <option value="">Price Per Night</option>
            <option value='{"min":0,"max":99}'>Less than $99</option>
            <option value='{"min":100,"max":299}'>$100 to $299</option>
            <option value='{"min":300,"max":499}'>$300 to $499</option>
            <option value='{"min":500}'>More than $500</option>
          </select>

    <MoreFiltersComponent setAmenities={setAmenities} amenities={amenities} />}
  )
}

I am using this parent component to display the filters like Price range and other filters that user can view on the screen and added test cases for them.我使用这个父组件来显示过滤器,比如价格范围和用户可以在屏幕上查看的其他过滤器,并为它们添加了测试用例。 I created a child component to this, MoreFiltersComponent, to display many other filters which user can view after clicking on More Filters button.我为此创建了一个子组件,MoreFiltersComponent,以显示许多其他过滤器,用户可以在单击“更多过滤器”按钮后查看这些过滤器。 amenities is part of MoreFilters but I created state for it in parent component and passing it as props so that I can run useEffect of parent component to check all the filters when there is any update.便利设施是 MoreFilters 的一部分,但我在父组件中为它创建了状态并将其作为道具传递,以便我可以在有任何更新时运行父组件的 useEffect 来检查所有过滤器。

export const MoreFiltersComponent = ({setAmenities, amenities}) => {

  const updateValue = (event, state, updateState) => {
   // code to update the state
  }
 
 return (
   <input type="checkbox" name="ac" id="ac" value="ac" onChange={(event) => updateValue(event, amenities, setAmenities)} />
 )
}

This is the test case I created to test the price range filter which is working fine这是我创建的测试用例,用于测试运行良好的价格范围过滤器

const setPriceRangeSpy = jest.fn();
const mockUseEffect = () => {
    useEffect.mockImplementationOnce((f) => f());
  };

it('should render the correct results for selected price range', () => {
    const event = {
      target: { value: '{"min": 0, "max": 99}' },
    };

    useStateSpy.mockImplementationOnce(() => [{}, setPriceRangeSpy]);
    renderedModule = shallow(<FilterComponent {...props} />);
    mockUseEffect();

    renderedModule.find('#price').simulate('change', event);
    
    expect(setPriceRangeSpy).toHaveBeenCalledWith({ min: 0, max: 99 });
    expect(renderedModule).toMatchSnapshot();
 }

I tried a similar test case for amenities but it doesn't work.我尝试了一个类似的便利设施测试用例,但它不起作用。 I can't simulate the onChange event as the element isn't in this component and so the lines of code in useEffect where I filter based on amenities are uncovered.我无法模拟 onChange 事件,因为该元素不在此组件中,因此 useEffect 中的代码行在我根据便利条件进行过滤的地方没有被发现。 is there a way I can cover those lines of code as well ?有没有办法我也可以覆盖这些代码行?

 const setAmenitiesSpy = jest.fn();
 const mockUseEffect = () => {
    useEffect.mockImplementationOnce((f) => f());
  };

 it('should render the correct results when there is no max price', () => {
   useStateSpy.mockImplementationOnce(() => [["ac", "tv", "wifi"], setAmenitiesSpy]);
   renderedModule = shallow(<FilterComponent {...props} />);
   mockUseEffect();

   expect(setAmenitiesSpy).toHaveBeenCalledWith(["ac", "tv", "wifi"]);

 }

I get this error for amenities test case:对于设施测试用例,我收到此错误:

Expected: ["ac", "tv", "wifi"]预期:[“交流”,“电视”,“无线网络”]

Number of calls: 0通话次数:0

I can't simulate the onChange event as the element isn't in this component and so the lines of code in useEffect where I filter based on amenities are uncovered.我无法模拟 onChange 事件,因为该元素不在此组件中,因此 useEffect 中的代码行在我根据便利条件进行过滤的地方没有被发现。 is there a way I can cover those lines of code as well ?有没有办法我也可以覆盖这些代码行?

Thanks!谢谢!

First, I think you better not mocking useState and useEffect .首先,我认为你最好不要嘲笑useStateuseEffect It's definitely implementation details and while you can technically do that you will - and you probably reached this point - make any change harder and harder to include in test.这绝对是实现细节,虽然您在技术上可以做到这一点 - 您可能已经达到了这一点 - 使任何更改越来越难以包含在测试中。 Not telling that if you for any reason ever decide to reshape your state(say, making some part of it coming from props or context instead) you will need to completely rewrite your tests.不告诉你,如果你出于任何原因决定重塑你的状态(比如,让它的一部分来自 props 或上下文),你将需要完全重写你的测试。 It's not good.这不好。

Second, since shallow() still does not work fine with useEffect .其次,因为shallow()仍然不能很好地useEffect一起useEffect So just use mount() .所以只需使用mount() Yes, it means you will have all nested components to be rendered in deep... until you explicitly mock them!是的,这意味着您将深入渲染所有嵌套组件……直到您明确模拟它们! See:看:

import { MoreFiltersComponent } from '../path/to/MoreFiltersComponent.jsx';

jest.mock('../path/to/MoreFiltersComponent.jsx', () => ({
 MoreFiltersComponent: function MoreFiltersComponent() {
  // so this is mocked React component that always returns null
   return null; 
 } 
}));

....
 const wrapper = mount(.....);
 // you still can search for this component, even if it's mocked and always returns null in render
 wrapper.find(MoreFiltersComponent) 

Also you most probably will need act() from react/test-utils .此外,您很可能需要react/test-utils act() Some enzyme's helpers like simulate() already call that while others maybe don't.一些酶的助手(如simulate()已经调用了它,而其他酶可能没有调用。 This method ensures all the related useEffect / useLayoutEffect will be run and run in sync way.此方法确保所有相关的useEffect / useLayoutEffect将以同步方式运行和运行。 Without act() you may find useEffect is executed after test has been completed that does not make any sense.如果没有act()您可能会发现测试完成执行useEffect没有任何意义。

Keeping all that in mind, we can test how FilterComponent works with MoreFiltersComponent (or more precisely with its mock):记住所有这些,我们可以测试FilterComponent如何与MoreFiltersComponent一起MoreFiltersComponent (或者更准确地说是与其模拟):

  const wrapper = mount(<FilterComponent data={mockedData} />);
  act(() => {
    wrapper.find(MoreFiltersComponent).invoke('setAmenities')(['a','b']);
  });

  expect(wrapper).toMatchSnapshot(); // should be only those matched filters

PS I cannot answer how you can solve that task with mocked useEffect and useState and shallow() PS 我无法回答你如何用useEffectuseState以及shallow()来解决这个任务

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在 JEST-Enzyme 中为 promise 在构造函数中调用编写测试用例 - Write test-case in JEST-Enzyme for promise calling in constructor 如何使用Jest和Enzyme为简单的React组件编写测试用例 - How to write a test case for a simple React component using Jest and Enzyme 玩笑和酶反应成分方法的测试案例 - test case for a react component method with jest and enzyme Jest React Enzyme测试用例 - Jest React Enzyme test case Jest/Enzyme Test 在 React 功能组件中将 Child prop 触发为 function - Jest/Enzyme Test firing Child prop as function in react functional component 如何为 componentDidMount() 编写单元测试用例并导出默认 connect(null, updateProps)(<componentname> ) 在 React 中使用 JEST/酶?</componentname> - How to write unit test case for componentDidMount() and export default connect(null, updateProps)(<ComponentName>) with JEST/Enzyme in React? 如何在Jest / Enzyme上测试子组件 - How can I test a child component on Jest/Enzyme 如何测试默认道具功能是否附加到组件? | 反应| Jest | 酶 - How to test default props functions is attached to component or not ? | React | Jest | Enzyme 如何使用Jest + Enzyme测试React组件的样式? - How can I test React component's style with Jest + Enzyme? 如何在 React with Jest(无酶)中测试功能组件的 state - How to test the state of a functional component in React with Jest (No Enzyme)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM