SlideShare a Scribd company logo
1 of 48
Download to read offline
Spectron
自己紹介
Ruby書いてない歴1年ちょっと
最後にまともに書いたのはGrapeでWeb API
JavaScript歴だいたい10ヶ月
Lambdaやテストでちょっと書いたことあったくらい
昨年春から某デスクトップアプリ開発へ
優しい先輩から口酸っぱく「テストねぇから!」の脅し
Ruby ‑> JavaScript(Node) あるある
 return を書かない
> hoge = function hoge() { "hogehoge" }
[Function: hoge]
> hoge()
undefined
 0 にハマる
> [0, 1, null].filter(val => { return val })
[ 1 ]
 this にハマる
NG : thisは呼び出し元=== ary1
convert() {
this.ary1.forEach(function(val) {
this.ary2.push(this.str2num(val))
})
}
OK : thisを渡す
convert() {
this.ary1.forEach(val => {
this.ary2.push(this.str2num(val))
}, this)
}
OK : Allow functionを使う(thisを語彙的に束縛する)
convert() {
this.ary1.forEach(val => {
this.ary2.push(this.str2num(val))
})
}
非同期処理がまどろこっしい
promise/async/awaitは最初の難関
これらがある時代に生まれたのでcallback地獄はさほど経験し
なかった
Fileの存在チェックで fs.existsSync() ということにむしろ驚く
HTTPリクエスト一個送るのも辛い
本題
Spectron
Electronアプリのテストフレームワーク(公式)
ElectronのAPIをフルサポート
裏側はWebdriver
Electron
デスクトップアプリケーションフレームワーク
Chromium + Node.js
HTML + CSS + JavaScript
クロスプラットフォーム対応
JS界でのこの分野はまだメジャー (参考)
Electronおさらい
とっとるびーでも何度か発表あり(20th, 25th)
メインプロセス:
Windowを起動したりメニュー操作イベントを受け取ったり
Node.js
レンダープロセス
ブラウザ(HTML + CSS + JavaScript) をレンダリング
Chromium
プロセス間通信はipcを用いる。イベントフックしてやり取りする
Electron App
your-app/
├── package.json
├── main.js
└── index.html
const { app, BrowserWindow } = require('electron')
function createWindow () {
win = new BrowserWindow({ width: 800, height: 600 })
win.loadFile('index.html')
}
app.on('ready', createWindow)
$ npm run start
demo
https://electronjs.org/blog/simple‑samples
https://github.com/electron/simple‑samples
Webdriver
Webdriver
ブラウザのテストツール
ページ上の要素を操作できる(クリック, 入力等)
ページ上の要素の有無や状態をテストできる
WebDriverIO === WebDriver binding for Node.js
ElectronアプリをSpectronでテストする
HTML + CSS + JavaScriptで作られたデスクトップアプリを、
WebDriverでテストする。
単純明快で、普通のアプリならテストしやすいよね~と思うじゃないで
すか。
例えばslack
入力・表示のテストとか
チャンネル切り替えとか
設定変更とか
コマンドとか
=> ブラウザのレンダリング領域のテストは容易
http://webdriver.io/api.html
Demo : npm runしてテストする
https://github.com/electron/spectron#usage
electronアプリを起動してWindowの数をテストするだけ
Demo : インストールした.appをテストする
内容は同じ
某PC用アプリケーション
Viewerアプリ
初手は画像か動画をメニューから開くところから
メニュー操作
メニュー操作vs Spectron
https://github.com/electron/spectron/issues/21
(メニューのテストってどうしたらいいの?)
メニュー操作vs Spectron
(メニュー取得するAPIにはまだ対応してしてないよ )
メニュー操作vs Spectron
SpectronからElectronアプリケーションのMenuを操作する
MenuのAPIがJSONにserializeされていないので、process間通信
が必要なSpectronでは操作が難しいというのがその理由のようで
す。 同じ様に、dialogモジュールの操作も出来ません。
アプリケーションの操作をChrome Driverを通じて行うのが基本理
念のSpectronでは、これらのnativeなAPIを必要とする操作に対す
るサポートはまだ不十分、というのが実情です。
spectron‑fake‑menu
SpectronはElectronのChrome Driverを通じてアプリケーションの
操作を実行できるのですが、メニューの操作には現状対応していま
せん。(詳しくは後述します。)
そこでspectron‑fake‑menuというSpectronからメニューの操作が
できるnpmを作成しました。
https://github.com/joe‑re/spectron‑fake‑menu
spectron‑fake‑menu でやっていること
https://github.com/electron/spectron/issues/94
Electronは‑‑requireオプションで、Electronの起動直前にスクリプ
トを差し込むことができます。
これを利用して、Mainプロセスにspectron‑fake‑menu用のイベン
トを受け取る口を仕込んでいます。
require('electron').ipcMain.on(
'SPECTRON_FAKE_MENU/SEND', (_e, labels) => {
const item = findItem(
require('electron').Menu.getApplicationMenu().items,
labels
);
item.click();
});
イメージ: spectron‑fake‑menu
続spectron‑fake‑menu
つらいところ: メニューの操作は非同期処理になる
https://github.com/joe‑re/spectron‑fake‑menu/tree/master/example
クリックした後の処理が終わったことを知る術がない
HTMLがレンダリングされて、何かしらが変わるのを待つ必要
がある
 setInterval() &  clearInterval() 
