CasperJSでWeb GUIテスト


CasperJSは、ヘッドレスブラウザのPhantomJSを使ってブラウザ操作やテストができるライブラリ。
WebテストのデファクトであるSeleniumやそのGroovyラッパーのGeb（これが一番おすすめ）に比べて、インストールが簡単で、動作の軽量なのが特徴。
以下のデメリットもありますが、軽いWebシステムには相性がよい。

* クロスブラウザができない（PhantomJSベースなので当たり前）
* Gebと比べると気が利かない
* 入れ子が多くなって気持ち悪い（Coffee Scriptを使えばいい？）

# CasperJSのドキュメント

http://docs.casperjs.org/en/latest/

http://docs.casperjs.org/en/latest/modules/index.html

# インストール

Macならコマンド一発。win用に簡単に説明。

参考：http://qiita.com/ledsun@github/items/d55e83d41a4435755fcd

## chocolateyのインストール

コマンドプロンプトで以下を実行
参考：https://chocolatey.org/

```
@powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%systemdrive%\chocolatey\bin
```

## PhantomJSのインストール

コマンドプロンプトで以下を実行

```
cinst phantomjs
```

コマンドプロンプトを再起動して以下で確認

```
phantomjs --version
```

## CasperJSのインストール

### ダウンロード

http://casperjs.org/
から【1.1-beta3】をダウンロード。
※stable versionだとwin対応されてないので注意！
※chocolateyにもあるけど、1.1はないみたい。

回答したフォルダを好きなところにコピー。
（以下、C:\CasperJS　にコピーした前提で説明します。）

### パスの設定

システムの詳細設定
=>環境変数
=>Path
=>編集
=>行頭に以下を追記

```
C:\CasperJS\bin
```

確認
--

コマンドプロンプトを再起動して、以下で確認

```
casperjs --version
```
# 実行の仕方

## 実行（テストなし）

```
casperjs foo.js
```

## 実行（テストあり）

```
casperjs test foo.js
```

# 基本処理

## 画面を開いてキャプチャーをとる

```js
var casper = require('casper').create();
casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

casper.start('../../introWork/introWork1.html', function(){
	this.capture('out/intro_work_1.png');
});

casper.run();
```

## クリックする

`this.click('#ok_button');`のようにCSSセレクターを使って要素を選択できる。

```js
var casper = require('casper').create();
casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

casper.start('../../introWork/introWork2.html', function(){
	this.click('#ok_button');
	this.capture('out/intro_work_2.png');
});

casper.run();
```

## 文字列を入力する

`this.sendKeys('#subject', 'Selenium', {reset: true});`
第１引数が要素のCSSセレクター、第２引数が文字列、第３引数がオプション（この場合は入力済みの文字をリセットする）。

```js
var casper = require('casper').create();
casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

casper.start('../../introWork/introWork3.html', function(){
	this.sendKeys('#subject', 'Selenium', {reset: true});
	this.capture('out/intro_work_3.png');
});

casper.run();
```

## ラジオボタンを選択する

クリックでいけますね。

```js
var casper = require('casper').create();
casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

casper.start('../../introWork/introWork4.html', function(){
	this.click('#on_radio');
	this.capture('out/intro_work_4.png');
});

casper.run();
```

## チェックボックスを選択する

`if(!this.getElementAttribute('#allowed_check', 'checked'))`部分がポイント。
チェックされているかを判定。

```js
var casper = require('casper').create();
casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

casper.start('../../introWork/introWork5.html', function(){
	if(!this.getElementAttribute('#allowed_check', 'checked')){
		this.click('#allowed_check');
	}
	this.capture('out/intro_work_5.png');
});

casper.run();
```

## プルダウンを選択する

```js
var casper = require('casper').create();
casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

casper.start('../../introWork/introWork6.html', function(){
	this.fillSelectors('form', {'#head_count': '5'});
	this.capture('out/intro_work_6.png');
});

casper.run();
```

## Assertion

start, then, runのように実施する。

```js
casper.test.begin('introWork7', 1, function suite(test) {
	casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');
    
    casper.start('../../introWork/introWork7.html', function() {
        this.capture('out/intro_work_7.png');
    });

    casper.then(function() {
        test.assertSelectorHasText('#total', '9000');
    });

    casper.run(function(){
    	test.done();
    });
});
```

PageObjectデザインパターン
------------------

### PageObjectデザインパターンって？

http://jsebfranck.blogspot.fr/2014/03/page-object-pattern-with-casperjs.html

### PageObject

入れ子になっていて気持ち悪いけど、基本的にはページに関する処理をラップしているだけ。

```js
function FooPage() {

    this.capture = function(name){
        casper.then(function(){
            this.capture(name);
        });
        return this;
    };

    this.startPage = function() {
        casper.start('foo.html');
        return this;
    };

    this.setBar = function(bar) {
        casper.then(function() {
            this.sendKeys('#bar', bar, {reset: true});
        });
        return this;
    };
    
    this.goToNext = function() {
        casper.then(function(){
            this.click('#goto_next');
        });
    };
}
```

## PageObjectを使う

PageObjectを作ってしまえば、メソッドチェーンで処理を書いていけばいい。

```js
phantom.page.injectJs('pages/foo_page.js');

var fooPage = new FooPage();

casper.userAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53');

casper.test.begin('PageObjectTest', function suite(test) {
    fooPage.startPage()
        .capture('out/foo.png')
        .setBar('bar')
        .goToNext();

    casper.run(function() {
        test.done();
    });
});
```

# Coffee Script

Coffee対応しているので、Coffeeを使うと簡潔に書けますね。
（書いたことないけど。。。）

http://docs.casperjs.org/en/latest/extending.html#using-coffeescript

# 参考

[STARの教材](https://sites.google.com/site/testautomationresearch/teaching_materials/maintainable_script)をCasperJSで書きなおしたソースが以下。

https://github.com/itagakishintaro/STARHandsOnCasperJS