Skip to content

Commit

Permalink
feat: Vuex support
Browse files Browse the repository at this point in the history
* working on Vuex example for cypress-io/cypress-vue-unit-test#6

* fix: Vuex integration and add Counter example tests (cypress-io/cypress-vue-unit-test#13)

* fix: vuex integration (bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6)

The inner Vue instance within Vuex Store must be refeshed by `resetStoreVM` to restore reactivity of the store state. This doesn’t fix stale mapped getters within components. That’s a separate WIP issue.

* fix: stale mapped getter `evenOrOdd` (bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6)

Current mapped vuex getters within components become stale. To have a working Counter example, the computed mapped `evenOrOdd` is accessed directly via `$store`. This will be changed back once the stale mapped getter issue (WIP) is fixed.

* feat: added example tests for Counter component

Added tests to cover all the features within the component. Fixes bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6

* minor: following better practices

* Full Vuex support with enhanced Counter.vue example and test spec (cypress-io/cypress-vue-unit-test#15)

* fix: vuex integration (bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6)

The inner Vue instance within Vuex Store must be refeshed by `resetStoreVM` to restore reactivity of the store state. This doesn’t fix stale mapped getters within components. That’s a separate WIP issue.

* fix: stale mapped getter `evenOrOdd` (bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6)

Current mapped vuex getters within components become stale. To have a working Counter example, the computed mapped `evenOrOdd` is accessed directly via `$store`. This will be changed back once the stale mapped getter issue (WIP) is fixed.

* feat: added example tests for Counter component

Added tests to cover all the features within the component. Fixes bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6

* minor: following better practices

* fix: refactor Vue initialization in app frame

Refactors how the Vue instance within the component app frame is initialized, and fully fixes Vue integration.
- fixes lingering issues after pull request bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#13
- fully fixes bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6
- fixes amirrustam/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#1
- README docs have been updated to reflect refactoring
- 'vue' option has been deprecated (with warning to user) as it's no longer necessary
- spread operator support has been added for upcoming Vuex example

* feat: enhanced Vuex Counter example and test spec

To thoroughly demonstrate Vuex support after the refactoring in commit amirrustam/cypress-vue-unit-test@e8773383, Counter.vue now:
- Utilizes all Vuex mapping functions.
- Can properly use computed mapped getters in its template. This was an issue after bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#13.
- Set count state via an input field to demonstrate mapped mutations. Two tests have been added to the spec for this new input field.

Close bahmutov/cypress-vue-unit-testbahmutov/cypress-vue-unit-test#6

* minor: remove redundant declaration
  • Loading branch information
bahmutov authored Jan 31, 2018
1 parent 79c7df0 commit 6e92cf3
Show file tree
Hide file tree
Showing 7 changed files with 281 additions and 78 deletions.
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,11 @@ See examples below for details.
See [cypress/integration/options-spec.js](cypress/integration/options-spec.js)
for examples of options.

* `vue` - path or URL to the Vue library to load. By default, will
try to load `../node_modules/vue/dist/vue.js`, but you can pass your
own path or URL.
* `mountId` - specify root Vue app mount element ID. Defaults to `app`.

```js
const options = {
vue: 'https://unpkg.com/vue'
mountId: 'rootApp' // div#rootApp
}
beforeEach(mountVue(/* my Vue code */, options))
```
Expand All @@ -103,12 +101,25 @@ beforeEach(mountVue(/* my Vue code */, options))
place to load additional libraries, polyfills and styles.

```js
const vue = '../node_modules/vue/dist/vue.js'
const polyfill = '../node_modules/mypolyfill/dist/polyfill.js'
const options = {
html: `<div id="app"></div><script src="${vue}"></script>`
html: `<div id="app"></div><script src="${polyfill}"></script>`
}
beforeEach(mountVue(/* my Vue code */, options))
```

* `vue` **[DEPRECATED]** - path or URL to the Vue library to load. By default, will
try to load `../node_modules/vue/dist/vue.js`, but you can pass your
own path or URL.

```js
const options = {
vue: 'https://unpkg.com/vue'
}
beforeEach(mountVue(/* my Vue code */, options))
```
> #### Deprecation Warning
> `vue` option has been deprecated. `node_modules/vue/dist/vue` is always used.
<a name="global-vue-extensions"/>

Expand Down
5 changes: 5 additions & 0 deletions components/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"plugins": [
"transform-object-rest-spread"
]
}
31 changes: 31 additions & 0 deletions components/Counter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<template>
<div>
Clicked: {{ count }} times, count is {{ evenOrOdd }}.<br>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="incrementIfOdd">Increment if odd</button>
<button @click="incrementAsync">Increment async</button>
<br><br>
<span>Set Count: </span>
<input type="number" :value="count" @input="set($event.target.value || 0)">
</div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
export default {
computed: {
...mapState(['count']),
...mapGetters(['evenOrOdd'])
},
methods: {
...mapMutations(['set']),
...mapActions([
'increment',
'decrement',
'incrementIfOdd',
'incrementAsync'
])
}
}
</script>
60 changes: 60 additions & 0 deletions components/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

// root state object.
// each Vuex instance is just a single state tree.
const state = {
count: 0
}

// mutations are operations that actually mutates the state.
// each mutation handler gets the entire state tree as the
// first argument, followed by additional payload arguments.
// mutations must be synchronous and can be recorded by plugins
// for debugging purposes.
const mutations = {
set (state, value) {
state.count = value
},
increment (state) {
state.count++
},
decrement (state) {
state.count--
}
}

// actions are functions that cause side effects and can involve
// asynchronous operations.
const actions = {
increment: ({ commit }) => commit('increment'),
decrement: ({ commit }) => commit('decrement'),
incrementIfOdd ({ commit, state }) {
if ((state.count + 1) % 2 === 0) {
commit('increment')
}
},
incrementAsync ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('increment')
resolve()
}, 1000)
})
}
}

