cordovaで開発したiPhoneアプリをappiumでテスト(2/2)

cordovaで開発したiPhoneアプリをAppiumでテストしたので、まとめました。

cordovaで開発したiPhoneアプリをappiumでテスト(1/2)
1.目標
2.simulator用appをビルド
3.appium他のインストール
4.Appiumデスクトップのインストール
5.Appiumデクトップを起動、Inspectorウィンドウで操作の記録

cordovaで開発したiPhoneアプリをappiumでテスト(2/2)
6.nodeでテストケース作成(アプリ起動のみ)
7.テストケースの実行
8.テストケース作成(座標をタップ、スクリーンショット保存)

6.nodeでテストケース作成

githubにappium公式サンプルソースがあります。
https://github.com/appium/sample-code

sample-code/examples/node/helpers/*.js
sample-code/examples/node/ios-simple.js
sample-code/examples/node/package.json
をダウンロードして、ios-simple.jsを改造します。

/Users/taro/projects/hello/platforms/ios/appium-testcaseの下に
helpers/*.js
ios-simple.js
package.json
を保存しました。

必要なnodeモジュールをインストールします。

$ cd /Users/taro/projects/hello/platforms/ios/appium-testcase
$ npm install

beforeメソッドのdesired変数は、「4.Appiumデクトップを起動、Inspectorウィンドウで操作の記録」のdesired capbilitiesの各項目を参考に設定してください。

テストケースの内容は、アプリを起動して、1秒間表示して、終了するだけです。

ios-simple.jsを編集します。

"use strict";

require("./helpers/setup");

var wd = require("wd"),
    _ = require('underscore'),
    Q = require('q'),
    serverConfigs = require('./helpers/appium-servers');

describe("ios simple", function () {
  this.timeout(300000);
  var driver;
  var allPassed = true;

  before(function () {
    var serverConfig = process.env.npm_package_config_sauce ?
      serverConfigs.sauce : serverConfigs.local;
    driver = wd.promiseChainRemote(serverConfig);
    require("./helpers/logging").configure(driver);

    var desired = {
      "appium-version": "1.4",
      platformName: "iOS",
      deviceName: "iPhone 7",
      platformVersion: "11.0",
      automationName: "XCUITest",
      app: "/Users/taro/projects/hello/app/Applications/HelloWorld.app",
    }; 

    return driver.init(desired);
  });

  after(function () {
    return driver
      .quit()
      .finally(function () {
        if (process.env.npm_package_config_sauce) {
          return driver.sauceJobStatus(allPassed);
        }
      });
  });

  afterEach(function () {
    allPassed = allPassed && this.currentTest.state === 'passed';
  });

  it ("test_1", function () {
    return driver
      .sleep(1000)
  });

});

7.テストケースの実行

appiumサーバの起動

Appiumデスクトップで[Start Server]しておくか、または、ターミナルで

appiumサーバの起動
$ appium &

appiumサーバの停止
$ pkill -f appium

テストケースの実行

$ cd /Users/taro/projects/hello/platforms/ios/appium-testcase
$ npm run ios-simple

iPhone simulatorの終了

$ pkill -f CoreSimulator

8.テストケース作成(座標をタップ、スクリーンショット保存)

Inspectorウィンドウで、xy座標をメモしてはクリックを繰り返して、テストケースを作りました。
次のように、座標指定のタップ、スクリーンショット保存処理、AlertダイアログのOKを追加しました。

"use strict";

require("./helpers/setup");

var wd = require("wd"),
    _ = require('underscore'),
    Q = require('q'),
    serverConfigs = require('./helpers/appium-servers'),
    fs = require('fs');

describe("ios simple", function () {
  this.timeout(300000);
  var driver;
  var allPassed = true;

  before(function () {
    var serverConfig = process.env.npm_package_config_sauce ?
      serverConfigs.sauce : serverConfigs.local;
    driver = wd.promiseChainRemote(serverConfig);
    //require("./helpers/logging").configure(driver);

    var desired = {
      "appium-version": "1.4",
      platformName: "iOS",
      deviceName: "iPhone 7",
      platformVersion: "11.0",
      automationName: "XCUITest",
      app: "/Users/taro/projects/hello/app/Applications/HelloWorld.app",
    }; 

    driver.saveScreenshot = function (path) {
      return driver.takeScreenshot().then(function(data) {
        fs.writeFile(path, data, "base64", function(err) {
          if (err) {
           throw err;
          }
        });
      });
    };

    return driver.init(desired);
  });

  after(function () {
    return driver
      .quit()
      .finally(function () {
        if (process.env.npm_package_config_sauce) {
          return driver.sauceJobStatus(allPassed);
        }
      });
  });

  afterEach(function () {
    allPassed = allPassed && this.currentTest.state === 'passed';
  });

  var tap_at = function (x, y) {
    var action = new wd.TouchAction();
    return action
      .press({"x": x, "y": y})
      .wait(100)
      .release();
  }

  it ("test_1", function () {
    return driver
      .sleep(1000)
      .saveScreenshot("/Users/taro/projects/hello/platforms/ios/appium-testcase/screenshots/01.png")

      .performTouchAction(tap_at(161, 464))
      .sleep(1000)
      .saveScreenshot("/Users/taro/projects/hello/platforms/ios/appium-testcase/screenshots/02.png")

      .acceptAlert()
      .sleep(1000)
      .saveScreenshot("/Users/taro/projects/hello/platforms/ios/appium-testcase/screenshots/03.png")
  });

});

最終的に、desired変数のdeviceName、platformVersion、appやスクリーンショット保存パスは、環境変数で渡すようにしました。
また、シミュレータでの実行が思ったより遅かったので、sleepで調整しています。

cordovaで開発したiPhoneアプリをappiumでテスト(1/2)

cordovaで開発したiPhoneアプリをAppiumでテストしたので、まとめました。

cordovaで開発したiPhoneアプリをappiumでテスト(1/2)
1.目標
2.simulator用appをビルド
3.appium他のインストール
4.Appiumデスクトップのインストール
5.Appiumデクトップを起動、Inspectorウィンドウで操作の記録

cordovaで開発したiPhoneアプリをappiumでテスト(2/2)
6.nodeでテストケース作成(アプリ起動のみ)
7.テストケースの実行
8.テストケース作成(座標をタップ、スクリーンショット保存)

当初、XcodeのXCUITestでwebviewのDOMを取得できなかったので、appiumを使ってみました。結局、appiumでもwebviewのDOMを取得できず、xy座標を指定してタップ操作を記述することにしました。それなら、XCUITestでテストケースを書いたほうがよかったかもしれません。

1.目標

全画面を遷移し、スクリーンショットを保存する。

対象機種のシミュレータ:
iPhone X、iPhone 8、iPhone 7 (11.0)、iPhone 7 Plus (11.0)、iPhone 6 (10.3)

2.simulator用appをビルド

cordovaプロジェクトの位置=/Users/taro/projects/hello
xcodeワークスペースの位置=/Users/taro/projects/hello/platforms/ios/HelloWorld.xcworkspace
appのファイル位置=/Users/taro/projects/hello/app/Applications/HelloWorld.app

ターミナルで次のsim_build.shを実行します。
app/Applications/HelloWorld.appが作成されます。

$ cd /Users/taro/projects/hello
$ ./sim_build.sh

/Users/taro/projects/hello/sim_build.sh

#!/bin/bash -x

WORKSPACE=HelloWorld
SCHEME=HelloWorld
CONFIG=Debug
SDK=iphonesimulator

xcodebuild \
  -workspace $WORKSPACE \
  -scheme $SCHEME \
  -configuration $CONFIG \
  clean \
  DSTROOT=${PWD}/app

xcodebuild \
  -workspace $WORKSPACE \
  -scheme $SCHEME \
  -configuration $CONFIG \
  -sdk iphonesimulator \
  install \
  DSTROOT=${PWD}/app

3.appium他のインストール

必要なものをインストールしてください。
ターミナルの cd する場所はどこでもかまいません。

Homebrewのインストール
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

rbenvのインストール
$ brew install rbenv ruby-build readline

RubyのパスをBashに追記
$ echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bash_profile
$ source ~/.bash_profile

Rubyのインストール
$ rbenv install --list
$ rbenv install 2.4.2
$ rbenv global 2.4.2
$ ruby -v

$ npm install -g appium
$ npm install -g appium-doctor
$ brew install carthage

環境確認
$ appium-doctor --ios

4.Appiumデスクトップのインストール

デスクトップ版 appium
https://github.com/appium/appium-desktop/releases

最新バージョンの appium-desktop-x.x.x.dmg をダウンロード、インストールしてください。

4.Appiumデクトップを起動、Inspectorウィンドウで操作の記録

Finder>アプリケーション>Appiumを起動してください。
[Simple]のまま、[start server]をクリックしてください。

黒いログコンソールが表示されます。
右上の虫メガネ[Start Inspector Session]ボタンをクリックしてください。

Inspectorウィンドウが表示されます。
Desired Capabilitiesタブで、次の5項目を設定してください。

項目
platformName text iOS
automationName text XCUITest
deviceName text iPhone 7
platformVersion text 11.0
app text /Users/taro/projects/hello/app/Applications/HelloWorld.app

platformName
“iOS”固定です

automationName
“XCUITest”固定です

deviceName
“iPhone 7″、”iPhone 7 Plus”、”iPhone 6″、”iPhone 6 Plus”などを入力します。

platformVersion
“10.3”、”11.0″などを入力します。
Xcodeで”9.3″シミュレータもダウンロード済みでしたが、appiumから”9.3″は起動できず諦めました。

app
「1.simulator用appをビルド」で作成したappファイルの絶対パスを指定してください。

[Start Session]をクリックしてください。
しばらくすると、iPhoneシミュレータが表示されます。
iPhoneシミュレータでテスト対象アプリが起動します。
Inspectorウィンドウにスクリーンショットが表示されます。

スクリーンショット上でマウスを動かしてみてください。
識別可能な画面要素が黄色くなり、クリックすると、緑になります。
ウィンドウの中央のApp Source領域には、ツリーが表示されます。
右側のSelected Element領域には、クリックした画面要素のXCUIElementツリーのxpathが表示されます。

cordovaで開発したアプリなので、画面要素はWebView内です。残念ながらDOM IDで画面要素を指定できないようです。画面要素が存在していること、属性が期待した値になっていること、などをアサーションしたいのですが、今回はあきらめました。

いろいろ試して、次の操作でテストケースを書くことにしました。

sleep(ミリ秒)
x, y座標指定のタップ
alertダイアログのOK
スクリーンショットの保存

iPhone 7でxy座標を調べて、iPhone 7 Plusなら座標を1.1倍することにし、iPhone Xは別に座標定義を用意することにしました。

画面ごとにスクリーンショットを保存し、担当者が見て確認することにしました。

(つづく)