Reactjs 使用测试库和jest的React组件引发的测试错误

Reactjs 使用测试库和jest的React组件引发的测试错误,reactjs,jestjs,react-testing-library,react-context,Reactjs,Jestjs,React Testing Library,React Context,按照本文解释的Kent C Dodds的提供者模式,我有一个上下文提供者组件和一个钩子来使用该上下文 钩子防止在提供者之外使用它 export function useUser() { const { user } = useContext(UserContext) || {}; const { switchUser } = useContext(SwitchUserContext) || {}; if (!user || !switchUser) { throw new E

按照本文解释的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>
    </>
  );
}
函数TestComponent(){
const{user,switchUser}=useUser();
返回(
用户:{User.name}

交换机用户 ); }
我这样测试它

  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;
  });
test('未包装在'UserProvider'中时应引发错误,()=>{
const err=console.error;
console.error=jest.fn();
让actualErrorMsg;
试一试{
render();
}捕获(e){
actualErrorMsg=e.message;
}
const expectedErrorMsg='不能在'UserProvider'之外使用'useUser';
expect(actualErrorMsg).toEqual(expectedErrorMsg);
console.error=err;
});
我目前必须模拟控制台。错误,然后在测试结束时将其设置为原始值。它起作用了。但我想让它更具声明性,更简单。有一个好的模式来实现它吗? 有什么用的吗

我对此有一个解释,上面的代码可以在
UserContext.js
UserContext.test.js
中找到


注意:测试可以在codesandbox自身的
测试选项卡下运行。

您可以这样做

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);
});
test('未包装在'UserProvider'中时应引发错误,()=>{
component.useUser=jest.fn().mockRejectedValue(新错误('不能在'UserProvider'之外使用'useUser');
让actualErrorMsg;
试一试{
render();
}捕获(e){
actualErrorMsg=e.message;
}
const expectedErrorMsg='不能在'UserProvider'之外使用'useUser';
expect(actualErrorMsg).toEqual(expectedErrorMsg);
});

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

因此,在你的情况下:

test(“未包装在`UserProvider`'中时应引发错误,()=>{
预期(()=>render())
.toThrow(“不能在`UserProvider`之外使用`useUser`”);
});
关于
控制台。错误
: 目前,按照设计,无法关闭默认错误日志。 如果要隐藏错误,仍然需要模拟
控制台.error


当您模拟诸如
console.error
之类的函数时,您希望在每次
回调后在
中还原它们,以便在测试失败时也还原它们。

这似乎不起作用。我得到
Error:Uncaught[错误:无法在
UserProvider
]之外使用
useUser`给你:)你是对的,测试确实通过了:)仍然记录了一个未捕获的错误。试一试不管用。没有办法捕捉测试中的错误吗?
expect(fn).toThrow()捕捉错误。但是在您捕获它之前,它已经被jsdom记录到测试环境中的控制台中。我能够通过如下方式模拟它来抑制console.log错误:
const consoleErrorFn=jest.spyOn(console,'error').mockImplementation(()=>jest.fn())如果你沿着那条路走,别忘了开玩笑。restoreMocks()
。不确定这里有什么组件?