タスクランナーとの親和性を向上。AppiumをNode.jsで動かす
前回までのコードはRubyで書いていましたが、MonacaアプリはHTML5/JavaScriptが主な利用言語になります。そこで今回はアプリを動かすスクリプトをNode.jsベースに書き直してみます。
これがうまく動けば、Gulpのようなテストランナーと組み合わせることで、コードの変更からテストまでがとてもスムーズになるはずです。DevOpsを積極的に進める上でも役立つのではないでしょうか。
Appiumのインストール、起動までは前回までの記事を参照してください。
Node.jsの設定
Node.jsについてはあらかじめインストールされていることとします。まだ未インストールの方はNode.jsよりダウンロード、インストールしてください。
まずテストスクリプトを書くフォルダを作成します。
mkdir appium_test
cd appium_test
npm init
そして必要なライブラリをインストールします。
npm install wd --save
これで準備は完了です。テストをスクリプトを書きます。まずAppiumに接続するまでの処理です。
"use strict";
var wd = require("wd");
var browser = wd.promiseChainRemote("0.0.0.0", 4723);
今回はローカルにAppiumサーバを立てています。そして接続する際の情報を定義します。今回はiOSシミュレータ向けに書いています。
var desired = {
"appium-version": "1.0",
platformName: "iOS",
deviceName: "iPhone 6 Plus",
app: "/Monaca_project_path/platforms/ios/build/emulator/AppiumTest.app"
};
接続がうまくいった場合は、アプリの起動した状態になっているはずです。
browser.init(desired).then(function() {
// この中にテストの処理を書きます
});
実際の処理ですが、XPathでエレメントを取得しなければなりません。これがとてもネストが深く、分かりづらいのでGUI版Appiumのインスペクタを使うのをお勧めします。Recordボタンを押して、要素をクリックすると、そこまでのXPathが表示されます。
そしてXPathが分かったらコードに反映していきます。例えば最初の画面のHelloWorld!を知りたい場合は次のように書きます。
browser.elementByXPath("//UIAApplication[1]/UIAWindow[1]/UIAScrollView[1]/UIAWebView[1]/UIAStaticText[1]").text().then(function(text) {
console.log(text); // -> HelloWorld!
});
全体としてPromiseで作られていますので、text()メソッドを実行しても {status: “pending”} が返ってくるだけです。then()でつないでテキストを受け取る必要があります。
そして非同期ということもあって、テキストの取得とクリックなどの処理をそのまま書いてしまうと、text()メソッドが間に合わずに画面遷移がはじまってしまいます。そこで、一画面ずつ順番に処理を行っていきます。
// テキストを取得
browser.elementByXPath("//UIAApplication[1]/UIAWindow[1]/UIAScrollView[1]/UIAWebView[1]/UIAStaticText[1]").text().then(function(text) {
console.log(text);
// タップ処理
browser.elementByXPath("//UIAApplication[1]/UIAWindow[1]/UIAScrollView[1]/UIAWebView[1]/UIALink[1]/UIAStaticText[1]").click().then(function() {
// タップした後の処理
});
});
最後にアプリを終了しますが、この時も非同期処理で行われているのを意識しないといけません。
browser.elementByXPath("//UIAApplication[1]/UIAWindow[1]/UIAScrollView[1]/UIAWebView[1]/UIALink[1]/UIAStaticText[1]").click().then(function() {
// 処理を遅らせないといきなり終了してしまいます
setTimeout(function() {
browser.quit();
}, 5000);
// ここに browser.quit(); を書くといきなりアプリが終了します
// browser.quit();
});
実際に実行した時の動画です。
最後に全体のコードです。
"use strict";
var wd = require("wd");
var desired = {
"appium-version": "1.0",
platformName: "iOS",
deviceName: "iPhone 6 Plus",
app: "/Volumes/SD/Dropbox/DevRel/Monaca/AppiumTest/platforms/ios/build/emulator/AppiumTest.app"
};
var browser = wd.promiseChainRemote("0.0.0.0", 4723);
browser.init(desired).then(function() {
browser.elementByXPath("//UIAApplication[1]/UIAWindow[1]/UIAScrollView[1]/UIAWebView[1]/UIAStaticText[1]").text().then(function(text) {
console.log(text);
browser.elementByXPath("//UIAApplication[1]/UIAWindow[1]/UIAScrollView[1]/UIAWebView[1]/UIALink[1]/UIAStaticText[1]").click().then(function() {
setTimeout(function() {
browser.quit();
}, 5000);
});
});
}).done();
注意点
JavaScriptで書く時の注意点としては、
- XPathで書く必要がある(ないかも知れませんがクラスでどう指定するのかが分かりませんでした…)
- 全体的に非同期処理
となっています。XPathは慣れればさほど難しくないかも知れませんが、Appiumのインスペクタを積極的に活用した方が良いでしょう。ただし画面の変化に対して弱くなってしまうように見えます。非同期についてはネストが深くなってしまう傾向がありますが、テストを適切に分離することで深くなりすぎるのを防げるかと思います。
JavaScriptを使う利点としてはRubyでiOSをテストする際にあった落ちるエラーが出なかったので、テストの品質が高くなりそうです。また、Appium自体がNode.jsでできているので親和性が高いかと思います。
Web開発ではGulpを使ってテストを定期的に実行するのが当たり前 になっています。Monacaを使ったハイブリッドアプリ開発においても同じようにテストを細かく行うことで品質の高いアプリ開発ができるようになるでしょう。