Blog>
Snippets

Integration Testing of Redux Store with TypeScript

Provide an example of how to write integration tests for a Redux store using TypeScript, ensuring the correct behavior of actions and reducers.
import { createStore, applyMiddleware, Store } from 'redux';
import thunk from 'redux-thunk';
import { rootReducer, AppState } from './store'; // Import your rootReducer and AppState

// Define a type for the dispatch
export type AppDispatch = typeof store.dispatch;

// Creating a function to easily create a configured store for tests
export function configureTestStore(): Store<AppState> {
  const store = createStore(rootReducer, applyMiddleware(thunk));
  return store;
}
This piece of code imports the necessary Redux modules to create a test store using the rootReducer and thunk middleware. This test store can mimic the actual store's behavior in a testing environment.
import { configureTestStore } from './testUtils';
import * as actions from './actions';
import { AnyAction } from 'redux';

// Define your specific action creators and initial state
// Example action creator
const addTodo = (title: string) => ({
  type: 'ADD_TODO',
  payload: { title }
});

// Define the initial state type
interface TodoState {
  todos: { title: string }[];
}

// Integration test example
it('should handle adding a todo', () => {
  const store = configureTestStore();
  const initialState: TodoState = { todos: [] };

  // Dispatch the action
  store.dispatch(addTodo('Test Todo') as AnyAction);

  // Get the current state
  const currentState = store.getState();

  // Assert that the state was updated correctly
  expect(currentState.todos).toEqual([{ title: 'Test Todo' }]);
});
Here we have an integration test example using Jest. It tests that when the 'addTodo' action creator is dispatched, the new todo item is correctly added to the state.
import { Action, combineReducers, Reducer } from 'redux';

// Example todo reducer
interface TodoState {
  todos: { title: string }[];
}

const INITIAL_STATE: TodoState = { todos: [] };

function todoReducer(state = INITIAL_STATE, action: Action): TodoState {
  switch (action.type) {
    case 'ADD_TODO':
      return {
        ...state,
        todos: [...state.todos, action.payload],
      };
    default:
      return state;
  }
}

// Combine with other reducers as needed
export const rootReducer: Reducer = combineReducers({
  todo: todoReducer,
  // ... other reducers here
});
This code defines a sample todoReducer and the rootReducer. The todoReducer handles adding a todo to the state when receiving the 'ADD_TODO' action type. The rootReducer uses Redux's combineReducers to combine multiple reducers.