How to test Vue components effectively with Jest and vue-test-utils.
Testing Vue componentswith Jest and vue-test-utils@ryohashimoto
View Slide
ࠓճ͓͢͠Δ͜ͱ• 2िؒ΄ͲલʹɺVue.jsΛϑϩϯτΤϯυͰͬͨRuby on RailsͷϓϩδΣΫτͰɺJestͱvue-test-utilsΛಋೖɻ• ؆୯ʹVueίϯϙʔωϯτͷ୯ମςετ͕ॻ͚ΔΑ͏ʹͳͬͯɺΧόϨοδऔΕΔΑ͏ʹͳͬͨɻ
ͳͥɺVueίϯϙʔωϯτͷ ςετΛߦ͏͔ʁ
Why?• ֤ίϯϙʔωϯτ͕ࢦఆ͞Εͨঢ়ଶͰਖ਼͘͠ಈ͘͜ͱΛอূ͢ΔͨΊʢϢχοτςετʣ• खಈςετͷ߹ͷखؒʢϒϥβͷૢ࡞ʣΛল͖ɺCIͰ࣮ߦՄೳʹ͢ΔͨΊ• কདྷతͳVue.jsͷΞοϓάϨʔυʹඋ͑ΔͨΊ
Vue.jsΞϓϦέʔγϣϯͷ ߏཁૉ
Vueίϯϙʔωϯτ• HTMLςϯϓϨʔτ+Vue.jsίʔυ• ΧϓηϧԽ͞Εͨ࠶ར༻Մೳͳίʔυ• ୯ҰϑΝΠϧίϯϙʔωϯτ(.vue֦ுࢠ)Λ༻Ͱ͖Δ• Έ߹ΘͤΔ͜ͱͰΞϓϦέʔγϣϯΛߏ
Vueίϯϙʔωϯτͷྫ{{ greeting }} World!<br/>module.exports = {<br/>data () {<br/>return {<br/>greeting: 'Hello'<br/>}<br/>}<br/>}<br/>JavaScript (ES6)HTML
Vuex ετΞ• ΞϓϦέʔγϣϯͷঢ়ଶʢεςʔτʣΛҰݩอ࣋͢Δ• ঢ়ଶͷมԽϛϡʔςʔγϣϯͷίϛοτʹΑͬͯߦ͏• ίϯϙʔωϯτຖʹঢ়ଶΛ࣋ͨͳͯ͘ࡁΉ (ύϥϝʔλͷड͚͕͠ෆཁʹͳΔ)
Vuex ετΞͷྫconst store = new Vuex.Store({state: {count: 0},mutations: {increment (state) {state.count++}}})εςʔτ ύϥϝʔλϛϡʔςʔγϣϯ ૢ࡞
Vueίϯϙʔωϯτͷςετ
લఏɿ୯ମςετͷ3-A• Arrange (४උ) ॳظԽ͠ɺσʔλΛ४උ͢Δ• Act (࣮ߦ) ςετରͱͳΔॲཧΛ࣮ߦ͢Δ• Assert (ݕূ) ༧ଌ௨Γʹಈ࡞͢Δ͜ͱΛݕূ͢Δ
Vueίϯϙʔωϯτͷ3A (1)Vue componentVuex state HTML• Vueίϯϙʔωϯτʹ VuexεςʔτΛೖྗͱͯ͠༩͑Δ͜ͱͰɺHTMLΛग़ྗ͢Δ• Arrange: VuexεςʔτɺAct: VueίϯϙʔωϯτɺAssert: HTML
Vueίϯϙʔωϯτͷ3A (2)Vue componentVuex state HTMLEvent• ΠϕϯτΛ༩͑ͨ߹ʢΫϦοΫͳͲʣ• Arrange: Vuexεςʔτ, Act: Πϕϯτ / Vueίϯϙʔωϯτ, Assert: HTML / Vuexεςʔτ
Vueίϯϙʔωϯτͷςετཁ݅• Vue ίϯϙʔωϯτ୯ମͰςετ͕Ͱ͖Δ• VuexετΞɺΠϕϯτͳͲΛਖ਼͘͠ѻ͑Δ• πʔϧͷಋೖ͕؆୯ͰɺΧόϨοδऔΕΔ• Jest ͱ vue-test-utilsͳΒશ͕ͯՄೳʂ
ςετͷπʔϧ (Jest / vue-test-utils)
Jest• JavaScriptͷςετϑϨʔϜϫʔΫ ʢFacebook, ReactYarnͳͲͰར༻)• ΦʔϧΠϯϫϯͰɺগͳ͍ઃఆͰར༻Ͱ͖Δ• ؆୯ʹΧόϨοδΛऔಘͰ͖Δ• Vue.jsͰͪΖΜར༻͕Մೳ
Jestͷίʔυྫ// sum.jsfunction sum(a, b) {return a + b}module.exports = sum// sum.test.jsimport sum from './sum'test('adds 1 + 2 to equal 3', () => {expect(sum(1, 2)).toBe(3)});
vue-test-utils• Vue.js͚ͷެࣜ୯ମςετϥΠϒϥϦ• VueίϯϙʔωϯτΛִͯ͠Ϛϯτͯ͠ಈ࡞ͤ͞ɺςετΛߦ͏͜ͱ͕Ͱ͖Δ• JestΛͬͨςετͷެࣜυΩϡϝϯτ͋Γ(https://vue-test-utils.vuejs.org/ja/guides/testing-SFCs-with-jest.html)
wrapper (vue-test-utils)• ίϯϙʔωϯτͱԾ DOM Λςετ͢ΔϝιουΛؚΉΦϒδΣΫτ• mount / shallowϝιουͰίϯϙʔωϯτΛࢦఆͯ͠ɺॳظԽ͢Δ• wrapper.findͰDOMΤϨϝϯτΛࢦఆͯ͠ɺtriggerͰΠϕϯτΛൃՐͤ͞Δ͜ͱ͕Մೳ
vue-test-utilsΛ༻͍ͨྫtest('close the app', () => {// Arrangeconst wrapper = shallow(TriggerButton)// Actwrapper.find('.close').trigger('click')// Assertexpect(store.state.closed).toBe(true)})
Jestͱvue-test-utilsͷϓϩδΣΫτͷಋೖ
ύοέʔδͷΠϯετʔϧ• yarn add @vue/test-utils jest vue-jest babel-jest jest-serializer-vue --dev• jest.config.jsʹઃఆϑΝΠϧΛՃ• Rails 5.1ͷϓϩδΣΫτͰWebpackerΛ༻͍ͯ͠ΔͷͰɺ༰қʹಋೖͰ͖ͨɻ
jest.config.jsmodule.exports = {"moduleFileExtensions": ["js", "json", "vue"],"moduleNameMapper": {"^@/(.*)$": "/app/javascript/$1"},"transform": {".*\\.(vue)$": "/node_modules/vue-jest","^.+\\.js$": "/node_modules/babel-jest"},"snapshotSerializers": ["/node_modules/jest-serializer-vue"],"testRegex": "/app/javascript/test/.*\\.test\\.js$"}
·ͱΊ• Jestͱvue-test-utilsΛಋೖ͢Εɺ؆୯ʹVue.jsίϯϙʔωϯτͷ୯ମςετΛॻ͘͜ͱ͕Ͱ͖Δɻ• ϑϩϯτΤϯυͷςετίʔυͲΜͲΜॻ͍͍͖ͯ·͠ΐ͏ɻ