web-dev-qa-db-ja.com

Redux単体テストでストアを更新する方法は?

酵素を使用して、モカとアサートを期待しています。

私のユニットテストの目的は、mergePropsで一時停止していても一時停止していないときに、ディスパッチが正しい引数で呼び出されることを確認することです。私はストアの状態を動的に変更する必要があります:paused: true

現時点では、ディスパッチして一時停止中の値を更新しようとしていますが、これは単なるモックであり、実際にレデューサーを通過することはないため、これは正しくないと思います。

私はパッケージ redux-mock-store を使用しています。

どうすればよいですか?

describe('Play Container', () => {
  const id = 'audio-player-1';

  const store = configureMockStore()({
    players: {
        'audio-player-1': { paused: false }
    }
  });
  let dispatchSpy;
  let wrapper;

  beforeEach(() => {
    dispatchSpy = expect.spyOn(store, 'dispatch');
    wrapper = shallow(
      <PlayContainer className={attributes.className}>
        {children}
      </PlayContainer>,
      { context: { id } },
      ).shallow({ context: { store } });
  });

  it('onClick toggles play if paused', () => {
    //Not Working
    store.dispatch(updateOption('paused', true, id));
    wrapper.simulate('click');
    expect(dispatchSpy).toHaveBeenCalledWith(play(id));
  });

  it('onClick toggles pause if playing', () => {
    wrapper.simulate('click');
    expect(dispatchSpy).toHaveBeenCalledWith(pause(id));
  });
});

コンテナ:

const mapStateToProps = ({ players }, { id }) => ({
  paused: players[id].paused
});

const mergeProps = (stateProps, { dispatch }, { id }) => ({
  onClick: () => (stateProps.paused ? dispatch(play(id)) : dispatch(pause(id)))
});

export default connectWithId(mapStateToProps, null, mergeProps)(Play);

connectWithId:

//getContext() is from recompose library and just injects id into props
export const connectWithId = (...args) => compose(
  getContext({ id: React.PropTypes.string }),
  connect(...args),
);

行動:

updateOption: (key, value, id) => ({
    type: actionTypes.player.UPDATE_OPTION,
    key,
    value,
    id,
}),
12
Martin Dawson

configureMockStoreはミドルウェアを適用してモックストアを構成するために使用されるファクトリです。 mockStoreオブジェクトを返します。
mockStoreは、構成されたモックストアのインスタンスを返します。アクションによって状態が変化することはありません。アクションが渡されたレコードのみが渡されました。背後にある理由は、「統合」(状態+コンポーネント)テストではなく、単体テストを作成するためのユーティリティツールであるためです。

それでも、状態の変化をシミュレートできます。 mockStoreは関数を受け入れるため、次のことができます。

import configureMockStore from 'redux-mock-store';

const middlewares = [];
const mockStore = configureMockStore(middlewares);

let state = {
  players: {
    'audio-player-1': { paused: false }
  }
};

const store = mockStore(() => state);

次に、テストで次のことができます。

state = NEW_STATE;

// now you need to make the components update the state.
// so you can dispatch any action so the mock store will notify the subscribers
store.dispatch({ type: 'ANY_ACTION' }); 
10
Lucas

あなたができることはあなたのテストで実際の店を使うことです。最初に、レデューサー関数を作成します。

const reducer = (state, action) => {
  if (action.type === actionTypes.player.UPDATE_OPTION) {
    return {
      ...state,
      players: {
        ...state.players,
        [action.id]: {
          ...state.players[action.id],
          [action.key]: action.value,
        },
      },
    };
  }
  return state;
};

(このテストで他の状態を保持しないことに問題がない場合は、上記を単純化して新しい状態を返すだけでよいことに注意してください。)

次に、そのレデューサーと初期状態でストアを作成します。

import { createStore } from 'redux';

const store = createStore(reducer, {
  players: {
    'audio-player-1': { paused: false }
  }
});

これで、updateOptionを使用したディスパッチは新しい状態になります。

1
robinst