Home Reference Source

src/IntegrationTestHelper.js

import React from 'react';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import { applyMiddleware, combineReducers, createStore } from 'redux';
import thunk from 'redux-thunk';

/**
 * Integration test helper
 * @since 0.1.0
 */
export class IntegrationTestHelper {
  /**
   * Wait for all the promises in the test to get resolved
   * @return {Promise}
   */
  static flushAllPromises() {
    return new Promise(resolve => setImmediate(resolve));
  }
  /**
   * Create an integration-test-helper
   * @param {ReduxReducers} reducers reducers to apply
   * @param {ReduxMiddlewares} middlewares array of middlewares to apply
   */
  constructor(reducers, middlewares = []) {
    this.dispatchSpy = jest.fn(() => ({}));
    const reducerSpy = (state, action) => this.dispatchSpy(action);
    const emptyStore = applyMiddleware(thunk, ...middlewares)(createStore);
    const combinedReducers = combineReducers({
      reducerSpy,
      ...reducers,
    });

    this.store = emptyStore(combinedReducers);
  }
  /**
   * Mount a component with the store
   * @param  {ReactNode} component A react node to mount
   * @return {EnzymeMount}         Mounted component with enzyme and redux store
   */
  mount(component) {
    return mount(<Provider store={this.store}>{component}</Provider>);
  }
  /**
   * Get the current state object
   * @return {Object} Current state
   */
  getState() {
    const state = this.store.getState();
    delete state.reducerSpy;
    return state;
  }
  /**
   * Get a list with all dispach calls
   * @return {Array} Dispach calls
   */
  getDispatchCalls() {
    const isRelevantCall = call =>
      call.filter(({ type }) => type.startsWith('@@redux')).length === 0;

    return this.dispatchSpy.mock.calls.filter(isRelevantCall);
  }
  /**
   * Get the last dispach call
   * @return {Array} dispach call
   */
  getLastDispachCall() {
    return this.getDispatchCalls().slice(-1);
  }
  /**
   * Take a store snapshot
   * @param  {string} description Snapshoot description
   */
  takeStoreSnapshot(description) {
    expect(this.getState()).toMatchSnapshot(description);
  }
  /**
   * Take a snapshot of all the actions
   * @param  {string} description Snapshoot description
   */
  takeActionsSnapshot(description = 'Integration test actions') {
    expect(this.getDispatchCalls()).toMatchSnapshot(description);
  }
  /**
   * Take a snapshot of the last called action
   * @param  {string} description Snapshoot description
   */
  takeLastActionSnapshot(description) {
    expect(this.getLastDispachCall()).toMatchSnapshot(description);
  }
  /**
   * Take a snapshot of the store together with the last action call
   * @param  {string} description Snapshot description
   */
  takeStoreAndLastActionSnapshot(description) {
    const state = this.getState();
    const action = this.getLastDispachCall();

    expect({ state, action }).toMatchSnapshot(description);
  }
}