変わるものがないような処理は・・・sleepのようなものを使
う・・・?
メニューの数だけクリックした後の処理終了を待つ関数が必要にな
る
もちろん共通化できるものもあるが・・・
spectron‑fake‑menu example
describe('Increment', function() {
this.timeout(10000);
let app;
beforeEach(function() {
app = createApplication();
return app.start();
});
afterEach(function() {
return app.stop();
});
it('increment count', () => {
return app.client.waitForExist('#count')
.then(() => {
fakeMenu.clickMenu('Count', 'Increment');
return waitForChangeCount(app, '1');
})
.then(() => assert.ok(true));
});
});
waitForChangeCount()
export function waitForChangeCount(app, count) {
return new Promise((resolve, _reject) => {
const timer = setInterval(() => {
app.client.getText('#count').then((text) => {
if (text === count) {
clearInterval(timer);
resolve();
}
});
}, 1000);
});
}
とは言え、メニュー操作はクリア
しかし
某PCアプリの最初の操作
1. メニュー : ファイル> 開く
2. ファイル選択のダイアログが開く
3. 画像or 動画を選択する
4. 3が再生される
しかし
MenuのAPIがJSONにserializeされていないので、process間通信
が必要なSpectronでは操作が難しいというのがその理由のようで
す。 同じ様に、dialogモジュールの操作も出来ません。
同じ様に、dialogモジュールの操作も出来ません。
dialogモジュールのテスト時のモックも同じ理屈ででき
る
https://github.com/electron/spectron/issues/112
ただしファイルはほぼ固定になる。
テストによってモックを差し替えるようにする等工夫は必要。
後はテストをするだけ
Electronアプリは基本的にrenderプロセス側に対する操作駆動
HTMLに対する操作に対するテストを書く
WebDriverで大抵カバーできる
WebDriverでテストしにくいことはできない
demo
SpectronでMenuからファイルを開く
Spectron API
ElectronのAPIをフルサポート
アプリの操作, 状態確認
 start() 
 stop() 
 restart() 
 isRunning() 
 getSetting() 
ログ取得
 client.getMainProcessLogs() 
 client.getRenderProcessLogs() 
Windowの状態確認
 client.getSelectedText() 
 client.getWindowCount() 
 client.waitUntilTextExists(selector, text, [timeout]) 
 client.waitUntilWindowLoaded([timeout]) 
 client.windowByIndex(index) 
