最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do I reset the redux-test-utils store between tests - Stack Overflow

programmeradmin1浏览0评论

I have a subscriber that dispatches an action based on the parameters supplied to a pub event

// subscriptions.js
import store from '../store';
import { action } from '../actions';
export const subscribeToToggle = () => {
    window.$.subscribe('action/toggle', (_e, isToggleOn) => {

        if (isToggleOn=== true){
            store.dispatch(action());
        }
    });
};

In my test file I write 2 tests that test that the action is sent only when true is supplied.

// subscriptions.test.js
import { subscribeToToggle } from './subscriptions';
import jQuery from 'jquery';
import { actionTypes } from '../constants';
import store from '../store';
jest.mock('../store');

beforeEach(() => {
    window.$ = jQuery;
    window.$.unsubscribe('action/toggle');

});

test('Action not sent when false', () => {

    subscribeToToggleOpen();
    window.$.publish('action/toggle', false);

    expect(store.getActions().length).toBe(0);
});

test('Action sent when true', () => {

    subscribeToToggleOpen();
    window.$.publish('action/toggle', true);

    expect(store.getActions().length).toBe(1);
    expect(store.getActions()[0].type).toBe(actionTypes.ACTION);
});

I have the following mocked store using redux-test-utils

import { createMockStore } from 'redux-test-utils';
let store = null;
store = createMockStore('');
export default store;

The issue I face is that my test only pass when the false test es first. If they are the other way around the 'Action not sent when false' test fails as it sees the action supplied by the 'Action sent when true' test.

Is there any way for me to use the beforeEach method to reset the mocked store object?

I have a subscriber that dispatches an action based on the parameters supplied to a pub event

// subscriptions.js
import store from '../store';
import { action } from '../actions';
export const subscribeToToggle = () => {
    window.$.subscribe('action/toggle', (_e, isToggleOn) => {

        if (isToggleOn=== true){
            store.dispatch(action());
        }
    });
};

In my test file I write 2 tests that test that the action is sent only when true is supplied.

// subscriptions.test.js
import { subscribeToToggle } from './subscriptions';
import jQuery from 'jquery';
import { actionTypes } from '../constants';
import store from '../store';
jest.mock('../store');

beforeEach(() => {
    window.$ = jQuery;
    window.$.unsubscribe('action/toggle');

});

test('Action not sent when false', () => {

    subscribeToToggleOpen();
    window.$.publish('action/toggle', false);

    expect(store.getActions().length).toBe(0);
});

test('Action sent when true', () => {

    subscribeToToggleOpen();
    window.$.publish('action/toggle', true);

    expect(store.getActions().length).toBe(1);
    expect(store.getActions()[0].type).toBe(actionTypes.ACTION);
});

I have the following mocked store using redux-test-utils

import { createMockStore } from 'redux-test-utils';
let store = null;
store = createMockStore('');
export default store;

The issue I face is that my test only pass when the false test es first. If they are the other way around the 'Action not sent when false' test fails as it sees the action supplied by the 'Action sent when true' test.

Is there any way for me to use the beforeEach method to reset the mocked store object?

Share Improve this question asked Feb 15, 2018 at 17:25 RobPethiRobPethi 5719 silver badges27 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 3

In this case, the problem is that your store is essentially a singleton. This can create issues when you are trying to do things like this and is generally kind of an anti-pattern.

Instead of exporting a store object, it'd probably be better if you exported a getStore() function which could be called to get the store. In that case, you could then do:

getStore().dispatch(action());

Inside of that, you could then have other helper functions to be able to replace the store that is being returned by it. That file could look something like this:

import { createMockStore } from 'redux-test-utils';
let store = createMockStore('');

export default () => store;

Then, inside of there, you can add another which could be resetStore as a non-default export:

export const resetStore = () => store = createMockStore('');

It would still technically be a singleton, but it's now a singleton you can have some control over.

Then, in your beforeEach() in your tests, just call resetStore():

import { resetStore } from '../store';

beforeEach(() => {
  resetStore();
});

This would also require you to update your real code to use getStore() instead of store directly, but it'll probably be a beneficial change in the long run.


Complete Updated Version:

// subscriptions.js
import getStore from '../store';
import { action } from '../actions';
export const subscribeToToggle = () => {
    window.$.subscribe('action/toggle', (_e, isToggleOn) => {

        if (isToggleOn=== true){
            getStore().dispatch(action());
        }
    });
};

// subscriptions.test.js
import { subscribeToToggle } from './subscriptions';
import jQuery from 'jquery';
import { actionTypes } from '../constants';
import getStore, { resetStore } from '../store';
jest.mock('../store');

beforeEach(() => {
    window.$ = jQuery;
    window.$.unsubscribe('action/toggle');
    resetStore();
});

test('Action not sent when false', () => {
    subscribeToToggleOpen();
    window.$.publish('action/toggle', false);

    expect(getStore().getActions().length).toBe(0);
});

test('Action sent when true', () => {

    subscribeToToggleOpen();
    window.$.publish('action/toggle', true);

    expect(getStore().getActions().length).toBe(1);
    expect(getStore().getActions()[0].type).toBe(actionTypes.ACTION);
});

import { createMockStore } from 'redux-test-utils';
let store;

export const resetStore = () => { store = createMockStore(''); }

resetStore(); // init the store, call function to keep DRY

export default () => store;

Beyond that, the other way would be to have a global reducer which could reset the state of the store to it's default, but that would be messier and I don't really think would generally fit with writing a unit test.

发布评论

评论列表(0)

  1. 暂无评论