Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 40 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# redux-mock-store [![Circle CI](https://circleci.com/gh/arnaudbenard/redux-mock-store/tree/master.svg?style=svg)](https://circleci.com/gh/arnaudbenard/redux-mock-store/tree/master)
# Deprecation notice

The Redux team does not recommend testing using this library. Instead, see our [docs](https://redux.js.org/usage/writing-tests) for recommended practices, using a real store.

Testing with a mock store leads to potentially confusing behaviour, such as state not updating when actions are dispatched. Additionally, it's a lot less useful to assert on the actions dispatched rather than the observable state changes.

You can test the entire combination of action creators, reducers, and selectors in a single test, for example:

```js
it('should add a todo', () => {
const store = makeStore() // a user defined reusable store factory

store.dispatch(addTodo('Use Redux'))

expect(selectTodos(store.getState())).toEqual([
{ text: 'Use Redux', completed: false }
])
})
```

This avoids common pitfalls of testing each of these in isolation, such as mocked state shape becoming out of sync with the actual application.

# redux-mock-store [![Circle CI](https://circleci.com/gh/arnaudbenard/redux-mock-store/tree/master.svg?style=svg)](https://circleci.com/gh/arnaudbenard/redux-mock-store/tree/master)

![npm](https://nodei.co/npm/redux-mock-store.png?downloads=true&downloadRank=true&stars=true)

Expand Down Expand Up @@ -36,7 +57,6 @@ const mockStore = configureStore(middlewares)
const addTodo = () => ({ type: 'ADD_TODO' })

it('should dispatch action', () => {

// Initialize mockstore with empty state
const initialState = {}
const store = mockStore(initialState)
Expand Down Expand Up @@ -69,22 +89,21 @@ function success() {
}
}

function fetchData () {
return dispatch => {
function fetchData() {
return (dispatch) => {
return fetch('/users.json') // Some async action with promise
.then(() => dispatch(success()))
};
}
}

it('should execute fetch data', () => {
const store = mockStore({})

// Return the promise
return store.dispatch(fetchData())
.then(() => {
const actions = store.getActions()
expect(actions[0]).toEqual(success())
})
return store.dispatch(fetchData()).then(() => {
const actions = store.getActions()
expect(actions[0]).toEqual(success())
})
})
```

Expand All @@ -93,41 +112,49 @@ it('should execute fetch data', () => {
```js
configureStore(middlewares?: Array) => mockStore: Function
```

Configure mock store by applying the middlewares.

```js
mockStore(getState?: Object,Function) => store: Function
```

Returns an instance of the configured mock store. If you want to reset your store after every test, you should call this function.

```js
store.dispatch(action) => action
```

Dispatches an action through the mock store. The action will be stored in an array inside the instance and executed.

```js
store.getState() => state: Object
```

Returns the state of the mock store.

```js
store.getActions() => actions: Array
```

Returns the actions of the mock store.

```js
store.clearActions()
```

Clears the stored actions.

```js
store.subscribe(callback: Function) => unsubscribe: Function
```

Subscribe to the store.

```js
store.replaceReducer(nextReducer: Function)
```

Follows the Redux API.

### Old version (`< 1.x.x`)
Expand All @@ -138,9 +165,9 @@ https://github.com/arnaudbenard/redux-mock-store/blob/v0.0.6/README.md

The following versions are exposed by redux-mock-store from the `package.json`:

* `main`: commonJS Version
* `module`/`js:next`: ES Module Version
* `browser` : UMD version
- `main`: commonJS Version
- `module`/`js:next`: ES Module Version
- `browser` : UMD version

## License

Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,10 @@
},
"peerDependencies": {
"redux": "*"
},
"prettier": {
"singleQuote": true,
"semi": false,
"trailingComma": "none"
}
}
68 changes: 50 additions & 18 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,61 @@
import { applyMiddleware } from 'redux'
import isPlainObject from 'lodash.isplainobject'

const isFunction = arg => typeof arg === 'function'

export function configureStore (middlewares = []) {
return function mockStore (getState = {}) {
function mockStoreWithoutMiddleware () {
const isFunction = (arg) => typeof arg === 'function'

/**
* @deprecated
*
* The Redux team does not recommend using this package for testing. Instead, check out our {@link https://redux.js.org/recipes/writing-tests testing docs} to learn more about testing Redux code.
*
* Testing with a mock store leads to potentially confusing behaviour, such as state not updating when actions are dispatched. Additionally, it's a lot less useful to assert on the actions dispatched rather than the observable state changes.
*
* You can test the entire combination of action creators, reducers, and selectors in a single test, for example:
* ```js
* it("should add a todo", () => {
* const store = makeStore(); // a user defined reusable store factory
*
* store.dispatch(addTodo("Use Redux"));
*
* expect(selectTodos(store.getState())).toEqual([{ text: "Use Redux", completed: false }]);
* });
* ```
*
* This avoids common pitfalls of testing each of these in isolation, such as mocked state shape becoming out of sync with the actual application.
*
* If you want to use `configureStore` without this visual deprecation warning, use the `legacy_configureStore` export instead.
*
* `import { legacy_configureStore as configureStore } from 'redux-mock-store';`
*/
export function configureStore(middlewares = []) {
return function mockStore(getState = {}) {
function mockStoreWithoutMiddleware() {
let actions = []
let listeners = []

const self = {
getState () {
getState() {
return isFunction(getState) ? getState(actions) : getState
},

getActions () {
getActions() {
return actions
},

dispatch (action) {
dispatch(action) {
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
'Use custom middleware for async actions.'
)
}

if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant? ' +
'Action: ' +
JSON.stringify(action)
'Have you misspelled a constant? ' +
'Action: ' +
JSON.stringify(action)
)
}

Expand All @@ -44,11 +68,11 @@ export function configureStore (middlewares = []) {
return action
},

clearActions () {
clearActions() {
actions = []
},

subscribe (cb) {
subscribe(cb) {
if (isFunction(cb)) {
listeners.push(cb)
}
Expand All @@ -63,7 +87,7 @@ export function configureStore (middlewares = []) {
}
},

replaceReducer (nextReducer) {
replaceReducer(nextReducer) {
if (!isFunction(nextReducer)) {
throw new Error('Expected the nextReducer to be a function.')
}
Expand All @@ -73,12 +97,20 @@ export function configureStore (middlewares = []) {
return self
}

const mockStoreWithMiddleware = applyMiddleware(
...middlewares
)(mockStoreWithoutMiddleware)
const mockStoreWithMiddleware = applyMiddleware(...middlewares)(
mockStoreWithoutMiddleware
)

return mockStoreWithMiddleware()
}
}

/**
* Create Mock Store returns a function that will create a mock store from a state
* with the supplied set of middleware applied.
*
* @param middlewares The list of middleware to be applied.
*/
export const legacy_configureStore = configureStore

export default configureStore