Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Vueコンポーネントのユニットテスト
Search
hypermkt
July 07, 2017
Programming
12
16k
Vueコンポーネントのユニットテスト
Vueコンポーネントのユニットテスト
Vue.js Tokyo v-meetup #4
https://vuejs-meetup.connpass.com/event/58071/
hypermkt
July 07, 2017
Tweet
Share
More Decks by hypermkt
See All by hypermkt
プロポーザルを書くときに 私が考えていること/what-i-think-about-when-writing-a-proposal
hypermkt
0
530
履歴 on Rails: Bitemporal Data Modelで実現する履歴管理/history-on-rails-with-bitemporal-data-model
hypermkt
1
3.9k
Sidekiqで実現する 長時間非同期処理の中断と再開 / Pausing and Resuming Long-Running Asynchronous Jobs with Sidekiq
hypermkt
8
6.5k
脆弱性から学ぶ Webセキュリティ Part2/study-web-security-from-vulnerability2
hypermkt
5
3.5k
脆弱性から学ぶ Webセキュリティ/study-web-security-from-vulnerability1
hypermkt
5
2.6k
モバイルアプリ向けAPI 開発を通じて学んだこと / learned-from-developing-mobile-app-api
hypermkt
3
4.8k
Passportのパスワードグラントで独自の認証を実装する方法 / how-to-implement-original-authentication-for-passport-password-grant
hypermkt
1
840
Webpackで作る Vueコンポーネント開発環境 / Creating the Vue component development with Webpack.
hypermkt
3
4.3k
あの問題解きました! / solved the code
hypermkt
0
360
Other Decks in Programming
See All in Programming
Fundamentals of Software Engineering In the Age of AI
therealdanvega
2
300
PHP でエミュレータを自作して Ubuntu を動かそう
m3m0r7
PRO
2
150
Mastering Event Sourcing: Your Parents Holidayed in Yugoslavia
super_marek
0
120
見せてもらおうか、 OpenSearchの性能とやらを!
shunta27
1
150
Codex CLIのSubagentsによる並列API実装 / Parallel API Implementation with Codex CLI Subagents
takatty
2
630
[PHPerKaigi 2026]PHPerKaigi2025の企画CodeGolfが最高すぎて社内で内製して半年運営して得た内製と運営の知見
ikezoemakoto
0
290
Angular-Apps smarter machen mit Gen AI: Lokal und offlinefähig - Hands-on Workshop!
christianliebel
PRO
0
140
Coding at the Speed of Thought: The New Era of Symfony Docker
dunglas
0
1.5k
Geminiをパートナーに神社DXシステムを個人開発した話(いなめぐDX 開発振り返り)
fujiba
0
120
へんな働き方
yusukebe
6
2.8k
Vuetify 3 → 4 何が変わった?差分と移行ポイント10分まとめ
koukimiura
0
200
Feature Toggle は捨てやすく使おう
gennei
0
370
Featured
See All Featured
Leading Effective Engineering Teams in the AI Era
addyosmani
9
1.8k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
118
110k
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
120
Conquering PDFs: document understanding beyond plain text
inesmontani
PRO
4
2.5k
Highjacked: Video Game Concept Design
rkendrick25
PRO
1
330
What does AI have to do with Human Rights?
axbom
PRO
1
2.1k
Everyday Curiosity
cassininazir
0
180
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
680
Large-scale JavaScript Application Architecture
addyosmani
515
110k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
91
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
300
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
420
Transcript
όʔνʔ(.01&1"#0JOD 7VFKT.FFUVQ 7VFίϯϙʔωϯτͷ Ϣχοτςετ
ιϑτΣΞΤϯδχΞ <b1)1FS` b7VFKT` b3BJMT`> Ξχϝ෦෦ όʔνʔ!IZQFSNLU IUUQCMPHIZQFSNLUKQ
7VFίϯϙʔωϯτͷ Ϣχοτςετ
ຊͷରऀ wओʹ7VFίϯϙʔωϯτͷςετΛॻ͍͍ͯΔਓ wࠓޙ7VFίϯϙʔωϯτͷςετΛॻ͖͍ͨਓ
ίϯϙʔωϯτͷςετͰͪΐͬͱࠔΔγʔϯᶃ it('จࣈྻ͕ೖྗ͞ΕͨΒɺAPI͕1ճݺΕΔ', () => { stub = sinon.stub(api, 'checkAccount') const
Constructor = Vue.extend(Event) const vm = new Constructor().$mount() const input = vm.$el.querySelector('input') const event = document.createEvent('HTMLEvents') event.initEvent('input', true, true) input.dispatchEvent(event) expect(stub.calledOnce).to.be.true }) <template> <div> Account: <input type="text" @input="checkAccount" > </div> </template> <script> import api from '../libs/api' export default { data () { return { msg: '' } }, methods: { checkAccount: () => { api.checkAccount() } } } </script> ίϯϙʔωϯτ ςετέʔε จࣈྻೖྗ͞ΕͨΒ"1*ͰνΣοΫ͢Δ JOQVUΠϕϯτΛൃੜͤ͞Δͷ͕खؒɾɾɾ
ίϯϙʔωϯτͷςετͰͪΐͬͱࠔΔγʔϯᶄ <template> <div> <p>{{ msg }}</p> <child></child> </div> </template> <script>
import Child from './Child.vue export default { components: { 'child': Child }, data () { return { msg: ‘Hello World' } } } </script> ࢠίϯϙʔωϯτͰ)551ܦ༝ͷ "1*ΛݺΜͰ͍Δɻ ͜ͷίϯϙʔωϯτͷςετͷΈʹ ूத͍ͨ͠ͷʹɺࢠίϯϙʔωϯτ ͕अຐͰςετ͕ͮ͠Β͍ɻ
ͬͱ؆୯ʹ7VFίϯϙʔωϯτͷ ςετ͕ॻ͚ͳ͍ͷ͔ʁ
7VFKT༻ςετϥΠϒϥϦͩʂ
୳ͨ͠Βͨ͘͞Μ͋ͬͨ wWVFUFTU wBWPSJB[ wWVFVOJU wWVFUFTUJOH wSFWVF wWVFOJU
ొͨ࣌͠ظ͍͍ͩͨಉ͡ wWVFUFTU wBWPSJB[ wWVFVOJU wWVFUFTUJOH wSFWVF wWVFOJU
ػೳ͍͍ͩͨಉ͡ w4IBMMPX'VMM3FOEFSJOH w%0.&WFOU5SJHHFS w7VFY 3PVUFS )551ͷϞοΫελϒ w"TTFSUJPO w%0.4FMFDUPS
ެࣜͷςετϥΠϒϥϦ͕ ແ͍ͩΖ͏͔ʁ
IUUQTGPSVNWVFKTPSHUJTBOZUIJOHCFJOHEPOFJODPSFWVFUPNBLFVOJUUFTUJOHFBTJFS
WVFUFTUVUJMTͷొ
WVFUFTUVUJMTͷݱঢ় wBWPSJB[։ൃऀͷ!FEEZFSCVSHIࢯ͕ϝΠϯͰ։ൃத wWVFUFTU SFWVF WVFVOJU WVFOJUͷ։ൃ͕ҙݟΛग़ ͠߹͍ w։ൃऴ൫ɻॳظ50%0ͷׂྃ wݱࡏυΩϡϝϯτ४උத wۙʑЌ൛͕ϦϦʔε͞Εͦ͏ͳ༧ײ
࣌
WVFUFTUVUJMT ·ͩЌ൛͢ΒϦϦʔε͞Ε͍ͯͳ͍Ͱ ݱঢ়Ͱਂ͘͏ͷ࣌ظঘૣ
WVFUFTUVUJMTBWPSJB[Λ౿ऻͯ͠։ൃ͞Ε͍ͯΔɻ BWPSJB[ΛΔ͜ͱͰWVFUFTUVUJMTΛઌऔΓ͠Α͏ʂ
BWPSJB[ B7VFKTUFTUJOHVUJMJUZMJCSBSZ IUUQTHJUIVCDPNFEEZFSCVSHIBWPSJB[
BWPSJB[ͷػೳ wK2VFSZϥΠΫͳηϨΫλʔ w%0.ΠϕϯττϦΨʔ w4IBMMPX 'VMMϨϯμϦϯά
BWPSJB[ͷྑ͍ͱ͜Ζ wγϯϓϧͳ"1* wυΩϡϝϯτ͕๛ w֤ςετϥΠϒϥϦผͷαϯϓϧίʔυ๛
$PNQPOFOUͷςετख๏ w*TPMBUFE5FTUJOH w $PNQPOFOUͷϩδοΫͷΈΛςετ͢Δ w4IBMMPX5FTUJOH w ࢠίϯϙʔωϯτϨϯμϦϯάͤͣɺࣗͷ$PNQPOFOUͷΈΛϨϯμϦϯάͯ͠ςε τ͢Δ w*OUFHSBUJPO5FTUJOH w
ࢠίϯϙʔωϯτશͯϨϯμϦϯάͯ͠ςετ͢Δ w&WFOU5FTUJOH w %0.ΠϕϯτΛൃੜͤ͞ɺఆ͢ΔڍಈΛ͢Δ͔ςετ͢Δ
$PNQPOFOUͷςετख๏ w*TPMBUFE5FTUJOH w $PNQPOFOUͷϩδοΫͷΈΛςετ͢Δ w4IBMMPX5FTUJOH w ࢠίϯϙʔωϯτϨϯμϦϯάͤͣɺࣗͷ$PNQPOFOUͷΈΛϨϯμϦϯάͯ͠ςε τ͢Δ w*OUFHSBUJPO5FTUJOH w
ࢠίϯϙʔωϯτશͯϨϯμϦϯάͯ͠ςετ͢Δ w&WFOU5FTUJOH w %0.ΠϕϯτΛൃੜͤ͞ɺఆ͢ΔڍಈΛ͢Δ͔ςετ͢Δ
4IBMMPXϨϯμϦϯά
՝ <template> <div> <p>{{ msg }}</p> <child></child> </div> </template> <script>
import Child from './Child.vue export default { components: { 'child': Child }, data () { return { msg: ‘Hello World' } } } </script> ࢠίϯϙʔωϯτͰ)551ܦ༝ͷ "1*ΛݺΜͰ͍Δɻ ͜ͷίϯϙʔωϯτͷςετͷΈʹ ूத͍ͨ͠ͷʹɺࢠίϯϙʔωϯτ ͕अຐͰςετ͕ͮ͠Β͍ɻ
ղܾ๏ɿ4IBMMPXϨϯμϦϯάΛར༻͢Δ w4IBMMPXϨϯμϦϯάͱɺࢠίϯϙʔωϯτΛల։ ͤͣʹϨϯμϦϯά͢Δ͜ͱ wBWPSJB[ͰTIBMMPXػೳΛར༻͢Δ͜ͱͰɺશͯͷࢠ ίϯϙʔωϯτΛελϒ ʹͳΔʣͯ͠ɺϨϯμ Ϧϯάͨ͠ϥούʔΦϒδΣΫτΛฦ͢
<template> <div> <p>{{ msg }}</p> <child></child> </div> </template> <script> import
Child from './Child.vue export default { components: { 'child': Child }, data () { return { msg: ‘Hello World' } } } </script> import Welcome from ‘../../src/components/Welcome.vue’ import { shallow } from 'avoriaz' describe('avoriaz༗Γͷςετέʔε', () => { it('Pλά͕ਖ਼ৗʹϨϯμϦϯά͞Ε͍ͯΔ͔', () => { const wrapper = shallow(Welcome) expect(wrapper.find(‘p')[0].text()).to.be.eql('Hello World') }) }) ίϯϙʔωϯτ ςετέʔε TIBMMPXΛ༻ͨ͠ςετέʔε
͜ΕͰςετ͍ͨ͠ίϯϙʔωϯτ ͚ͩʹूதͰ͖Δʂʂ
*OUFHSBUJPO5FTU
՝ <template> <div> <p>{{ msg }}</p> <child></child> </div> </template> <script>
import Child from './Child.vue export default { components: { 'child': Child }, data () { return { msg: ‘Hello World' } } } </script> ࢠίϯϙʔωϯτؚΊͯը໘શମ ͕ਖ਼ৗʹϨϯμϦϯά͞Ε͍ͯΔͷ Λ֬ೝ͍ͨ͠ɻ
ղܾ๏ɿ'VMMϨϯμϦϯάΛར༻͢Δ w'VMMϨϯμϦϯάͱɺίϯϙʔωϯτશମΛϨϯμ Ϧϯά͢Δ wBWPSJB[ͰNPVOUػೳΛར༻͢Δ͜ͱͰɺ'VMMϨϯ μϦϯά͞ΕͨϥούʔΦϒδΣΫτΛऔಘͰ͖Δ
<template> <div> <p>{{ msg }}</p> <child></child> </div> </template> <script> import
Child from './Child.vue export default { components: { 'child': Child }, data () { return { msg: ‘Hello World' } } } </script> import Welcome from ‘../../src/components/Welcome.vue’ import { mount } from 'avoriaz' describe('avoriaz༗Γͷςετέʔε', () => { it('Pλά͕ਖ਼ৗʹϨϯμϦϯά͞Ε͍ͯΔ͔', () => { // mount: ϑϧϨϯμϦϯά͞ΕͨίϯϙʔωϯτͷϥούʔΦϒδΣΫτΛฦ͢ const wrapper = mount(Welcome) // find: DOMͷྻΛฦ͢ // text: ϥούʔΦϒδΣΫτͷจࣈྻίϯςϯπΛฦ͢ expect(wrapper.find(‘p')[0].text()).to.be.eql('Hello World') }) }) ίϯϙʔωϯτ ςετέʔε NPVOUΛར༻ͨ͠ςετέʔε
&WFOU5FTUJOH
՝ it('จࣈྻ͕ೖྗ͞ΕͨΒɺAPI͕1ճݺΕΔ', () => { stub = sinon.stub(api, 'checkAccount') const
Constructor = Vue.extend(Event) const vm = new Constructor().$mount() const input = vm.$el.querySelector('input') const event = document.createEvent('HTMLEvents') event.initEvent('input', true, true) input.dispatchEvent(event) expect(stub.calledOnce).to.be.true }) <template> <div> Account: <input type="text" @input="checkAccount" > </div> </template> <script> import api from '../libs/api' export default { data () { return { msg: '' } }, methods: { checkAccount: () => { api.checkAccount() } } } </script> ίϯϙʔωϯτ ςετέʔε จࣈྻೖྗ͞ΕͨΒ"1*ͰνΣοΫ͢Δ JOQVUΠϕϯτΛൃੜͤ͞Δͷ͕खؒɾɾɾ
ղܾ๏ɿUSJHHFSΛར༻͢Δ wUSJHHFS FWFOU/BNF ࢦఆͨ͠ΠϕϯτΛݺͼग़͢ ͜ͱ͕ग़དྷΔ
BWPSJB[ͩͱΠϕϯτൃੜ͕Ͱ͖Δʂ it('จࣈྻ͕ೖྗ͞ΕͨΒɺAPI͕1ճݺΕΔ', () => { stub = sinon.stub(api, 'checkAccount') const
wrapper = mount(Event) wrapper.find('input')[0].trigger('input') expect(stub.calledOnce).to.be.true })
·ͱΊ
·ͱΊ wWVFUFTUVUJMTɺ։ൃதͳͷͰࠓޙͲ͏ͳΔ͔·ͩ ͔Βͳ͍ɻ wBWPSJB[Λར༻͢Εɺ؆୯ʹίϯϙʔωϯτͷςε τ͕ॻ͚ΔΑ͏ʹͳΔɻ wBWPSJB[ͱWVFUFTUVUJMT"1*͕͍͍ͩͨಉ͡ͳͷ ͰɺΓָ͑ɻࠓ͔ΒͰBWPSJB[Λ͏ͷ༗ Γɻ