// getters are functions
const getters = {
evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
}

// A Vuex instance is created by combining the state, mutations, actions,
// and getters.
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
70 changes: 70 additions & 0 deletions cypress/integration/counter-vuex-spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// testing Vuex component
// https://github.com/vuejs/vuex/tree/dev/examples/counter
import Counter from '../../components/Counter.vue'
import store from '../../components/store'
import Vuex from 'vuex'
import mountVue from '../..'

/* eslint-env mocha */
describe('Vuex Counter', () => {

// configure component
const extensions = {
plugins: [Vuex],
components: {
Counter
}
}

// define component template
const template = '<counter />'

// define count get and set helpers
const getCount = () => Cypress.vue.$store.state.count
const setCount = value => Cypress.vue.$store.commit('set', value)

// initialize a fresh Vue app before each test
beforeEach(mountVue({template, store}, {extensions}))

it('starts with zero', () => {
cy.contains('0 times')
})

it('increments the counter on click of "+"', () => {
cy.contains('button', '+').click()
cy.contains('1 times')
})

it('decrements the counter on click of "-"', () => {
cy.contains('button', '-').click()
cy.contains('0 times')
})

it('increments the counter if count is odd', () => {
setCount(3) // start with an odd number
cy.contains('odd')
cy.contains('button', 'Increment if odd').as('btn').click()
cy.contains('even')
cy.get('@btn').click()
cy.contains('even')
})

it('asynchronously increments counter', () => {
const count = getCount()
// increment mutation is delayed by 1 second
// Cypress waits 4 seconds by default
cy.contains('button', 'Increment async').click()
cy.contains(`${count + 1} times`)
})

it('count is zero when input is cleared', () => {
cy.get('input').type(`{selectall}{backspace}`)
cy.contains('0 times')
}),

it('set count via input field', () => {
const count = 42
cy.get('input').type(`{selectall}{backspace}${count}`)
cy.contains(`${count} times`)
})
})
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"generateNotes": "github-post-release"
},
"devDependencies": {
"babel-plugin-transform-object-rest-spread": "6.26.0",
"axios": "0.17.1",
"ban-sensitive-files": "1.9.2",
"css-loader": "0.28.7",
Expand All @@ -87,8 +88,8 @@
"semantic-action": "1.1.0",
"simple-commit-message": "3.3.2",
"standard": "10.0.3",
"vue": "2.5.13",
"vue-loader": "13.6.1",
"vuex": "3.0.1"
"vue-router": "3.0.1",
"vue-template-compiler": "2.5.13"
},
Expand All @@ -101,6 +102,7 @@
},
"dependencies": {
"@cypress/webpack-preprocessor": "1.1.2",
"common-tags": "1.6.0"
"common-tags": "1.6.0",
"vue": "2.5.13"
}
}
Loading

0 comments on commit 6e92cf3

Please sign in to comment.