wait系のAPIが2つしかない
WebDriverを使ったことがある人は「待つ」処理がどれだけ必要か分か
るはず。
普通にテストを書いていると「xxの処理を待つ」が頻発。
 client.waitUntilTextExists(selector, text, [timeout]) 
 client.waitUntilWindowLoaded([timeout]) 
をラップした便利関数が多数必要になる。
例) window数がN個になるまで待つ
継続的インテグレーション
Travis CI
### .travis.yml ###
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- sleep 3 # give xvfb some time to start
実装例& 一部Demo
まとめ
WebDriverを使ったテストが書ける
メニュー操作・ダイアログ操作は辛い
wait地獄と上手に付き合いましょう
CIもできる
Spectron

More Related Content

What's hot

はてなブックマーク in Scala
はてなブックマーク in Scalaはてなブックマーク in Scala
はてなブックマーク in ScalaLintaro Ina
 
ScalaプログラマのためのHaskell入門
ScalaプログラマのためのHaskell入門ScalaプログラマのためのHaskell入門
ScalaプログラマのためのHaskell入門Yasuaki Takebe
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門Makoto Fukuhara
 
なぜリアクティブは重要か #ScalaMatsuri
なぜリアクティブは重要か #ScalaMatsuriなぜリアクティブは重要か #ScalaMatsuri
なぜリアクティブは重要か #ScalaMatsuriYuta Okamoto
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタートShumpei Shiraishi
 
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fallこれからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fallなおき きしだ
 
OSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニックOSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニック庸介 高橋
 
PHPコードではなく PHPコードの「書き方」を知る
PHPコードではなく PHPコードの「書き方」を知るPHPコードではなく PHPコードの「書き方」を知る
PHPコードではなく PHPコードの「書き方」を知るMasashi Shinbara
 
知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編Shota Baba
 
演算子オーバーライドをDSLに活用する
演算子オーバーライドをDSLに活用する演算子オーバーライドをDSLに活用する
演算子オーバーライドをDSLに活用するkwatch
 
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化Lintaro Ina
 
Why Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriWhy Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriYuta Okamoto
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)x1 ichi
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行guest5f4320
 

What's hot (20)

Trait in scala
Trait in scalaTrait in scala
Trait in scala
 
Phantom Type in Scala
Phantom Type in ScalaPhantom Type in Scala
Phantom Type in Scala
 
はてなブックマーク in Scala
はてなブックマーク in Scalaはてなブックマーク in Scala
はてなブックマーク in Scala
 
ScalaプログラマのためのHaskell入門
ScalaプログラマのためのHaskell入門ScalaプログラマのためのHaskell入門
ScalaプログラマのためのHaskell入門
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門
 
なぜリアクティブは重要か #ScalaMatsuri
なぜリアクティブは重要か #ScalaMatsuriなぜリアクティブは重要か #ScalaMatsuri
なぜリアクティブは重要か #ScalaMatsuri
 
Scalaノススメ
ScalaノススメScalaノススメ
Scalaノススメ
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
JavaScriptクイックスタート
JavaScriptクイックスタートJavaScriptクイックスタート
JavaScriptクイックスタート
 
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fallこれからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
これからのコンピューティングの変化とJava-JJUG CCC 2015 Fall
 
OSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニックOSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニック
 
PHPコードではなく PHPコードの「書き方」を知る
PHPコードではなく PHPコードの「書き方」を知るPHPコードではなく PHPコードの「書き方」を知る
PHPコードではなく PHPコードの「書き方」を知る
 
知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編知って得するC# LINQ to Objects編
知って得するC# LINQ to Objects編
 
演算子オーバーライドをDSLに活用する
演算子オーバーライドをDSLに活用する演算子オーバーライドをDSLに活用する
演算子オーバーライドをDSLに活用する
 
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
はてなブックマークにおけるアクセス制御 - 半環構造に基づくモデル化
 
