1

I am trying to write test for my error boundary hoc. But when I mock throwing error in my wrapped component my test gets fail because of the same error I throw, like it seems like it doesnt recognize that this error was intended for testing. I am not sure what I am doing wrong here.

This is ErrorBoundary HOC:


interface StateProps {
  error: unknown;
  info: unknown;
}

interface ErrorBoundaryProps {
  createNotification(...args: any): void;
}

const connector = connect(null, {
  createNotification: createNotificationAction,
});

export const withErrorBoundary = <P extends object>(TargetComponent: React.ComponentType<P>) => {
  class ErrorBoundary extends React.Component<ErrorBoundaryProps, StateProps> {
    constructor(props: ErrorBoundaryProps) {
      super(props);
      this.state = {
        error: null,
        info: null,
      };
    }

    public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
      this.props.createNotification({
        alertType: 'error',
        message: `${TargetComponent.name} is not being rendered. Error: ${error.message}`,
      });
      this.setState({ error, info: errorInfo });
    }

    public render() {
   
      const { ...props } = this.props;
      if (this.state.error instanceof Error) {
        return null;
      }
      return <TargetComponent {...(props as P)} />;
    }
  }

  return connector(ErrorBoundary) as any;
};

and here is the test:


describe('ErrorBoundary HOC', () => {
  let store;
  let createNotification;
  let props;

  beforeEach(() => {
    store = configureStore(defaultState);
    createNotification = jest.fn();

    props = {
      createNotification,
    };

  });

  test('Renders nothing if error', async () => {
    const targetComponent = () => {
      throw new Error('Errored!');
    };
    const WrappedComponent = withErrorBoundary(targetComponent);
    const RenderedComponent = render(
      <BrowserRouter>
        <Provider store={store}>
          <WrappedComponent {...props} />
        </Provider>
      </BrowserRouter>
    );

    await waitFor(() => expect(() => WrappedComponent.toThrow()));
    expect(RenderedComponent.container.hasChildNodes()).toBeFalsy();
    await waitFor(() => expect(createNotification).toHaveBeenCalled());

 
  });

});

What I have been found so far is the error is throwing before render in the test. but not sure how to solve this.

Thanks for your help in advance.

Fody
  • 23,754
  • 3
  • 20
  • 37
Samira Arabgol
  • 359
  • 2
  • 5
  • 22

1 Answers1

1

In a functional component, everything before the return is executed before rendering, except for stuff in useEfffect().

In this case targetComponent has no return or JSX to render, but it still applies.

You can throw the error after render like this

const targetComponent = () => {
  useEffect(() => {
    throw new Error('Errored!');
  }, [])
}

I'm not sure if it's enough to give you the desired test, but it's a strating point.

Fody
  • 23,754
  • 3
  • 20
  • 37