Getting Started with Redux in React Testing Library: A Guide to Custom Render Functions.
Tags: javascript, react, testdev, programming
Published: 2024-03-04 14:36:36

#### Introduction 
Often in our projects we need to manage the state. For this purpose, we can use Redux however in 2024 there is a Redux toolkit , which simplifies the use of Redux itself.  In this tutorial, I want to focus on how to start testing an application that uses the Redux toolkit.

#### Custom render function. 

In testing React components, It is often used external libraries, not only _redux-toolkit_, but also _react-router-dom_ or _styled-components_ . In these cases, it is usefull to create custom render function.

Let's take as example boardSlice.ts (example from my project): 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2cxay9zz6m5hn2t5g1fr.png)

Import the necessary modules and components from React, Redux Toolkit, React Testing Library, and your application.

```
import { ReactElement, ReactNode } from 'react';
import { render, RenderOptions } from '@testing-library/react';
import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import { boardSlice } from './store/slices';
```
Define the CustomRenderOptions interface witch extends the `RenderOptions` from `@testing-library/react`, excluding the `wrapper` property. It adds optional `preloadedState` and `store` properties. This allows you to pass an initial state for the Redux store or a custom store when calling `customRender`. 

```
interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
  preloadedState?: Record<string, unknown>;
  store?: ReturnType<typeof configureStore>;
}
```

Create the customRender function  takes a React element and an options object as arguments. The options object defaults to an empty object if not provided. 
Create the Redux store: If a store is not provided in the options, a new store is created using the `configureStore` function from Redux Toolkit. The store uses the `boardSlice.reducer` as its reducer and the `preloadedState` as its initial state.


```
const customRender = (
  ui: ReactElement,
  {
    preloadedState = {},
    store = configureStore({
      reducer: { board: boardSlice.reducer },
      preloadedState,
    }),
    ...options
  }: CustomRenderOptions = {}
) => {
  // ...
};
```
Create the Wrapper component, wraps its children in a Redux `Provider`. The `Provider` makes the Redux store available to the components.

```
const Wrapper = ({ children }: { children: ReactNode }) => (
  <Provider store={store}>{children}</Provider>
);
```

Call the render function finally, the function calls the `render` function from React Testing Library, passing the `ui` and the `Wrapper` as the `wrapper` option.

```
return render(ui, { wrapper: Wrapper, ...options });
```


Export the `customRender` function,  then exported as `render`, so it can be used in place of the `render` function from `@testing-library/react`.

```
export { customRender as render };
```

Finally we receive : 

```
import { ReactElement, ReactNode } from 'react';
import { render, RenderOptions } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import { configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import { boardSlice } from './store/slices';
interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
  preloadedState?: Record<string, unknown>;
  store?: ReturnType<typeof configureStore>;
}

const customRender = (
  ui: ReactElement,
  {
    preloadedState = {},
    store = configureStore({
      reducer: { board: boardSlice.reducer },
      preloadedState,
    }),
    ...options
  }: CustomRenderOptions = {}
) => {
  const Wrapper = ({ children }: { children: ReactNode }) => (
   // Here you can other providers
    <Provider store={store}>
      {children}
    </Provider>
  );

  return render(ui, { wrapper: Wrapper, ...options });
};

export * from '@testing-library/react';
export { customRender as render };

```

#### Sumarry

In this tutorial, we've explored how to create a custom render function for testing React components that interact with a Redux store, using Redux Toolkit. This custom render function simplifies the testing process by automatically wrapping the component under test in the necessary context providers, such as Redux's `Provider` and React Router's `MemoryRouter`.

We started by importing the necessary modules and defining a `CustomRenderOptions` interface to extend the `RenderOptions` from `@testing-library/react`. This interface allows us to optionally pass an initial state or a custom store to the `customRender` function.

Next, we created the `customRender` function, which takes a React element and an options object as arguments. Inside this function, we created a Redux store (if not provided in the options) and a `Wrapper` component that wraps its children in a Redux `Provider`.

Finally, we called the `render` function from `@testing-library/react`, passing the `ui` and the `Wrapper` as the `wrapper` option, and exported the `customRender` function as `render`.

This custom render function is a powerful tool that can simplify your test setup, reduce repetition in your tests, and make your tests more robust and flexible when working with libraries like Redux Toolkit.
 With this configuration, your application is now equipped to handle Redux Toolkit in unit tests. In subsequent sections, we will delve into the specifics of what to test and how to conduct these tests within the Redux Toolkit context.