HDCLT
HDCLTHDCLT
HDCLT
 
Shelly
ShellyShelly
Shelly
 
Why Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuriWhy Reactive Matters #ScalaMatsuri
Why Reactive Matters #ScalaMatsuri
 
あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)あなたのScalaを爆速にする7つの方法(日本語版)
あなたのScalaを爆速にする7つの方法(日本語版)
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 

Similar to Spectron

関数型プログラミング in javascript
関数型プログラミング in javascript関数型プログラミング in javascript
関数型プログラミング in javascriptRyuma Tsukano
 
LaravelでAPI定義を管理する
LaravelでAPI定義を管理するLaravelでAPI定義を管理する
LaravelでAPI定義を管理するKenjiro Kubota
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-Kazunari Hara
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門masatora atarashi
 
RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数Altech Takeno
 
第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまで第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまでMugen Fujii
 
Javascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional ProgrammingJavascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional Programmingtodorokit
 
Vim scriptとJavaとHaskell
Vim scriptとJavaとHaskellVim scriptとJavaとHaskell
Vim scriptとJavaとHaskellaiya000
 
そんな装備で大丈夫か?
そんな装備で大丈夫か?そんな装備で大丈夫か?
そんな装備で大丈夫か?2celeb
 
今日からはじめるGPars
今日からはじめるGPars今日からはじめるGPars
今日からはじめるGParsfumokmm
 
Web技術勉強会 第31回
Web技術勉強会 第31回Web技術勉強会 第31回
Web技術勉強会 第31回龍一 田中
 
知ってるようで意外と知らないPHPの便利関数
知ってるようで意外と知らないPHPの便利関数知ってるようで意外と知らないPHPの便利関数
知ってるようで意外と知らないPHPの便利関数Wataru Terada
 
そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4Shingo Inoue
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDEdcubeio
 

Similar to Spectron (20)

Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
関数型プログラミング in javascript
関数型プログラミング in javascript関数型プログラミング in javascript
関数型プログラミング in javascript
 
LaravelでAPI定義を管理する
LaravelでAPI定義を管理するLaravelでAPI定義を管理する
LaravelでAPI定義を管理する
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
PHP 入門
PHP 入門PHP 入門
PHP 入門
 
RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数RubyとJavaScriptに見る第一級関数
RubyとJavaScriptに見る第一級関数
 
第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまで第4回勉強会 Groovyの文法からSpockまで
第4回勉強会 Groovyの文法からSpockまで
 
Javascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional ProgrammingJavascriptで学ぶ Functional Programming
Javascriptで学ぶ Functional Programming
 
Go guide for Java programmer
Go guide for Java programmerGo guide for Java programmer
Go guide for Java programmer
 
Vim scriptとJavaとHaskell
Vim scriptとJavaとHaskellVim scriptとJavaとHaskell
Vim scriptとJavaとHaskell
 
そんな装備で大丈夫か?
そんな装備で大丈夫か?そんな装備で大丈夫か?
そんな装備で大丈夫か?
 
今日からはじめるGPars
今日からはじめるGPars今日からはじめるGPars
今日からはじめるGPars
 
Web技術勉強会 第31回
Web技術勉強会 第31回Web技術勉強会 第31回
Web技術勉強会 第31回
 
Haxe
HaxeHaxe
Haxe
 
知ってるようで意外と知らないPHPの便利関数
知ってるようで意外と知らないPHPの便利関数知ってるようで意外と知らないPHPの便利関数
知ってるようで意外と知らないPHPの便利関数
 
そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4そしてjsの基礎へ戻る#4
そしてjsの基礎へ戻る#4
 
ATN No.2 Scala事始め
ATN No.2 Scala事始めATN No.2 Scala事始め
ATN No.2 Scala事始め
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDE
 
pecl-AOPの紹介
pecl-AOPの紹介pecl-AOPの紹介
pecl-AOPの紹介
 

Spectron