Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/posva/vuex-mock-store

✅Simple and straightforward Vuex Store mock for vue-test-utils
https://github.com/posva/vuex-mock-store

jest mock sinon store test vue vuex

Last synced: about 13 hours ago
JSON representation

✅Simple and straightforward Vuex Store mock for vue-test-utils

Awesome Lists containing this project

README

        

# vuex-mock-store [![Build Status](https://badgen.net/circleci/github/posva/vuex-mock-store)](https://circleci.com/gh/posva/vuex-mock-store) [![npm package](https://badgen.net/npm/v/vuex-mock-store)](https://www.npmjs.com/package/vuex-mock-store) [![coverage](https://badgen.net/codecov/c/github/posva/vuex-mock-store)](https://codecov.io/github/posva/vuex-mock-store) [![thanks](https://img.shields.io/badge/thanks-%E2%99%A5-ff69b4.svg)](https://github.com/posva/thanks)

> Simple and straightforward mock for Vuex v3.x and v4.x (Vue 2 and 3)

Automatically creates spies on `commit` and `dispatch` so you can focus on testing your component without executing your store code.

**Help me keep working on Open Source in a sustainable way 🚀**. Help me with as little as \$1 a month, [sponsor me on Github](https://github.com/sponsors/posva).

Silver Sponsors



Vue Mastery logo



Vuetify logo

Bronze Sponsors



Storyblok logo

---

## Installation

```sh
npm install -D vuex-mock-store
# with yarn
yarn add -D vuex-mock-store
```

## Usage

ℹ️: _All examples use [Jest](https://jestjs.io) API_. See [below](#providing-custom-spies) to use a different mock library.

Usage with [vue-test-utils](https://github.com/vuejs/vue-test-utils):

Given a component `MyComponent.vue`:

```vue


{{ count }}


{{ doubleCount }}


+
-


Save

import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'

export default {
computed: {
...mapState(['count']),
...mapGetters(['doubleCount']),
},
methods: {
...mapMutations(['increment', 'decrement']),
...mapActions(['save']),
},
}

```

You can test interactions without relying on the behaviour of your actions and mutations:

```js
import { Store } from 'vuex-mock-store'
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'

// create the Store mock
const store = new Store({
state: { count: 0 },
getters: { doubleCount: 0 },
})
// add other mocks here so they are accessible in every component
const mocks = {
global: { $store: store },
// for Vue 2.x: just { $store: store } without global
}

// reset spies, initial state and getters
afterEach(() => store.reset())

describe('MyComponent.vue', () => {
let wrapper
beforeEach(() => {
wrapper = mount(MyComponent, { mocks })
})

it('calls increment', () => {
wrapper.find('button.increment').trigger('click')
expect(store.commit).toHaveBeenCalledOnce()
expect(store.commit).toHaveBeenCalledWith('increment')
})

it('dispatch save with count', () => {
wrapper.find('button.save').trigger('click')
expect(store.dispatch).toHaveBeenCalledOnce()
expect(store.dispatch).toHaveBeenCalledWith('save', { count: 0 })
})
})
```

⚠️ The mocked `dispatch` method returns `undefined` instead of a Promise. If you rely on this, you will have to call the appropriate function to make the `dispatch` spy return a Promise:

```js
store.dispatch.mockReturnValue(Promise.resolve(42))
```

If you are using Jest, you can check the documentation [here](https://jestjs.io/docs/en/mock-function-api#mockfnmockreturnvaluevalue)

### Initial state and getters

You can provide a `getters`, and `state` object to mock them:

```js
const store = new Store({
getters: {
name: 'Eduardo',
},
state: {
counter: 0,
},
})
```

### Modules

#### State

To mock module's `state`, provide a nested object in `state` with the same name of the module. As if you were writing the state yourself:

```js
new Store({
state: {
value: 'from root',
moduleA: {
value: 'from A',
moduleC: {
value: 'from A/C',
},
},
moduleB: {
value: 'from B',
},
},
})
```

That will cover the following calls:

```js
import { mapState } from 'vuex'

mapState(['value']) // from root
mapState('moduleA', ['value']) // from A
mapState('moduleB', ['value']) // from B
mapState('moduleA/moduleC', ['value']) // from C
```

_When testing `state`, it doesn't change anything for the module to be namespaced or not_

#### Getters

To mock module's `getters`, provide the correct name based on whether the module is _namespaced_ or not. Given the following modules:

```js
const moduleA = {
namespaced: true,

getters: {
getter: () => 'from A',
},

// nested modules
modules: {
moduleC: {
namespaced: true,
getter: () => 'from A/C',
},
moduleD: {
// not namespaced!
getter: () => 'from A/D',
},
},
}

const moduleB = {
// not namespaced
getters: {
getter: () => 'from B',
},
}

new Vuex.Store({ modules: { moduleA, moduleC } })
```

We need to use the following getters:

```js
new Store({
getters: {
getter: 'from root',
'moduleA/getter': 'from A',
'moduleA/moduleC/getter': 'from A/C',
'moduleA/getter': 'from A/D', // moduleD isn't namespaced
'moduleB/getter': 'from B',
},
})
```

#### Actions/Mutations

As with _getters_, testing actions and mutations depends whether your [modules are namespaced](https://vuex.vuejs.org/guide/modules.html#namespacing) or not. If they are namespaced, make sure to provide the full action/mutation name:

```js
// namespaced module
expect(store.commit).toHaveBeenCalledWith('moduleA/setValue')
expect(store.dispatch).toHaveBeenCalledWith('moduleA/postValue')
// non-namespaced, but could be inside of a module
expect(store.commit).toHaveBeenCalledWith('setValue')
expect(store.dispatch).toHaveBeenCalledWith('postValue')
```

_Refer to the module example below using `getters` for a more detailed example, even though it is using only `getters`, it's exactly the same for `actions` and `mutations`_

### Mutating `state`, providing custom `getters`

You can [modify](#state) the `state` and `getters` directly for any test. Calling [`store.reset()`](#reset) will reset them to the initial values provided.

## API

### `Store` class

#### `constructor(options)`

- `options`
- `state`: initial state object, _default_: `{}`
- `getters`: getters object, _default_: `{}`
- `spy`: interface to create spies. [details below](#providing-custom-spies)

#### `state`

Store state. You can directly modify it to change state:

```js
store.state.name = 'Jeff'
```

#### `getters`

Store getters. You can directly modify it to change a value:

```js
store.getters.upperCaseName = 'JEFF'
```

ℹ️ _Why no functions?_: if you provide a function to a getter, you're reimplementing it. During a test, you know the value, you should be able to provide it directly and be **completely sure** about the value that will be used in the component you are testing.

#### `reset`

Reset `commit` and `dispatch` spies and restore `getters` and `state` to their initial values

#### Providing custom spies

By default, the Store will call `jest.fn()` to create the spies. This will throw an error if you are using `mocha` or any other test framework that isn't Jest. In that situation, you will have to provide an interface to _create_ spies. This is the default interface that uses `jest.fn()`:

```js
new Store({
spy: {
create: (handler) => jest.fn(handler),
},
})
```

The handler is an optional argument that mocks the implementation of the spy.

If you use Jest, you don't need to do anything.
If you are using something else like [Sinon](https://sinonjs.org), you could provide this interface:

```js
import sinon from 'sinon'

new Store({
spy: {
create: (handler) => sinon.spy(handler),
},
})
```

### `commit` & `dispatch`

Spies. Dependent on the testing framework

- [jest.fn](https://jestjs.io/docs/en/jest-object#jestfnimplementation)
- [sinon.spy](https://sinonjs.org/releases/v6.3.4/spies)

## Related

- [vue-test-utils](https://github.com/vuejs/vue-test-utils)
- [vuex](https://github.com/vuejs/vuex)

## License

[MIT](http://opensource.org/licenses/MIT)