Testes em React-Redux
Tags: javascript, webdev, beginners, redux
Published: 2022-01-07 22:47:32

## Testando Redux

### Como fazer?
Para testarmos aplicações em Redux utilizamos uma lógica similar a testes com o React-Router, ou seja, trocamos a função `render()` padrão do RTL, pelo render da biblioteca, no caso do Redux, `renderWithRedux()`.

Assim como no React-Router, nosso `render()` para testes da biblioteca não vem pronto, devemos criá-lo como uma função. Fazendo isso, basta chamar essa função antes dos testes e pronto, podemos trabalhar o RTL normalmente.

### Sintaxe
A função `renderWithRedux()` recebe dois parâmetros, o primeiro é o componente que queremos renderizar e o segundo é uma desconstrução de objeto representando um Store. Dessa forma podemos criar um Store apenas para o ambiente de testes e manipulá-lo livremente.

A desconstrução de objeto no segundo parâmetro deve conter o initialState, o Store, que por sua vez recebe a função `createStore()`, essa que recebe por parâmetro o reducer e o initialState.

O retorno da função `renderWithRedux()` deve ser um objeto de duas chaves, a primeira chave representa a desconstrução de um componente renderizado através da função `render()` padrão, sendo que esse componente deve estar _“encapsulado”_ pelo componente Provider.

Já a segunda chave é a própria store criada através da desconstrução de objeto nos parâmetros da função.

``` js
const renderWithRedux = (
  component,
  { initialState, store = createStore(reducer, initialState) } = {}
) => {
  return {
    ...render(
      <Provider store={store}>
        {component}
      </Provider>
    ),
    store,
  };
};
```

Por ser uma sintaxe complexa, podemos simplesmente _“copiar e colar”_ essa função sempre que necessário, assim depois que o componente for renderizado, basta seguir o passo a passo de um teste comum do RTL.

A única ressalva fica em relação a função `createStore(),` chamada no parâmetro da função `renderWithRedux()`, caso utilizemos um combineReducer em nossa Store original da aplicação, devemos utilizá-lo no parâmetro também.

Além de que __os Reducers que o combineReducer irá receber, devem ter os mesmos nomes dos originais__, afinal estamos fazendo uma desconstrução de objeto, logo __o nome das chaves tem que ser respeitados__.

``` js
const renderWithRedux = (
  component,
  {
    initialState,
    store = createStore(combineReducers({ myReducer }), initialState),
  } = {}
) => {
  return {
    ...render(
      <Provider store={store}>
        {component}
      </Provider>
    ),
    store,
  };
};
```

## Testes Assíncronos no Redux

### Como fazer?
Assim como nos testes síncronos, ainda precisamos utilizar a função `renderWithRedux()`, sendo que a maior diferença se dá na criação da Store personalizada para os testes, onde além de precisarmos passar o estado inicial e o Reducer, também é necessário passar o Redux-Thunk através do `applyMiddleware()`.

### Sintaxe
A sintaxe geral continua a mesma como dito anteriormente, com a pequena diferença que precisamos utilizar o `applyMiddleware()`. Também é interessante frisar que __podemos dividir a função em mais pedaços__, ou não.

#### Uma função

``` js
const renderWithRedux = (
  component,
  {
    initialState,
    store = createStore(
      combineReducers({ reducer }),
      initialState,
      applyMiddleware(thunk)
    ),
  } = {}
) => ({
  ...render(
    <Provider store={store}>
      {component}
    </Provider>
  ),
  store,
});

```

#### Dividindo em duas funções
``` js
const createMockStore = (initialState) =>
  createStore(
    combineReducers({ reducer }),
    initialState,
    applyMiddleware(thunk)
  );

const renderWithRedux = (
  component,
  { initialState, store = createMockStore(initialState) } = {}
) => ({
  ...render(
    <Provider store={store}>
      {component}
    </Provider>
    ),
  store,
});

```

## Testes com Redux + Router

### Como fazer?
Para testarmos components que estão dentro de uma rota e conectados a Store, precisamos de uma função _(helper)_ mais completa. Esse helper deverá executar tanto o encapsulamento por Rota, quanto pelo Provider do Redux.

### Sintaxe
A sintaxe desse helper é consideravelmente mais complexa que a dos outros, porém por se tratar de um helper podemos simplesmente _"copiar e colar"_ conforme a necessidade.

O helper `renderWithRuterAndRedux()` consiste em uma função com dois parâmetros, o __primeiro parâmetro é obrigatório__ e consiste no __componente que desejamos renderizar__.

Já o __segundo parâmetros é opcional__ e __é um objeto com quatro chaves__, sendo que todas essas chaves também são opcionais, logo podemos passar todas as chaves ou apenas uma.

O objeto do segundo parâmetro possue as seguintes chaves:
- __initialState__: refere-se ao estado inicial da Store, o que nós permite _mocka-lá_
- __store__: como o nome indica, é a Store do Redux, sendo assim podemos passar uma Store personalizada
- __initialEntries__: é um Array com caminhos do Router, sendo assim podemos criar uma _"trilha"_ para o React-Router
- __history__: refere-se ao histórico de paginação do Router.

Lembrando que todas as chaves do objeto do segundo parâmetro devem conter valores padrões, assim como o objeto em si.

``` js
const renderWithRouterAndRedux = (
  component,
  {
    initialState = {},
    store = createStore(rootReducers, initialState),
    initialEntries = ['/'],
    history = createMemoryHistory({ initialEntries }),
  } = {},
) => ({
  ...render(
    <Router history={ history }>
      <Provider store={store}>
        {component}
      </Provider>
    </Router>
  ),
  history,
  store,
});
```