Skip to content

How to test useReducer dispatch that errors? #43

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ahnkee opened this issue Apr 17, 2019 · 6 comments
Closed

How to test useReducer dispatch that errors? #43

ahnkee opened this issue Apr 17, 2019 · 6 comments
Labels
question Further information is requested

Comments

@ahnkee
Copy link

ahnkee commented Apr 17, 2019

What is your question:

How can I test that a reducer dispatch results in an error?

The renderHook api returns a result object with an error key. The docs state that this is an error that is thrown if the callback function threw an error during rendering. I'm trying to test for an error from a subsequent dispatch, not from the initial renderHook call.

Dan Abrmaov suggests that with useReducer, the default switch case should throw an error: https://twitter.com/dan_abramov/status/1093969005675773954?lang=en

import { useReducer } from 'react';
import { act, renderHook } from 'react-hooks-testing-library';

const initialState = {};

function reducer(state, action) {
  switch (action.type) {
    default: 
      throw new Error('Unknown action type');
  }
}

test('throws an error when dispatched with an unknown action type', () => {
  expect.assertions(1);

  const { result } = renderHook(() => useReducer(reducer, initialState));
  const [, dispatch] = result.current;

  try {
    act(() => {
      dispatch({ type: 'whaaat' });
    });
  } catch (e) {
    // asserting here does not appear to be the right approach
  }
});

Would the best approach be to render the test by wrapping it in an ErrorBoundary type component and testing for the resulting render?

As it stands, I get the following reported, just not sure how to catch/handle it in my test.

Screen Shot 2019-04-17 at 9 37 10 AM
Screen Shot 2019-04-17 at 9 37 06 AM

@ahnkee ahnkee added the question Further information is requested label Apr 17, 2019
@mpeyper
Copy link
Member

mpeyper commented Apr 18, 2019

If it's catching in the ErrorBoundary, then try checking the result.error property.

test("throws an error when dispatched with an unknown action type", () => {
  expect.assertions(1);

  const { result } = renderHook(() => useReducer(reducer, initialState));
  const [, dispatch] = result.current;

  act(() => {
    dispatch({ type: "whaaat" });
  });

  expect(result.error).toEqual(Error("Unknown action type"));
});

Here is the test passing in a sandbox

@ahnkee
Copy link
Author

ahnkee commented Apr 18, 2019

Ah.. that makes sense, thank you for the help!

@ahnkee ahnkee closed this as completed Apr 18, 2019
@good-idea
Copy link

@mpeyper , is there a way to suppress the console.error message that's coming from ErrorBoundary?

This test is passing:

  it('should throw if the initialVariant does not exist', () => {
    const { result } = renderHook(() =>
      useProductVariant(dummyProduct, { initialVariant: '2' })
    );
    expect(result.error.message).toBe(
      'There is no variant with the id "2" on the product Dummy Product'
    );
  });

But I still see this in the console:

  console.error node_modules/react-test-renderer/cjs/react-test-renderer.development.js:9215
    The above error occurred in the <TestHook> component:
        in TestHook
        in Suspense
        in ErrorBoundary
    
    React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary.

I know one option is to create a global console.error - but I'd rather leave it in place for other scenarios when i would like those warnings to show up. Is there some kind of middle ground?

@mpeyper
Copy link
Member

mpeyper commented May 10, 2019

You may want to take a look at #50 as there was a better way but the switch to react-test-renderer broke it. I've raised an issue in the React repo, but it has not had any response yet. I'm getting pretty close to just removing the ErrorBoundary and going back to basic try/catch as the warning is pretty annoying.

@gyto23
Copy link

gyto23 commented Feb 26, 2021

@good-idea @mpeyper dont know if you still interested in it, but I have different approach to it, by just avoiding the console error to show up in the unit test

window.addEventListener('error', (e) => e.preventDefault());

@Amine-Abbi
Copy link

You can update the expectation to check for the error message without throwing it :

expect(() => act(() => dispatch({ type: 'whaaat' })).toThrow('Unknown action type');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

5 participants