使用 testing-library 和 jest 测试 React 组件抛出的错误

时间:2021-02-23 07:05:26

标签: reactjs jestjs react-testing-library react-context

按照本 blog post 中解释的 Kent C Dodds 提供者模式,我有一个上下文提供者组件以及一个使用该上下文的钩子。

钩子防止在提供者之外使用它,

export function useUser() {
  const { user } = useContext(UserContext) || {};
  const { switchUser } = useContext(SwitchUserContext) || {};
  if (!user || !switchUser) {
    throw new Error('Cannot use `useUser` outside of `UserProvider`');
  }
  return { user, switchUser };
}

为了测试场景,我创建了一个 TestComponent 并在其中使用了 useUser 钩子。

function TestComponent() {
  const { user, switchUser } = useUser();
  return (
    <>
      <p>User: {user.name}</p>
      <button onClick={switchUser}>Switch user</button>
    </>
  );
}

我是这样测试的,

  test('should throw error when not wrapped inside `UserProvider`', () => {
    const err = console.error;
    console.error = jest.fn();
    let actualErrorMsg;
    try {
      render(<TestComponent />);
    } catch(e) {
      actualErrorMsg = e.message;
    }
    const expectedErrorMsg = 'Cannot use `useUser` outside of `UserProvider`';
    expect(actualErrorMsg).toEqual(expectedErrorMsg);

    console.error = err;
  });

我目前必须模拟 console.error,然后在测试结束时将其设置为其原始值。有用。但我想让它更具声明性和更简单。有没有好的模式来实现它? 可能使用 .toThrow() 的东西?

我有一个 codesandbox,上面的代码可以在 UserContext.jsUserContext.test.js 中找到。

注意:测试可以在 Tests 标签下的代码和框本身中运行。

2 个答案:

答案 0 :(得分:4)

正如您已经提到的,有 expect().toThrow() :)

所以在你的情况下:

  test("should throw error when not wrapped inside `UserProvider`", () => {
    expect(() => render(<TestComponent />))
      .toThrow("Cannot use `useUser` outside of `UserProvider`");
  });

关于 console.error: 目前,设计上无法关闭默认错误日志。 如果你想隐藏错误,你仍然需要模拟 console.error

当您模拟 console.error 等函数时,您希望在 afterEach 回调中恢复它们,以便在测试失败时也能恢复它们。

答案 1 :(得分:0)

你可以这样做

test('should throw error when not wrapped inside `UserProvider`', () => {
  component.useUser = jest.fn().mockRejectedValue(new Error('Cannot use `useUser` outside of `UserProvider`'));
  let actualErrorMsg;
  try {
    render(<TestComponent />);
  } catch(e) {
    actualErrorMsg = e.message;
  }
  const expectedErrorMsg = 'Cannot use `useUser` outside of `UserProvider`';
  expect(actualErrorMsg).toEqual(expectedErrorMsg);
});