简体   繁体   English

等待 fetch() 解决使用 Jest 进行 React 测试?

[英]Wait for fetch() to resolve using Jest for React test?

In my componentDidMount of a React.Component instance I have a fetch() call that on response calls setState .在我的React.Component实例的componentDidMount中,我有一个fetch()调用,响应调用setState

I can mock out the request and respond using sinon but I don't know when fetch will have resolved it's promise chain.我可以模拟请求并使用sinon进行响应,但我不知道 fetch 何时会解决它的承诺链。

componentDidMount() {
  fetch(new Request('/blah'))
    .then((response) => {
      setState(() => {
        return newState;
      };
    });
}

In my test using jest with enzyme :在我用enzyme jest的测试中:

it('has new behaviour from result of set state', () => {
  let component = mount(<Component />);

  requests.pop().respond(200);

  component.update() // fetch() has not responded yet and
                     // thus setState has not been called yet
                     // so does nothing

  assertNewBehaviour(); // fails

  // now setState occurs after fetch() responds sometime after
});

Do I need to flush the Promise queue/callback queue or something similar?我是否需要刷新 Promise 队列/回调队列或类似的东西? I could do a repeated check for newBehaviour with a timeout but that's less than ideal.我可以在超时的情况下重复检查 newBehaviour ,但这并不理想。

The best answer it seems is to be use a container pattern and pass down the API data from a container class with separated concerns and test the components separately.最好的答案似乎是使用容器模式并从具有分离关注点的容器类中传递 API 数据并分别测试组件。 This allows the component under test to simply take the API data as props and makes it much more testable.这允许被测组件简单地将 API 数据作为 props 并使其更易于测试。

Since you're not making any real api calls or other time-consuming operations, the asynchronous operation will resolve in a predictably short time.由于您没有进行任何真正的 api 调用或其他耗时的操作,因此异步操作将在可预见的短时间内解决。

You can therefore simply wait a while.因此,您只需稍等片刻即可。

it('has new behaviour from result of set state', (done) => {
  let component = mount(<Component />);
  requests.pop().respond(200);

  setTimeout(() => {
    try {
      component.update();
      assertNewBehaviour();
      done();
    } catch (error) {
      done(error);
    }
  }, 1000);
});

The react testing library has a waitFor function that works perfectly for this case scenario. react 测试库有一个waitFor函数,非常适合这种情况。

I will give an example with hooks and function as that is the current react pattern.我将举一个带有钩子和函数的例子,因为那是当前的反应模式。 Lets say you have a component similar to this one:假设您有一个类似于此的组件:

export function TestingComponent(props: Props) {
    const [banners, setBanners] = useState<MyType>([]);

    React.useEffect(() => {
        const response = await get("/...");
        setBanners(response.banners);
    }, []);

    return (
        {banners.length > 0 ? <Component> : </NoComponent>}
    );
}


Now you can write a test like this to make sure that when banners are set Component is rendered现在您可以编写这样的测试来确保在设置横幅时渲染Component

test("when the banner matches the url it renders", async () => {
        const {container} = render(<TestingComponent />);
        await waitFor(() => {expect(...).toBe(...)});
    });

waitFor will wait for the condition in the function to be met before proceeding. waitFor将等待函数中的条件满足,然后再继续。 There is a timeout that will fail the test if the condition is not met in X time.如果在 X 时间内不满足条件,则会有超时导致测试失败。 Check out the react testing library docs for more info 查看反应测试库文档以获取更多信息

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM