Skip to content

Commit 6e92cf3

Browse files
authored
feat: Vuex support
* 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
1 parent 79c7df0 commit 6e92cf3

File tree

7 files changed

+281
-78
lines changed

7 files changed

+281
-78
lines changed

README.md

+17-6
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,11 @@ See examples below for details.
7777
See [cypress/integration/options-spec.js](cypress/integration/options-spec.js)
7878
for examples of options.
7979

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

8482
```js
8583
const options = {
86-
vue: 'https://unpkg.com/vue'
84+
mountId: 'rootApp' // div#rootApp
8785
}
8886
beforeEach(mountVue(/* my Vue code */, options))
8987
```
@@ -103,12 +101,25 @@ beforeEach(mountVue(/* my Vue code */, options))
103101
place to load additional libraries, polyfills and styles.
104102

105103
```js
106-
const vue = '../node_modules/vue/dist/vue.js'
104+
const polyfill = '../node_modules/mypolyfill/dist/polyfill.js'
107105
const options = {
108-
html: `<div id="app"></div><script src="${vue}"></script>`
106+
html: `<div id="app"></div><script src="${polyfill}"></script>`
107+
}
108+
beforeEach(mountVue(/* my Vue code */, options))
109+
```
110+
111+
* `vue` **[DEPRECATED]** - path or URL to the Vue library to load. By default, will
112+
try to load `../node_modules/vue/dist/vue.js`, but you can pass your
113+
own path or URL.
114+
115+
```js
116+
const options = {
117+
vue: 'https://unpkg.com/vue'
109118
}
110119
beforeEach(mountVue(/* my Vue code */, options))
111120
```
121+
> #### Deprecation Warning
122+
> `vue` option has been deprecated. `node_modules/vue/dist/vue` is always used.
112123
113124
<a name="global-vue-extensions"/>
114125

components/.babelrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"plugins": [
3+
"transform-object-rest-spread"
4+
]
5+
}

components/Counter.vue

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<template>
2+
<div>
3+
Clicked: {{ count }} times, count is {{ evenOrOdd }}.<br>
4+
<button @click="increment">+</button>
5+
<button @click="decrement">-</button>
6+
<button @click="incrementIfOdd">Increment if odd</button>
7+
<button @click="incrementAsync">Increment async</button>
8+
<br><br>
9+
<span>Set Count: </span>
10+
<input type="number" :value="count" @input="set($event.target.value || 0)">
11+
</div>
12+
</template>
13+
14+
<script>
15+
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
16+
export default {
17+
computed: {
18+
...mapState(['count']),
19+
...mapGetters(['evenOrOdd'])
20+
},
21+
methods: {
22+
...mapMutations(['set']),
23+
...mapActions([
24+
'increment',
25+
'decrement',
26+
'incrementIfOdd',
27+
'incrementAsync'
28+
])
29+
}
30+
}
31+
</script>

components/store.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import Vue from 'vue'
2+
import Vuex from 'vuex'
3+
Vue.use(Vuex)
4+
5+
// root state object.
6+
// each Vuex instance is just a single state tree.
7+
const state = {
8+
count: 0
9+
}
10+
11+
// mutations are operations that actually mutates the state.
12+
// each mutation handler gets the entire state tree as the
13+
// first argument, followed by additional payload arguments.
14+
// mutations must be synchronous and can be recorded by plugins
15+
// for debugging purposes.
16+
const mutations = {
17+
set (state, value) {
18+
state.count = value
19+
},
20+
increment (state) {
21+
state.count++
22+
},
23+
decrement (state) {
24+
state.count--
25+
}
26+
}
27+
28+
// actions are functions that cause side effects and can involve
29+
// asynchronous operations.
30+
const actions = {
31+
increment: ({ commit }) => commit('increment'),
32+
decrement: ({ commit }) => commit('decrement'),
33+
incrementIfOdd ({ commit, state }) {
34+
if ((state.count + 1) % 2 === 0) {
35+
commit('increment')
36+
}
37+
},
38+
incrementAsync ({ commit }) {
39+
return new Promise((resolve, reject) => {
40+
setTimeout(() => {
41+
commit('increment')
42+
resolve()
43+
}, 1000)
44+
})
45+
}
46+
}
47+
48+
// getters are functions
49+
const getters = {
50+
evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd'
51+
}
52+
53+
// A Vuex instance is created by combining the state, mutations, actions,
54+
// and getters.
55+
export default new Vuex.Store({
56+
state,
57+
getters,
58+
actions,
59+
mutations
60+
})
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// testing Vuex component
2+
// https://github.com/vuejs/vuex/tree/dev/examples/counter
3+
import Counter from '../../components/Counter.vue'
4+
import store from '../../components/store'
5+
import Vuex from 'vuex'
6+
import mountVue from '../..'
7+
8+
/* eslint-env mocha */
9+
describe('Vuex Counter', () => {
10+
11+
// configure component
12+
const extensions = {
13+
plugins: [Vuex],
14+
components: {
15+
Counter
16+
}
17+
}
18+
19+
// define component template
20+
const template = '<counter />'
21+
22+
// define count get and set helpers
23+
const getCount = () => Cypress.vue.$store.state.count
24+
const setCount = value => Cypress.vue.$store.commit('set', value)
25+
26+
// initialize a fresh Vue app before each test
27+
beforeEach(mountVue({template, store}, {extensions}))
28+
29+
it('starts with zero', () => {
30+
cy.contains('0 times')
31+
})
32+
33+
it('increments the counter on click of "+"', () => {
34+
cy.contains('button', '+').click()
35+
cy.contains('1 times')
36+
})
37+
38+
it('decrements the counter on click of "-"', () => {
39+
cy.contains('button', '-').click()
40+
cy.contains('0 times')
41+
})
42+
43+
it('increments the counter if count is odd', () => {
44+
setCount(3) // start with an odd number
45+
cy.contains('odd')
46+
cy.contains('button', 'Increment if odd').as('btn').click()
47+
cy.contains('even')
48+
cy.get('@btn').click()
49+
cy.contains('even')
50+
})
51+
52+
it('asynchronously increments counter', () => {
53+
const count = getCount()
54+
// increment mutation is delayed by 1 second
55+
// Cypress waits 4 seconds by default
56+
cy.contains('button', 'Increment async').click()
57+
cy.contains(`${count + 1} times`)
58+
})
59+
60+
it('count is zero when input is cleared', () => {
61+
cy.get('input').type(`{selectall}{backspace}`)
62+
cy.contains('0 times')
63+
}),
64+
65+
it('set count via input field', () => {
66+
const count = 42
67+
cy.get('input').type(`{selectall}{backspace}${count}`)
68+
cy.contains(`${count} times`)
69+
})
70+
})

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"generateNotes": "github-post-release"
7272
},
7373
"devDependencies": {
74+
"babel-plugin-transform-object-rest-spread": "6.26.0",
7475
"axios": "0.17.1",
7576
"ban-sensitive-files": "1.9.2",
7677
"css-loader": "0.28.7",
@@ -87,8 +88,8 @@
8788
"semantic-action": "1.1.0",
8889
"simple-commit-message": "3.3.2",
8990
"standard": "10.0.3",
90-
"vue": "2.5.13",
9191
"vue-loader": "13.6.1",
92+
"vuex": "3.0.1"
9293
"vue-router": "3.0.1",
9394
"vue-template-compiler": "2.5.13"
9495
},
@@ -101,6 +102,7 @@
101102
},
102103
"dependencies": {
103104
"@cypress/webpack-preprocessor": "1.1.2",
104-
"common-tags": "1.6.0"
105+
"common-tags": "1.6.0",
106+
"vue": "2.5.13"
105107
}
106108
}

0 commit comments

Comments
 (0)