Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Vueコンポーネントのユニットテスト
Search
hypermkt
July 07, 2017
Programming
16k
12
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Vueコンポーネントのユニットテスト
Vueコンポーネントのユニットテスト
Vue.js Tokyo v-meetup #4
https://vuejs-meetup.connpass.com/event/58071/
hypermkt
July 07, 2017
More Decks by hypermkt
See All by hypermkt
プロポーザルを書くときに 私が考えていること/what-i-think-about-when-writing-a-proposal
hypermkt
0
730
履歴 on Rails: Bitemporal Data Modelで実現する履歴管理/history-on-rails-with-bitemporal-data-model
hypermkt
1
5.1k
Sidekiqで実現する 長時間非同期処理の中断と再開 / Pausing and Resuming Long-Running Asynchronous Jobs with Sidekiq
hypermkt
8
6.9k
脆弱性から学ぶ Webセキュリティ Part2/study-web-security-from-vulnerability2
hypermkt
5
3.6k
脆弱性から学ぶ Webセキュリティ/study-web-security-from-vulnerability1
hypermkt
5
2.7k
モバイルアプリ向けAPI 開発を通じて学んだこと / learned-from-developing-mobile-app-api
hypermkt
3
5k
Passportのパスワードグラントで独自の認証を実装する方法 / how-to-implement-original-authentication-for-passport-password-grant
hypermkt
1
870
Webpackで作る Vueコンポーネント開発環境 / Creating the Vue component development with Webpack.
hypermkt
3
4.4k
あの問題解きました! / solved the code
hypermkt
0
380
Other Decks in Programming
See All in Programming
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
3
340
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
160
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
1
150
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
120
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
180
【DroidKaigi 2026】「アクセシビリティを利用するとき、 アクセシビリティもまたこちらを利用している」 〜マルウェアによる攻撃と防衛について〜
halunoyo
0
460
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
310
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
390
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
150
Intent as Code
shoppingjaws
6
1k
モバイル交通系ICへのチャージ実例から考える、クロスプラットフォーム開発におけるiOS実機テスト設計とCI運用
yusuga
1
470
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
350
Featured
See All Featured
Six Lessons from altMBA
skipperchong
29
4.5k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
330
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
590
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
420
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
240
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.2k
Everyday Curiosity
cassininazir
0
320
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
320
Collaborative Software Design: How to facilitate domain modelling decisions
baasie
1
320
The Curious Case for Waylosing
cassininazir
1
510
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
520
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[Λ͏ͷ༗ Γɻ