【问题标题】:Update not wrapped in act(...) and the mock function not firing. react-testing-library, jest更新未包含在 act(...) 中,并且模拟函数未触发。反应测试库,开玩笑
【发布时间】:2020-08-29 23:17:15
【问题描述】:

我希望得到一些帮助。我研究这个问题太久了,我认为我没有提出任何问题。

提前感谢您的时间和关注,

我已经在互联网上搜索并尝试了很多东西,但我仍然没有运气 - 这就是问题所在。

总而言之 - 我正在跟随 https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning

将 react-testing-library 与 jest 结合使用 - 并遇到两个问题

  1. Warning: An update to Login inside a test was not wrapped in act(...).
  2. Jest 没有意识到正在调用模拟

我真的认为我已经正确连接了所有东西 - 不确定我错过了什么。 在 mock 中我可以放置一个 console.log 并且可以确认 mock 确实被调用了。

/*
  Test
*/
it('should call props.fetchSignIn with the username and password', async () => {
  const promise = Promise.resolve({
    email: 'test@circulate.social',
    firstName: 'Mike',
    lastName: 'A',
  });
  const fetchSignIn = jest.fn(() => promise);
  const { queryByTestId, queryByPlaceholderText } = renderLogin({
    fetchSignIn,
  });
  const emailInput = queryByPlaceholderText('joedoe@gmail.com');
  const passwordInput = queryByPlaceholderText('password');
  const submitButton = queryByTestId('submitButton');

  fireEvent.change(emailInput, {
    target: { value: 'mike@circulate.social' },
  });
  fireEvent.change(passwordInput, { target: { value: 'Password1!' } });

  fireEvent.click(submitButton);

  // I expected this to fail from the parameters being wrong
  expect(fetchSignIn).toHaveBeenCalledWith('asf');

  await act(() => promise);
});
/*
  Functional Component using the `useState(...)` hooks
  onFormFinished is the form `onSubmit` handler
*/
  const handleSignIn = async (
    email: string,
    password: string
  ): Promise<UserContextType['user']> => {
    setIsLoginInFlight(true);
    try {
      const result = await props.fetchSignIn(email, password);
      setIsLoginInFlight(false);
      return result;
    } catch (error) {
      // Other logic removed
  };

  const onFormFinish = async (values: FormValues): Promise<void> => {
    const { email, password } = values;
    const signInResult = await handleSignIn(email, password);

    // Other logic removed
  };

有两件事正在发生 1 - 那个警告 2 - 测试失败,因为从未调用过 fetchSignIn

预期结果 调用fetchSignIn导致测试失败,但参数错误

欢迎任何意见或要求澄清。

谢谢

【问题讨论】:

标签: javascript reactjs unit-testing jestjs react-testing-library


【解决方案1】:

让我们先解决您的第二个问题。

Jest 没有意识到正在调用模拟

我发现使用 ant 设计表单进行测试也很棘手。经过一些挖掘和实验,似乎模拟“点击”不会触发 onFinish,而是模拟“提交”。使用 Jest 和 Enzyme 对以下示例进行成像:

export default MyForm = () => {
    <Form onFinish={onFinish}>
       <Form.Item>
         <Button htmlType='submit'>Submit</Button>
       </Form.Item>
    </Form>
}

it('should trigger onFinish if submit', () => {
   const onFinish = jest.fn();
   const wrapper = mount(<MyForm onFinish={onFinish}/>);
   wrapper.find('button').simulate('submit');
   await sleep(200)
   expect(onFinish).toHaveBeenCalled();
})

我自己也在为第一个问题苦苦挣扎:

警告:测试中登录的更新未包含在 act(...) 中

请注意,只有在出现验证错误时才会发生这种情况,因为它们的表单实现存在内部状态更改。

首先,这是一个警告,意思是如果你不介意日志被污染,可以忽略它。

其次,只有在“开发”而非“生产”时才发出警告。

如果你确实想让它消失,这就是我正在采取的“hacky”方式(我不知道是否有更好的方式):

it('should trigger onFinish if submit', () => {
   const onFinish = jest.fn();
   const wrapper = mount(<MyForm onFinish={onFinish}/>);
   await act(async () => {
     wrapper.find('button').simulate('submit');
   })
   await sleep(200)
   wrapper.update()
   // check errors here
   expect(onFinish).not.toHaveBeenCalled();
})

这在此处正式记录:https://github.com/enzymejs/enzyme

【讨论】:

    【解决方案2】:

    与喜剧接壤,绝对不是解决问题的正确方法。但是一种解决问题的方法 - 除了完全避免使用onFinish 并依赖按钮上的onClick 之外,唯一对我有用的方法。

    那么诀窍实际上是将expect(...) 包装在setTimeout(...)

          // click || submit - both seemed to work for me
          fireEvent.submit(submitButton);
          setTimeout(() => {
            expect(fetchSignIn).toHaveBeenCalledWith('asf');
          });
    
        it('should call props.fetchSignIn with the username and password', async () => {
          const promise = Promise.resolve({
            email: 'test@circulate.social',
            firstName: 'Mike',
            lastName: 'A',
          });
          const fetchSignIn = jest.fn(() => promise);
          const { queryByTestId, queryByPlaceholderText } = renderLogin({
            seedEmail: 'aasdf',
            seedPassword: 'asdf',
            fetchSignIn,
          });
          const emailInput = queryByPlaceholderText('joedoe@gmail.com');
          const passwordInput = queryByPlaceholderText('password');
          const submitButton = queryByTestId('submitButton');
    
          fireEvent.change(emailInput, {
            target: { value: 'mike@circulate.social' },
          });
          fireEvent.change(passwordInput, { target: { value: 'Password1!' } });
    
          // click || submit - both seemed to work for me
          fireEvent.submit(submitButton);
          setTimeout(() => {
            expect(fetchSignIn).toHaveBeenCalledWith('asf');
          });
    
          await act(() => promise);
        });
    

    这是有人在 GitHub 问题上向我提出的 https://github.com/ant-design/ant-design/issues/21272#issuecomment-628607141 所以在 GH 上向 @ildarnm 大喊

    【讨论】:

      【解决方案3】:

      我在使用 Ant Design 4 + react-testing-library 提交表单时也遇到了一些麻烦。经过一些实验后,我总是使用 data-testid 提交表单:

      <Button data-testid="submit" htmlType="submit">Submit</>
      
      // Form element has onFinish attribute
      
      // in test
      fireEvent.click(rtl.getByTestId("submit"));
      expect(...);
      

      这不是 RTL 所提倡的(应该避免使用 datat-testid,像真正的用户一样进行测试),但我可以接受。

      但是根据https://github.com/ant-design/ant-design/issues/21272 触发提交事件应该也可以,我一定会试一试。

      【讨论】:

      • 不幸的是,拥有submit 并没有为我解决问题。不过,我会回答这个问题,因为做了什么!
      猜你喜欢
      • 2021-01-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-25
      • 1970-01-01
      • 2021-05-22
      • 2021-06-16
      • 2021-09-12
      相关资源
      最近更新 更多