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
おもらし Resolve
Search
Ryotaro Ko
November 01, 2019
Programming
770
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
おもらし Resolve
Retty Engineer Meetup#1 (
https://retty.connpass.com/event/152101/
) で話した LT の公開用スライドです。
Ryotaro Ko
November 01, 2019
More Decks by Ryotaro Ko
See All by Ryotaro Ko
タイ語のサジェストを日本人の俺が頑張った道のり
pikatenor
0
160
Other Decks in Programming
See All in Programming
AI 時代のソフトウェア設計の学び方
masuda220
PRO
29
12k
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
250
今さら聞けないCancellationToken
htkym
0
220
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
3.4k
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
500
決定論的オーケストレーションの設計と実装 / Design and Implementation of Deterministic Orchestration
nrslib
3
1.1k
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
2.8k
Technical Debt: Understanding it Rightly, Engaging it Rightly #LaravelLiveJP
shogogg
0
190
正しくソフトウェアを作る、前提を疑うための認知の視点 / doubt-premise
minodriven
17
5.9k
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
1
170
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
120
軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring
macha64
0
450
Featured
See All Featured
What's in a price? How to price your products and services
michaelherold
247
13k
Into the Great Unknown - MozCon
thekraken
41
2.5k
How Fast Is Fast Enough? [PerfNow 2025]
tammyeverts
3
600
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Rails Girls Zürich Keynote
gr2m
96
14k
Un-Boring Meetings
codingconduct
0
310
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
150
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Designing for Performance
lara
611
70k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
Transcript
+4ςετςΫχοΫ CZ3ZPUBSP,P!QJLBUFOPS ʙ͓Β͠1SPNJTFͷճʙ
͜Ε3FUUZ&OHJOFFS.FFUVQͰͨ͠-5ͷެ։༻ࢿྉͰ͢ IUUQTSFUUZDPOOQBTTDPNFWFOU
͓લ୭ͩ 3FUUZגࣜձࣾ8FCݕࡧνʔϜΤϯδχΞ 3ZPUBSP,P *%େମ!QJLBUFOPS େֶଔۀޙೖࣾ ۀྖҬ όοΫΤϯυ ݕࡧ࣭վળ &MBTUJDTFBSDIͷ͓कΓ
Πϯϑϥख͍ 0ODBMM
͜Μͳςετ "XFTPNFͳϑΥʔϜ ૹ৴ ॲཧͷྲྀΕ
͜Μͳςετ ϐΧνϡ ૹ৴ ॲཧͷྲྀΕ
͜Μͳςετ ϐΧνϡ ૹ৴ ॲཧͷྲྀΕ ೖྗྃޙɺૹ৴ϘλϯΛԡ͢ ˣ
͜Μͳςετ ϐΧνϡ ૹ৴ ॲཧͷྲྀΕ ೖྗྃޙɺૹ৴ϘλϯΛԡ͢ ˣ Ϙλϯ͕άϨʔΞτ͢Δ<BUUSEJTBCMFE> ˣ
͜Μͳςετ ϐΧνϡ ૹ৴ ॲཧͷྲྀΕ ೖྗྃޙɺૹ৴ϘλϯΛԡ͢ ˣ Ϙλϯ͕άϨʔΞτ͢Δ<BUUSEJTBCMFE> ˣ "1*௨৴ ˣ
"1*αʔόʔ
͜Μͳςετ ϐΧνϡ ૹ৴ ॲཧͷྲྀΕ ೖྗྃޙɺૹ৴ϘλϯΛԡ͢ ˣ Ϙλϯ͕άϨʔΞτ͢Δ<BUUSEJTBCMFE> ˣ "1*௨৴ ˣ
ྃͨ͠Βݩʹ͢<BUUS> "1*αʔόʔ
͜Μͳςετ ϐΧνϡ ૹ৴ ॲཧͷྲྀΕ ೖྗྃޙɺૹ৴ϘλϯΛԡ͢ ˣ Ϙλϯ͕άϨʔΞτ͢Δ<BUUSEJTBCMFE> ˣ "1*௨৴ ˣ
ྃͨ͠Βݩʹ͢<BUUS> "1*αʔόʔ ૹ৴Ϙλϯ͕ԡ͞Ε͔ͯΒ௨৴ྃ·Ͱ disabledͰ͋Δ͜ͱΛςετ͍ͨ͠
ίϯϙʔωϯτͷίʔυྫ <template> <form> <input v-model="name" placeholder="Awesome Form"/> <button type="submit" :disabled="loading">ૹ৴</button>
</form> </template> <script> import { callAPI } from 'API௨৴͢Δͭ'; export default { data() { return { name: '', loading: false, }; }, methods: { async onSubmit() { this.loading = true; try { await callAPI(this.name); this.$emit('success'); } catch (error) { // ͳΜ͔Δ } finally { this.loading = false; } }, }, }; </script>
ίϯϙʔωϯτͷίʔυྫ <template> <form> <input v-model="name" placeholder="Awesome Form"/> <button type="submit" :disabled="loading">ૹ৴</button>
</form> </template> <script> import { callAPI } from 'API௨৴͢Δͭ'; export default { data() { return { name: '', loading: false, }; }, methods: { async onSubmit() { this.loading = true; try { await callAPI(this.name); this.$emit('success'); } catch (error) { // ͳΜ͔Δ } finally { this.loading = false; } }, }, }; </script> BTZODBXBJU
Γ͍ͨςετ describe('onSubmit', () => { it('activates loading flag when form
submitted', () => { // before submit expect(wrapper.vm.loading).toBe(false); // waiting API call expect(wrapper.vm.loading).toBe(true); // after submission completed expect(wrapper.vm.loading).toBe(false); }); });
Γ͍ͨςετ describe('onSubmit', () => { it('activates loading flag when form
submitted', () => { // before submit expect(wrapper.vm.loading).toBe(false); // waiting API call expect(wrapper.vm.loading).toBe(true); // after submission completed expect(wrapper.vm.loading).toBe(false); }); }); ͜͜Ͳ͏͢Μͷ
ωλΒ͠ ͓Β͠1SPNJTF1SPNJTFͷSFTPMWFϋϯυϥͷείʔϓΛ֎ʹ࿙Β͢ 3FTPMWF
1SPNJTFSFTPMWF
Promise.resolve(value) • valueͰ3FTPMWF͞ΕͨPromiseΛฦ͢ • ͭ·Γ͜͏ function rizorubu(value) { return new
Promise(function(resolve){ resolve(value); }) } 1SPNJTFSFTPMWF
function rizorubu(value) { return new Promise(function(resolve){ resolve(value); }) }
let leakedResolve; function rizorubu(value) { return new Promise(function(resolve){ leakedResolve =
resolve; }) } 3FTPMWFͷ࿙Β͔ͨ͠
let leakedResolve; function rizorubu(value) { return new Promise(function(resolve){ leakedResolve =
resolve; }) } 3FTPMWFϋϯυϥ͕ είʔϓ֎ʹ࿙ΕΔ 3FTPMWFͷ࿙Β͔ͨ͠
let leakedResolve; function rizorubu(value) { return new Promise(function(resolve){ leakedResolve =
resolve; }) } leakedResolve(Promise.resolve("poyo")); BTZODGVODUJPOrezorubu()Λ ͖ͳͱ͖ʹ3FTPMWFͰ͖Δʂ 3FTPMWFͷ࿙Β͔ͨ͠ 3FTPMWFϋϯυϥ͕ είʔϓ֎ʹ࿙ΕΔ
Γ͍ͨςετ describe('onSubmit', () => { it('activates loading flag when form
submitted', () => { // before submit expect(wrapper.vm.loading).toBe(false); // waiting API call expect(wrapper.vm.loading).toBe(true); // after submission completed expect(wrapper.vm.loading).toBe(false); }); });
ίϯϙʔωϯτͷίʔυྫ <template> <form> <input v-model="name" placeholder="Awesome Form"/> <button type="submit" :disabled="loading">ૹ৴</button>
</form> </template> <script> import { callAPI } from 'API௨৴͢Δͭ'; export default { data() { return { name: '', loading: false, }; }, methods: { async onSubmit() { this.loading = true; try { await callAPI(this.name); this.$emit('success'); } catch (error) { // ͳΜ͔Δ } finally { this.loading = false; } }, }, }; </script>
ίϯϙʔωϯτͷίʔυྫ <template> <form> <input v-model="name" placeholder="Awesome Form"/> <button type="submit" :disabled="loading">ૹ৴</button>
</form> </template> <script> import { callAPI } from 'API௨৴͢Δͭ'; export default { data() { return { name: '', loading: false, }; }, methods: { async onSubmit() { this.loading = true; try { await callAPI(this.name); this.$emit('success'); } catch (error) { // ͳΜ͔Δ } finally { this.loading = false; } }, }, }; </script>
݁ہ͜͏ͳͬͨ let apiResolve; jest.mock('API௨৴͢Δͭ', () => ({ callAPI: () =>
new Promise(resolve => { apiResolve = resolve; }), })); describe('AwesomeForm', () => { let wrapper; beforeEach(() => { wrapper = shallowMount(AwesomeForm); }); +FTUͱWVFUFTUVUJMTΛ͍ͬͯ·͢ describe('onSubmit', () => { it('activates loading flag when form submitted', async () => { // before submit expect(wrapper.vm.loading).toBe(false); const submissionPromise = wrapper.vm.onSubmit(); // waiting API call await wrapper.vm.$nextTick(); expect(wrapper.vm.loading).toBe(true); apiResolve(Promise.resolve(true)); await submissionPromise; // after submission completed expect(wrapper.vm.loading).toBe(false); }); }); });
݁ہ͜͏ͳͬͨ let apiResolve; jest.mock('API௨৴͢Δͭ', () => ({ callAPI: () =>
new Promise(resolve => { apiResolve = resolve; }), })); describe('AwesomeForm', () => { let wrapper; beforeEach(() => { wrapper = shallowMount(AwesomeForm); }); +FTUͱWVFUFTUVUJMTΛ͍ͬͯ·͢ describe('onSubmit', () => { it('activates loading flag when form submitted', async () => { // before submit expect(wrapper.vm.loading).toBe(false); const submissionPromise = wrapper.vm.onSubmit(); // waiting API call await wrapper.vm.$nextTick(); expect(wrapper.vm.loading).toBe(true); apiResolve(Promise.resolve(true)); await submissionPromise; // after submission completed expect(wrapper.vm.loading).toBe(false); }); }); }); jest.mock Ͱ Λஔ͖͑ import { callAPI } from 'API௨৴͢Δͭ';
݁ہ͜͏ͳͬͨ let apiResolve; jest.mock('API௨৴͢Δͭ', () => ({ callAPI: () =>
new Promise(resolve => { apiResolve = resolve; }), })); describe('AwesomeForm', () => { let wrapper; beforeEach(() => { wrapper = shallowMount(AwesomeForm); }); describe('onSubmit', () => { it('activates loading flag when form submitted', async () => { // before submit expect(wrapper.vm.loading).toBe(false); const submissionPromise = wrapper.vm.onSubmit(); // waiting API call await wrapper.vm.$nextTick(); expect(wrapper.vm.loading).toBe(true); apiResolve(Promise.resolve(true)); await submissionPromise; // after submission completed expect(wrapper.vm.loading).toBe(false); }); }); }); +FTUͱWVFUFTUVUJMTΛ͍ͬͯ·͢ jest.mock Ͱ Λஔ͖͑ import { callAPI } from 'API௨৴͢Δͭ'; ͓Β͠
݁ہ͜͏ͳͬͨ let apiResolve; jest.mock('API௨৴͢Δͭ', () => ({ callAPI: () =>
new Promise(resolve => { apiResolve = resolve; }), })); describe('AwesomeForm', () => { let wrapper; beforeEach(() => { wrapper = shallowMount(AwesomeForm); }); describe('onSubmit', () => { it('activates loading flag when form submitted', async () => { // before submit expect(wrapper.vm.loading).toBe(false); const submissionPromise = wrapper.vm.onSubmit(); // waiting API call await wrapper.vm.$nextTick(); expect(wrapper.vm.loading).toBe(true); apiResolve(Promise.resolve(true)); await submissionPromise; // after submission completed expect(wrapper.vm.loading).toBe(false); }); }); }); +FTUͱWVFUFTUVUJMTΛ͍ͬͯ·͢ MPBEJOHUSVF Λݕূͯ͠3FTPMWF ΦέΦέΦοέʔ
Promise.reject(reason) • reasonʹΑΓ3FKFDU͞ΕͨPromiseΛฦ͢ • ɹɹ Έ͍ͨʹॻ͘͜ͱͰΤϥʔ࣌ͷςετͰ͖·͢ 1SPNJTFSFKFDU leakedResolve(Promise.reject(new Error("something happened")))
References: Mozilla. "Promise.reject()". MDN Web docs. 2019/3/23. https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject Mozilla. "Promise.resolve()".
MDN Web docs. 2019/3/18. https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve azu. "Javascript Promise ͷຊ". Ver 1.6.5. https://azu.github.io/promises-book/