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
karmaを使ったSPA向けE2Eテスト技法
Search
kyo_ago
February 27, 2017
Programming
5.7k
6
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
karmaを使ったSPA向けE2Eテスト技法
kyo_ago
February 27, 2017
More Decks by kyo_ago
See All by kyo_ago
フロントエンドの リソース管理の話 TechFeed Summit#1 #techfeed #techfeedsummit
kyo_ago
5
2k
TypeScriptでType Match的なことをする話 #すえなみチャンス暑気払い
kyo_ago
1
1.4k
WebReplayから見るWeb開発の未来 #builderscon
kyo_ago
2
1k
今日から始めるbugbounty
kyo_ago
0
320
E2Eという名称の指すもの
kyo_ago
0
2.7k
How to use Scala.js in real world?
kyo_ago
1
2.2k
Other Decks in Programming
See All in Programming
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
7.6k
Family mrubyの進捗
kishima
1
130
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
270
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
480
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
300
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
180
WebAssembly in Android Apps 〜 WASMはJNIの夢を見るか
keiji
1
110
仕様駆動開発による爆速プロダクト開発 / Bakusoku Spec Driven Development
kobakei
0
120
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
3k
UPDATE をやめる — EF Core でマスタをバージョン管理する
panda728
PRO
0
240
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
220
20260914 AIエージェント時代のPlatform Engineering LLM基盤とプロダクトの責務境界線
kanfab1
7
2.1k
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
55
8.3k
The SEO identity crisis: Don't let AI make you average
varn
0
560
Thoughts on Productivity
jonyablonski
76
5.4k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
290
Joys of Absence: A Defence of Solitary Play
codingconduct
1
520
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
400
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Making Projects Easy
brettharned
120
6.8k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.3k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.7k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8k
Transcript
karmaΛͬͨSPA͚ E2Eςετٕ๏
ࣗݾհ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ɾ@kyo_ago ɾChatworkͷதͷਓ ɾझຯLocal Proxy࡞ ɾUnder30͡Όͳ͍ΤϯδχΞ ɾਪ͠APIApplication Cache
·ͣँࡑ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ࠓճ௨Γ͕͍͍ͱࢥͬͯʮ&&ςετʯͬͯݴͬͯ·͕͢ *OUFHSBUJPOςετͬͯݴ͏ํ͕ਖ਼֬ͩͬͨΓ͠·͢ɻ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ࠓճ͍͑ͨ͜ͱ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
41"ͷςετʹ 8FC%SJWFS͔ͳ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
8FC%SJWFSͱ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
4FMFOJVN͔Βൃలͨ͠πʔϧ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ϒϥβ͝ͱͷυϥΠόͱ ͦͷυϥΠόͱ௨৴͢Δ"1* LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ChromeDriver FirefoxDriver IEDriver SafariDriver JSON Wire Protocol
"1*ʹରԠͨ͠ΫϥΠΞϯτΛ ͏͜ͱͰ൚༻తͳςετ͕Ͱ ͖Δ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ྺ࢙͋Δ&&ςετͷ మ൘πʔϧ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ 2004։ൃ։࢝
Ͱͳͥʮ41"ͷςετʹ 8FC%SJWFS͔ͳ͍ʯͷ͔ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
8FC%SJWFS͋͘·Ͱը໘ ΛભҠ͍ͯ͘͠ʮ8FCαΠτʯ ͷͨΊͷςετπʔϧ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
41"͚ͷςετπʔϧͰͳ ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
41"Λ8FC%SJWFSͰςετ͢ Δͷ͍͠ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
8FC%SJWFS௨ৗͷ։ൃπʔ ϧͱҧ͏֓೦Ͱಈ͘ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ChromeDriver FirefoxDriver IEDriver SafariDriver JSON Wire Protocol ಠࣗϓϩτίϧͷੈք
௨ৗͷ։ൃϑϩʔͱͷ ࠩҟ͕େ͖͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ྫ͑ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
/PEFDPOUFYUͱ #SPXTFSDPOUFYUͷஅ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ Electron͕ղܾ͔ͨͬͨͭ͠
let webdriver = require('selenium-webdriver'); let driver = new webdriver.Builder()
.forBrowser('chrome') .build(); driver.executeScript('return 2').then((res) => { console.log('returned ', res); }); driver.get('https://www.google.co.jp/').then(() => { driver.quit(); }); LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ͚ͩ͜͜#SPXTFSDPOUFYU
%FWFMPQQFS5PPMTͱڝ߹ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ DriverʹΑͬͯ
DPOTPMFMPHͷ༰͕UFSNJOBM Ͱ͔֬͠ೝͰ͖ͳ͍ ʢ0CKFDUల։ͱ͔ग़དྷͳ͍ʣ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
OPEFJOEFYKT UIFOBCMF8FC%SJWFS1SPYZ\ qPX@ $POUSPM'MPX\ QSPQBHBUF6OIBOEMFE3FKFDUJPOT@USVF BDUJWF2VFVF@ 5BTL2VFVF\ OBNF@5BTL2VFVF
qPX@<$JSDVMBS> UBTLT@<0CKFDU> JOUFSSVQUT@OVMM QFOEJOH@OVMM TVC2@OVMM LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ͜Ε͕ਏ͍ʂ
ը໘ΛભҠ͍ͯ͘͠ʮ8FCα ΠτʯͰ͋ΕͦΕ΄Ͳͳ ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
41"ͷ߹ɺ͜ΕΒͷπʔϧ͕ ͑ͳ͍ͷඇৗʹ͍͠ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
·ͨɺ8FC%SJWFSϖʔδͷ ಡΈࠐΈΫϦοΫޙͷભҠΛ ࣗಈͰͭػೳ͕͋Δ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
var webdriver = require('selenium-webdriver'), By = webdriver.By, until = webdriver.until;
var driver = new webdriver.Builder() .forBrowser('firefox') .build(); driver.get('http://www.google.com/'); driver.findElement(By.name(‘q')).sendKeys('webdriver'); driver.findElement(By.name('btnG')).click(); driver.wait(until.titleIs('webdriver - Google Search'), 1000); driver.quit(); LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ͬͯ͘ΕΔ
͕ɺ41"Ͱ௨ৗ͜ΕΒͷػೳ ༻͠ͳ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ͦ͜Ͱ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
41"ͷ*OUFHSBUJPOςετʹ ,BSNB LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
,BSNB LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ɾɾɾͬͯ͠·͢ʁ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ࣾͰฉ͍ͯΈͨ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ʮLBSNBͷ͢ΔΜͰ͢Αʯ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ʮ͋Εɺ"OHVMBS+4ઐ༻Ͱ͢Α Ͷʁʯ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ʮ·ͩ͋ͬͨΜͰ͔͢ʁʯ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ʮ1SPUSBDUPSʹͳͬͨͱࢥͬ ͯ·ͨ͠ʯ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ɾɾɾ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ͱͱ"OHVMBS+4ͷςετ༻ ʹ։ൃ͞Εͨςετπʔϧ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ݱࡏී௨ʹ൚༻తͳπʔϧ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ʢͱݴ͏͔Ή͠ΖAngularͱͷ૬ੑྑ͘ͳ͍Α͏ͳɻɻɻʣ
·ͩ·ͩ։ൃ׆ൃ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ʢ5લʹver 1.5.0ެ։ʣ
1SPUSBDUPSͱҧ͏ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ʢProtractorWebDriverܥʣ
ͬ͘͟Γ͍͏ͱ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ϒϥβ্Ͱಈ͘ 6OJUςετϥϯφʔ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
describe('Assert', () => { it('should true', () => { expect(true).toEqual(true);
}); }); LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ͜Ε͕ϒϥβ্Ͱಈ͘
ࠓճ7FSͰՃ͞Εͨ ػೳΛͬͯ*OUFHSBUJPOςε τͷํΛհ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
DVTUPN$POUFYU'JMF LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ςετΛࢦఆ͞ΕͨIUNM্Ͱ ߦ͏ػೳ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
<!DOCTYPE html> <html lang="ja"> <head> <script src="context.js"></script> <script type="text/javascript"> %CLIENT_CONFIG%
window.__karma__.setupContext(window); %MAPPINGS% </script> %SCRIPTS% <title>Inside Frontend</title> </head> <body> <script type="text/javascript"> window.__karma__.loaded(); </script> </body> </html> LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ͜͜ʹLBSNBDPOGKTͷ'JMF͕ల։͞ΕΔ ͔͜͜Β࣮ߦΛ։࢝
·ΔͰαΠτ্Ͱ6OJUUFTUΛ Β͍ͤͯΔ͔ͷΑ͏ʹॻ͚Δ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
describe('Document title', () => { it('should be', () => {
expect(document.title).toEqual('Inside Frontend'); }); }); LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
Β͍͘ʂ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
͔͠͠ɻɻɻ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
DVTUPN$POUFYU'JMFʹ Γͳ͋͞Δ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
Γͳ͞ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ಡΈࠐΈॴ͕MPDBMIPTU LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ Γͳ͞
࣮ࡍςετ͍ͨ͠υϝΠϯͰಡ Έࠐ·ΕΔΘ͚Ͱͳ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ͜͏͍ͨ͠
ௐͯΈͨ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ɻɻɻͪΐͬͱແཧͬΆ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ͜͏͢Δ
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ผυϝΠϯ௨৴ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ϒϥβΛͩ·͢ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
खॱ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
௨৴ͷॻ͖͑ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
-PDBMQSPYZΛ͏ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
$ npm install --save-dev karma-proxy-plugin LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
customContextFile: "custom-context-file.html", proxyValidateSSL: false, client: { clearContext: false }, middleware:
['proxy'], proxy: { '/inside-frontend/': { 'target': 'http://inside-frontend.com/', 'changeOrigin': true } }, proxyReq: (proxyReq, req, res, options) => { }, proxyRes: (proxyRes) => { }, LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ LBSNBDPOGKT 44-1SPYZ࣌ͷূ໌ॻΤϥʔΛແࢹ ςετ࣮ߦ͝ͱʹڥΛΫϦΞ͠ͳ͍ LBSNBQSPYZQMVHJO༻ LBSNBඪ४ͷQSPYJFTͰͳ͍͜ͱʹҙ ૹ৴Πϕϯτ ड৴Πϕϯτ
JOTJEFGSPOUFOEͷ௨৴Λ IUUQJOTJEFGSPOUFOEDPN సૹ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
௨৴ͷ͖ઌͷมߋ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
IUNM+4ͷ௨৴ͷ͖ઌΛ JOTJEFGSPOUFOEʹ͚͍ͨ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ 1ͰProxyϓϩηε্ཱ͕͕͚ͪͬͨͩͰɺ ϒϥβͷProxyઃఆΛߦͬͨΘ͚Ͱͳ͍
let base = document.createElement('base'); base.href = '/example/'; document.head.insertAdjacentElement('afterbegin', base); LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
DVTUPNDPOUFYUpMFIUNM
XMLHttpRequest = () => {/* … */}; fetch = ()
=> {/* … */}; LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ DVTUPNDPOUFYUpMFIUNM
؆୯ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ଞʹ͍Ζ͍Ζ͍ͨ͠߹ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
3FGFSFSΛॻ͖͍͑ͨ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
proxyReq: (proxyReq, req, res, options) => { proxyReq.setHeader('Referer', 'https://example.com/'); },
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ LBSNBDPOGKT
$PPLJFΛॻ͖͍͑ͨ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
proxyRes: (proxyRes) => { if (proxyRes.headers['set-cookie']) { proxyRes.headers['set-cookie'] = proxyRes.headers['set-cookie'].map((cookie)
=> { // karmahttpͳͷͰsecureΛফ͢ return cookie.replace(/\s*secure;?/i, ''); }) } }, LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ LBSNBDPOGKT
ϦμΠϨΫτઌΛมߋ͍ͨ͠ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
proxyRes: (proxyRes) => { if (proxyRes.headers['location']) { // ϦμΠϨΫτઌΛมߋ proxyRes.headers['location']
= proxyRes.headers['location'].replace(/^https:\/\/ example.com/i, '/example/'); } }, LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ LBSNBDPOGKT
ϩάΠϯ͍ͨ͠ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
fetch('/example/login', { method: 'POST', body: new FormData(document.getElementById('#login')) }).then((response) => response.text()).then((text)
=> { // ϨεϙϯεʹToken͕͋Εมʹอଘ // Cookieอ࣋͞ΕΔ window.__karma__.loaded(); }); LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ DVTUPNDPOUFYUpMFIUNM
͜͏͍ͬͨํ๏Λ͏͜ͱͰผ υϝΠϯͰಡΈࠐ·ΕΔΛ ղফ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
QSPYZ3FRɺQSPYZ3FTͷҾ ҎԼࢀর LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ IUUQTHJUIVCDPNOPEFKJUTVOPEFIUUQQSPYZ
͜͜·ͰདྷΔͱςετΛॻ͘ͷ ඇৗʹ؆୯ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ී௨ʹαΠτ্ͷ%FW5PPMT্ Ͱݕূ͢ΔͷͱมΘΒͳ͍Ϩϕ ϧͰςετ͕ॻ͚Δ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ const assert = require("power-assert"); describe('index page', () =>
{ it('Google map', () => { assert(google.maps); }); it('copyright', () => { assert(document.querySelector('.copyright')); }); });
ඇৗʹ͓͢͢Ί LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
࣮ࡍͬͯΈͯͲ͏͔ͩͬͨ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ςετඇৗʹॻ͖͍͢ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ͨͩɺϒϥβʹىҼ͢Δෆ҆ ఆ͞Ͳ͏͠Α͏ͳ͔ͬͨ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
%0.ͱ͍͏Ҭม͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ঢ়ଶͷΫϦΞ͕ࣗͷʹͳ ΔͷͰਏ͍ ʢָʹͳΔ෦͋Δ͚Ͳʣ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ࣗͰ੍ޚͰ͖Δൣғ͕͕Δ ͷخ͍͠ ʢ8FC%SJWFSͷϒϥοΫϘο Ϋεײ͕ͳ͍ʣ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ͦͦ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
8FC%SJWFSड͚ೖΕςετ ͷπʔϧͰ͋ͬͯɺ։ൃऀ͚ πʔϧͰͳ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
։ൃ͠ͳ͕Βςετ͢ΔͷͰ͋ Εผͷํ๏Λݕ౼͢Δํ͕͍ ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
ͨͩɺड͚ೖΕςετͳΒ 8FC%SJWFSͷ΄͏͕ྑ͍͔ ͠Εͳ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
8FC%SJWFSߴੑೳ͚ͩͲɺ ෆཁͳػೳଟ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
࠷ޙʹ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
&&ςετ ॻ͔ͳ͍ʹӽͨ͜͠ͱͳ͍ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
࣭͝ʁ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏
࣭͝ʁ LBSNBΛͬͨ41"͚ͷ&&ςετٕ๏ ྫ ɾ࣮ߦ࣌ؒʁ ɾ࣮ࡍͲ͏͍͏;͏ʹಈ͔ͯ͠Δʁ ɾଞͷϝϯόʔͷԠʁ ɾͬͯΑ͔ͬͨʁ ɾͲ͏͍͏ͱ͖ʹ͓͢͢Ίʁ ɾCIͱͷ࿈ܞʁ