Skip to content
This repository has been archived by the owner on Jun 17, 2024. It is now read-only.

React/Testing Library - How to do proper cleanup and re-use Component Initialisation with Proper State and Props?? #818

Open
EfstathiadisD opened this issue May 26, 2020 · 0 comments

Comments

@EfstathiadisD
Copy link

EfstathiadisD commented May 26, 2020

I have a Loading, Error, Data State in a component. Think of it as a Switch Statement. on Steroids. I want to test that Logic. So, I wrote the below code:

The below code works perfectly. Absolutely fine. But I have a problem with it. I need to call Logic Component in every single it statement. Which makes it hard to read, check and maintain.

In case it makes a difference, the renderWithRouter I am using is a custom one, I wrote, and you can see it below:

/* {renderWithRouter} Helper Component is meant to be used only for Testing.
 * Use it if you want to wrap you Component with react-router
 *
 * @param MockHistory: History Object. Similar to MemoryRouter.
 * @param MockWrapper: Wrapping the children with Router with {history}
 *
 * @return All the component, along with their Wrapper and history
 */
const renderWithRouter = (component: JSX.Element, route: string) => {
  const MockHistory = createMemoryHistory({ initialEntries: [route] });
  const MockWrapper = ({ children }: any) => <Router history={MockHistory}>{children}</Router>;
  return { ...render(component, { wrapper: MockWrapper }), MockHistory };
};
  describe('Error View if [isLoading: false, isError: true, data: null, error: errorResponse]', () => {
    const Logic = () =>
      renderWithRouter(
        <LogicComponent
          isError
          data={null}
          isLoading={false}
          error={errorResponse.error}
          callServer={() => errorResponse.primaryCall()}
        />,
        route
      );

    it('should NOT render [Loading View]', () => {
      const { queryByTestId } = Logic();
      expect(queryByTestId('lenses-content-spinner')).toBeNull();
    });
    it('should render [ErrorView]', () => {
      const { queryByTestId, queryByText } = Logic();
      const searchWithin = within(queryByTestId('no-resource'));

      expect(searchWithin.queryByText('Error: WS Error Message')).toBeDefined();
      expect(queryByText('There has been an error. Please try again.')).toBeDefined();
    });
    it('should NOT render [DataView]', () => {
      const { queryByTestId } = Logic();

      expect(queryByTestId('data--view')).toBeNull();
    });
    it('should render [ErrorView] and call [Callback] exactly once', () => {
      const { queryByText, queryByTestId } = Logic();
      const searchWithin = within(queryByTestId('no-resource'));

      waitForElement(() => searchWithin.queryByText('Try Again'));
      fireEvent.click(queryByText('Try Again'));

      expect(errorResponse.primaryCall).toHaveBeenCalledTimes(1);
    });
  });

Is there a way to re-use Component with their unique props, in every test? And in general is this pattern consider acceptable? What should we do in situation like that? My desired code would looked something like that:

  describe('Error View if [isLoading: false, isError: true, data: null, error: errorResponse]', () => {
    const {queryByTestId, queryByText } = renderWithRouter(
        <LogicComponent
          isError
          data={null}
          isLoading={false}
          error={errorResponse.error}
          callServer={() => errorResponse.primaryCall()}
        />,
        route
      );

    it('should NOT render [Loading View]', () => {
      expect(queryByTestId('lenses-content-spinner')).toBeNull();
    });
    it('should render [ErrorView]', () => {
      expect(searchWithin.queryByText('Error: WS Error Message')).toBeDefined();
      expect(queryByText('There has been an error. Please try again.')).toBeDefined();
    });
    it('should NOT render [DataView]', () => {
      expect(queryByTestId('data--view')).toBeNull();
    });
    it('should render [ErrorView] and call [Callback] exactly once', () => {
      waitForElement(() => searchWithin.queryByText('Try Again'));
      fireEvent.click(queryByText('Try Again'));

      expect(errorResponse.primaryCall).toHaveBeenCalledTimes(1);
    });
  });

Is the above possible? I haven't been able to make it work. Basically, state isn;t clean between it statements, and I resorted to the individual initialisation. Thank you!!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant