Webサイト、業務用Webシステムを構築する際にコーディングが各ブラウザに適切かどうかは必ずチェックすると思います。コーディングに問題があるとブラウザによってはデザインが崩れたり、思ったユーザ体験が提供できないことがあります。Web標準に則って開発するのも大切です。
そうしたコーディングチェックツールは幾つかありますが、今回は特に「古いIE向けのコード」や「Web標準やベストプラクティスに従っていないコード」を検出し、修正案を出してくれるMicrosoft公式のサイトスキャンのオフライン版を試してみたいと思います。modern.IEのサイトではURLを入力するとそのページをすぐにスキャンできますが、オフライン版であればLAN内部のサーバに対してチェックできるので、開発中のサイトに対しても利用できるのが利点です。
Webブラウザによる業務システムが普及してくるのに伴って、OSの自由度が広がっています。数年前であればWindows機ばかりだったオフィスもMac OSX導入が進んでおり、さらにデスクトップではないスマートデバイス(スマートフォン、タブレット)を使った業務システムも使われています。
とはいえ開発の現場ではIE向けにも正しく表示できるかのテストは必ず必要になります。IEもブラウザシェアのばらつきがあり、すべてのブラウザが網羅できているとは限りません。
ローカルで各バージョンのIEを試す手段としてはmodern.IEによるVMイメージの提供があります。しかし、VMをローカルで動かさなくて済めば、もっと手軽にテストができるでしょう。
というわけで、今回はリモートでIEが試せる「RemoteIE」を使ってみます。

RemoteIEは現在のところIE 11に限定して提供されています。またRemoteIEはベータ版なのでご注意ください。
必要なもの
マイクロソフトのアカウント
Live.comのアカウントが使えます。
Microsoft Remote Desktop
以下のプラットフォーム向けに提供されています。
- Mac OSX
- iPhone/iPad
- Android
- Windows Phone 8.1
- Azure RemoteApp for Windows x86
- Azure RemoteApp for Windows x64
- Azure RemoteApp for Windows RT

今回はMac OSX版を試しています。
Microsoft Remote Desktopの起動
Microsoft Remote Desktopを起動したら、Microsoft RemoteAppをクリックします。

開いたウィンドウでLive.comアカウントでログインします。

そうするとMicrosoft RemoteAppとしてInternet Explorerが追加されています。

このIE Technical PreviewをダブルクリックするとRDPが開始します。
使ってみる
RemoteIEではウィンドウ全体にIEが表示されます。面白いのは一つのウィンドウとして立ち上がっていることです。リモートデスクトップとしてOSが使えるのではなく、あくまでもIEだけが使える状態です。
最初にWindows 8風のログイン処理が行われます。

こちらが表示した状態です。日本語も問題なく表示できます。日本語の入力はできませんでした。

バージョンは IE 11.0.9879.0 になります。

性能を見る
HTML5 Testを使ってみたところ、376ポイントでした。Google Chrome 38が512なのでHTML5については、まだまだこれからといった所でしょうか。

F12 Developer Toolsという開発ツールを立ち上げることができます。Google ChromeでいうDevToolsです。

コンソールを使ったり、プロファイルを実行できます。

HTMLソースの変更も可能です。

もちろんブレークポイントも。最初の読み込み時にもブレークポイントが仕込めます。

制限
リモートと言うこともあって制限もあります。まずインターネットオプションは使えません。

印刷もできません。

ブックマークは使えましたが、セッションは10分間の放置または1時間で破棄されますので使うことはなさそうです。
雑感
現状ですと、自動化テストで使うと言ったような積極的な活用ではなく、一旦Google ChromeやFirefoxで作ったWebアプリケーションの最終確認としてIEでテストすると言った使い方になるかと思います。互換モードで過去のIEでの表示をテストすることもできますのであくまでも表示乱れがないかの確認と言ったところでしょう。
初めに述べたように、Microsoftでは各バージョンのIEを動かすための仮想マシン(VirtualBox/VMWare Fusion/Parallels)も提供しています。こちらはローカルでいつでも使えるメリットがありますが、ライセンスは90日間に限られます(再ライセンスは可能)。リモートであれば動作が重たくなったりもしませんので、IE 11のみならず使えるブラウザが広がってくれると使い勝手が良くなりそうです。
概要
ついにW3C勧告となり、ブラウザの対応も進んできたHTML5。業務システムにおいてもその活用シーンは増えてきています。
しかし、長期の運用・保守が前提でコスト削減の要求も強い業務システム開発では、高度化するニーズに応えつつ開発を効率化を図ることが非常に重要です。今回のセミナーでは、HTML5/JavaScriptを使ってiOS/Android双方に対応したモバイルアプリの開発を効率化する開発基盤「Monaca」、および業務システム構築に主眼を置いたHTML5 Webアプリ開発フレームワーク「hifive」をご紹介します。
お申込みはこちら:
第2回 HTML5 企業Webシステム開発セミナー「アプリ×HTML5」 – connpass
スピーカー
- アシアル株式会社 代表取締役社長 田中正裕様
- 新日鉄住金ソリューションズ システム研究開発センター hifive開発班
タイムスケジュール
| 時間 | 内容 |
|---|---|
| 19:15 | 開場 |
| 19:30〜 | HTML5ハイブリッドアプリ及びMonacaの利点(アシアル株式会社 田中様) |
| 20:15〜 | HTML5を活用した業務システム開発をサポートする「hifive」のご紹介(hifive開発班) |
| 21:00〜 | 懇親会(※無料) |
テーマ/スピーカープロフィール
HTML5ハイブリッドアプリ及びMonacaの利点
HTML5を用いたアプリ開発(ハイブリッドアプリ)の利点と、弊社の提供するクラウド型サービスMonacaを紹介します。
スピーカー:アシアル株式会社 代表取締役社長 田中正裕様
ユーザーインタフェース設計からインフラストラクチャー構築まで、最先端の技術を駆使したシステム構築を手がける。
特にPHPをはじめとするOSSや、HTML5やJavaScriptといったオープンなアーキテクチャーを用いたシステムの構築に尽力している。モバイルアプリ開発プラットフォーム「Monaca」のプロダクトマネジャーを兼務。
HTML5を活用した業務システム開発をサポートする「hifive」のご紹介
実装を助けるフレームワークからデバッグに役立つツールセットまで、業務Webシステムの開発をトータルで支援する「hifive」の最新情報をご紹介します。
スピーカー:新日鉄住金ソリューションズ システム研究開発センター hifive開発班
主な対象の方
- HTML5のエンタープライズ開発を推進している方
- HTML5を使ったハイブリッドアプリに興味がある方
- 最新のHTML5情報と業務システムへの活かし方に興味がある方
司会
hifive エヴァンジェリスト 中津川 篤司(@moongift)
お問い合わせ先
contact@htmlhifive.com
当日、受付時に名刺を1枚頂戴しますので予めご用意ください。
ユーザが入力したデータはきちんとチェックしなければなりません。システム上、意図しないデータが入力される場合はもちろんのこと、全角と半角の違いやデータベースに格納できるサイズを超えたデータ入力をされるケースもあります。
hifive自身ではバリデーションのクラスはありませんが、jQuery Validateと組み合わせて入力値の検証が可能です。
コントローラ側の実装は次のようになります。
h5.core.controller('body', {
__name: 'sample.plugin.validationSampleController',
__ready:function() {
// バリデーターにルールやメッセージ等を設定
this.$find('#form1').validate({
onsubmit: true, // Submitイベントが実行された場合に、自動でバリデーションを実行するか
focusCleanup: false, // フォーカスが当たった場合に現在のエラー内容を一旦クリアするか
rules: { // バリデーションルール
food: {
required: true
},
conf_tobacco: {
required: true
},
:
},
messages: { // エラー時に表示するメッセージ
food: {
required: '1つ以上選択して下さい。'
},
conf_tobacco: {
required: '「はい」または「いいえ」のいずれかを選択して下さい'
},
:
},
errorPlacement: function(error, el) { // エラーメッセージの表示先を指定する
el.parent().children('.errorMsg').append(error);
},
showErrors: function(errorMap, errorList) { // エラーがある要素毎に実行するコールバック
this.defaultShowErrors();
},
}),
highLightArea: function(orgThis, el, error, errorClass) {
// エラーのある要素の背景色を赤にする
$(el).css('background-color', 'red');
},
:
invalidHandler: function(orgThis, ev, validator) {
alert('入力内容に誤りがあります。');
},
successHandler: function(orgThis, errMsgElement, inputElement) {
if (window.console) {
console.log('入力OK: '+ inputElement.name);
}
},
'[name="food"] click': function(context, $ct) {
// input[name="food"]の要素に対してバリデーションを実行する
$ct.valid();
},
});
上半分はjQuery Validateをそのまま使っていますが、たとえばチェックボックス要素は送信時にのみ入力チェックが可能になっていますので、それを hifive のコントローラでバリデーション処理を実行させています。
'[name="food"] click': function(context, $ct) {
// input[name="food"]の要素に対してバリデーションを実行する
$ct.valid();
},
一つのコントローラ内で入力チェック周りの実装が完結するのでメンテナンスもしやすいかと思います。
hifive + jQuery Validation Pluginにてデモが可能です。

もちろんhifiveの入力チェックはクライアントサイドになりますので、サーバサイドは別途入力チェックを行うのが良いでしょう。しかし画面遷移したりすることなくリアルタイムに入力エラーが出せるのでユーザストレスは低く済むはずです。
HTML5の機能が充実し、JavaScriptが高速化するのに伴って、ローカルアプリケーションとWebアプリケーションの垣根がどんどん低くなってきています。数年前まではまるで無理だった多機能な操作もWebブラウザ上で実現できるようになっています。
とはいえファイルシステムやネットワークなど、まだまだWebアプリケーションだけでは完結できないこともあります。そこで使ってみたいのが、HTML5アプリケーションをラッピングしてローカルアプリケーション化するフレームワーク達です。なお、今回紹介するものは基本的にデスクトップPC(Windows)およびMac向けのアプリに変換するものです。
node-webkit
node-webkitはnode(node.js)/HTML5/JavaScriptでローカルアプリケーションを提供するソフトウェアです。nodeがネイティブの機能(ファイルシステムやネットワークなど)を提供し、JavaScriptで通信できるようにしています。
画面はChromium(Google Chromeのオープンソース版)を使っており、WebKit(最近ではBlink)ベースのレンダリングをサポートしています。
Web2Executable

Web2Executableはnode-webkit向けに作られたパッケージをランタイムとともにラッピングし、実行ファイルに変換します。Windows/Mac OSX/Linux向けに、それ単体で動作するバイナリに変換してくれます。
ランタイムを内包するため、その分サイズは大きくなります。とはいえ実行に際してnode-webkit環境のインストールが不要になりますので、配布時にはとても便利でしょう。
HTML5-Packer

HTML5-PackerはHTML5/JavaScript/スタイルシートをはじめ、さらに画像、オーディオ、動画も含めてすべて一つのファイルとしてラッピングしてくれるソフトウェアです。ラッピングすると一つのHTMLファイルができます。他にも何のファイルもいりませんので、Webアプリケーションとしての配布がとても楽になります。
slfsrv
slfsrvはHTML5/JavaScript/スタイルシートを読み込むためのWebサーバを提供します。slfsrvでラップされた実行ファイルを起動すると、Webサーバが立ち上がります。後はWebブラウザからアクセスすれば、Webアプリケーションとして利用できる仕組みです。Windows/Mac OSX/Linux向けに実行ファイルが生成されます。
HTML5-PackerはローカルのHTMLファイルとして利用するのでセキュリティ上の制限がありますが、slfsrvは外部リソース(JavaScriptなど)の読み込みにも対応しています。
Chromeless
ChromelessはMozillaが開発している技術で、xulrunnerを使ってHTML5/JavaScript/スタイルシートを一つのデスクトップ実行ファイルにラッピングします。ぱっと見ではWebブラウザのように見えますが、指定されたドメイン外には出られませんので、セキュリティ上も安心できる仕組みです。なお、現在は開発が終了しています。
Bowline
Bowlineは他のnodeとは違い、Rubyでローカル側の仕組みを作り、HTML5/JavaScriptでUIを作成します。開発は数年前から停止している模様です。
いかがでしょうか。意外と便利なのが利用者への配布ではないかと思います。URLを覚えてもらうのではなく、アプリケーションとして提供してしまえば起動するだけでサービスにアクセスできます。実際のデータはWeb APIを通じてサーバから提供する形でも良いでしょう。
さらにアプリケーションが限定されたドメインにしかアクセスできないことで、外部への不用意なデータ流出を避けると言った目的にも使えます。業務中で使う小さなアプリケーションをWeb化する際に使ってみてはいかがでしょう。
前回のChromeに続いてiOSでのテストになります。今回は実機ではなく、iOSシミュレータを使ってテストを行います。
テスト構成
iOSシミュレータの場合、Mobile Safariにて http://localhost/ と打つと母艦の http://localhost/ にアクセスします。そのためURLの扱いについてはデスクトップブラウザを使った時と変わりません。

問題があるとすれば、iOSシミュレータに対応したWebDriverの扱いになるかと思います。
ios-driverを使う
現在、iOSシミュレータに対応していて最も簡単に扱えそうなのがios-driverになります。Javaが入っていれば立ち上げられます。
なお、執筆時点での最新バージョン(0.6.6)ではiOS8には対応していないようです。実行すると次のようなエラーが出ます。
$ java -jar ios-server-standalone-0.6.6-SNAPSHOT-2.jar
:
Using Xcode install: /Applications/Xcode.app
Using instruments: version:6.1, build: 56160
Using iOS version 8.1
iOS >= 6.0. Safari and hybrid apps are supported.
Applications :
CFBundleName=Safari,CFBundleVersion=600.1.4,/Users/nakatsugawa/.ios-driver/safariCopies/safari-8.1.app
2014-11-11 11:04:26.106:INFO:oejs.Server:jetty-8.y.z-SNAPSHOT
2014-11-11 11:04:26.172:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:5555
04:44:281 INFO IOSSafariSimulatorManager.copySafariToAllowInstallByInstruments temporarily moving MobileSafari out of the install directory, if you need to restore it yourself use: $ cp -rf /Users/nakatsugawa/.ios-driver/safariCopies/MobileSafari-8.1.app /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator8.1.sdk/Applications/MobileSafari.app
Unable to get UUID for device iPhone Retina (4-inch) with SDK 8.1
04:44:442 WARNING NewSessionNHandler.safeStart Error starting the session.null
04:44:667 WARNING NewSessionNHandler.safeStart app has crashed at startup :normal
UUIDが取得できないというエラーになってうまく動きません。
解決する方法としては Apple Developer からXcodeのバージョン5をダウンロードして、そちらにスイッチするのが良さそうです。
$ sudo xcode-select -s /Applications/Xcode5.app/Contents/Developer/
Xcode5に切り替えたら ios-driver を起動します。
$ java -jar ios-server-standalone-0.6.6-SNAPSHOT-2.jar
45:54:180 INFO ApplicationStore.<init> App archive folder:/path/applications
version:663b7cc0a7a48ff629b1bcb39bbd78aed1c1e560
Beta features enabled (enabled by -real flag): false
Simulator enabled : true
Inspector: http://0.0.0.0:5555/inspector/
Tests can access the server at http://0.0.0.0:5555/wd/hub
Server status: http://0.0.0.0:5555/wd/hub/status
Connected devices: http://0.0.0.0:5555/wd/hub/devices/all
Applications: http://0.0.0.0:5555/wd/hub/applications/all
Capabilities: http://0.0.0.0:5555/wd/hub/capabilities/all
Monitoring '/path/applications' for new applications
Archived apps: /path/applications
Build info: ios-driver 0.6.6-SNAPSHOT (built:20141009-1559,sha:663b7cc0a7a48ff629b1bcb39bbd78aed1c1e560)
Running on: Mac OS X 10.10 (x86_64)
Using java: 1.7.0_60
Using Xcode install: /Applications/Xcode5.app
Using instruments: version:5.1.1, build: 55045
Using iOS version 7.1
iOS >= 6.0. Safari and hybrid apps are supported.
Applications :
CFBundleName=Safari,CFBundleVersion=9537.53,/Users/nakatsugawa/.ios-driver/safariCopies/safari-7.1.app
2014-11-11 11:46:01.797:INFO:oejs.Server:jetty-8.y.z-SNAPSHOT
2014-11-11 11:46:01.851:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:5555
ios-driverが起動したら、Seleniumテストの設定をします。
Capybara.app_host = "http://localhost:3000"
Capybara.register_driver :iphone do |app|
Capybara.default_wait_time = 60
Capybara::Selenium::Driver.new app,
browser: :remote,
url: 'http://(母艦のIPアドレス):5555/wd/hub',
desired_capabilities: {
browserName: 'iphone',
CFBundleDisplayName: 'Safari',
CFBundleExecutable: "MobileSafari",
platform: 'Mac',
simulatorVersion: '7.1',
simulator: true,
sdkVersion: "7.1",
variation: "Retina4",
locale: "ja_JP",
language: "ja",
version: '7.1'
}
end
この設定でテストを実行すると、iOSシミュレータが起動してテストが実行されます。

iPadを使ったテスト
設定をちょっと書き換えるだけでiPadでのテストにも対応します。
Capybara.register_driver :ipad do |app|
Capybara.default_wait_time = 60
Capybara::Selenium::Driver.new app,
browser: :remote,
url: 'http://192.168.100.100:5555/wd/hub',
desired_capabilities: {
browserName: 'ipad', # ここが違うだけ
CFBundleDisplayName: 'Safari',
CFBundleExecutable: "MobileSafari",
platform: 'Mac',
simulatorVersion: '7.1',
simulator: true,
sdkVersion: "7.1",
variation: "Retina",
locale: "ja_JP",
language: "ja",
version: '7.1',
deviceOrientation: 'landscape'
}
end
ios-driverはアプリのテストにも利用できますが、MobileSafariと指定することでHTML5のテストにも使えます。Selenium Serverの代わりにios-driverを立ち上げる程度の違いしかありませんので、モバイルファーストなテストをぜひ実施してください。
hifiveはMVCフレームワークであり、使用するUI部品に関しては基本的に制約がありません。要件に応じてマッチするものを選択できるようになっています。とはいえ、業務アプリケーションでよく使われる機能・パターンはやはり存在します。また、よく使われる部品だけに、機能性はもちろん互換性やパフォーマンスに関して高いレベルが求められることもしばしばです。そこで、hifiveではよく使われるUIコンポーネントを順次開発中です。
そこで、今回はその開発中ライブラリの中からチャートライブラリをご紹介します。ここでは機能をそぎ落としたシンプルな見た目で紹介します。
ユニットテストなどは当たり前に行われるようになっていますが、Webブラウザベースのテスト(いわゆる結合、機能テスト)はつい後に放っておかれがちです。UIは頻繁に変わるケースがあり、それがシステムと関係のない部分であってもテストが落ちる可能性があるため、一旦落ち着くまではそのままになり、いつしかテストが行われなくなったりします。
もちろんそのままで良いわけではなく、実際のユーザが使っている環境下でこそ正しく動いているか確認できなければなりません。そのためのツールとしてよく知られているのがSelenium + WebDriverでしょう。
現在の開発、テスト環境
クライアントPCの性能が向上するのに合わせてクライアントPC上に開発用のWebサーバを立ててその場で実行結果を確認する開発方法が当たり前になっています。さらにWindowsユーザの場合、開発環境と本番環境が異なるケースが多く(サーバがLinuxディストリビューションなど)VMWare Playerなどを使ってサーバOSの仮想環境を作って開発するのもよく行われてきました。
そんな中、最近ではVagrantを使ってVirtualBoxベースの仮想環境で開発を行うことが増えてきました。Vagrantを使った場合、Vagrantfileの配布だけで開発用サーバ環境が整ってしまうのがポイントです(もちろんVagrantのインストール、加えてVirtualBoxが必要ですが)。しかしこのようなケースにおいてSeleniumでどうテストを行うかといった情報があまり多くないようです。
従来はこのように一つのPC環境にWebブラウザ、Webサーバが入っています。つまりlocalhostでアクセスできる状態です。

それがVagrantによって環境が分離しています。さらに最近ではスマートフォン、タブレットのWebテストを行いたいというニーズも多いです。

次回以降詳しく書きますが、iOSの場合はMac OSX向けにシミュレータがあります。シミュレータは実行環境を模擬的に再現しています。外部から見た振る舞いを模倣しているだけです。つまりiOSシミュレータのSafariで http://localhost/ にアクセスすると、それは母艦にアクセスするのと同じことになります。
対してエミュレータはハードウェアレベルで再現しています。そのため、Androidエミュレータで http://localhost/ にアクセスすると、それはAndroidエミュレータ本体のWebサーバにアクセスするということになります。つまりAndroidエミュレータでテストする場合はVagrat – 母艦 – Androidエミュレータの3つの環境を橋渡ししなければなりません。Androidのテストについては次回説明します。
Google Chromeでのテスト
今回は分かりやすいところでGoogle Chromeを使ってテストを行います。WebアプリケーションはRuby on Railsを使っています。今回の目的にあったVagrantfileがrails/rails-dev-boxに公開されています。これをcloneして開発環境を整えます。

$ git clone https://github.com/rails/rails-dev-box.git
$ cd rails-dev-box
$ vagrant up
: しばらくかかります
$ vagrant ssh
$ cd /vagrant
$ rails new web -T # Rspecベースなのでテストを除外します。もしかすると sudo gem install rails が必要かも知れません。
$ cd web
このVagrantfileを見ると分かりますが、仮想環境側の3000番ポートがそのまま母艦の3000番ポートにつながっています。そのため母艦の http://localhost:3000/ にアクセスすると、仮想環境の http://localhost:3000/ にアクセスしたのと同じになります。また、 /vagrant がカレントディレクトリになりますので、そこにRailsアプリケーションを作成して母艦からファイル操作ができるようになっています。
必要なライブラリは以下の通りです。Gemfile に記載します。
gem 'rspec-rails'
gem 'capybara'
gem 'selenium-webdriver'
これらのインストール( bundle install && rails generate rspec:install)ができたら、 spec/support/capybara_drivers.rb を作成します。ここにはWebブラウザごとの設定を記述します。
Capybara.javascript_driver = ENV['DRIVER'] ? ENV['DRIVER'].to_sym : :chrome
Capybara.app_host = [:safari, :chrome, :firefox, :iphone, :ipad].include?(Capybara.javascript_driver) ? "http://localhost:3000" : "http://192.168.100.116:3000"
Capybara.default_wait_time = 10
Capybara.run_server = false
Capybara.register_driver :chrome do |app|
Capybara::Selenium::Driver.new app,
browser: :remote,
desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome,
url: "http://192.168.100.116:4444/wd/hub"
end
IPアドレス(192.168.100.116)はそれぞれ読み替えてください。4444番ポートはそのままで大丈夫です。
ここで注意して欲しいのは、 app_host と run_server です。app_hostは一度設定すると Capybara.register_driver のブロック内で上書きしても変更されないようです。そのため、テスト対象のブラウザによって見る場所を変えています。192.168.100.でアクセスするのはAndroidエミュレータまたは実機になります。
Capybara.run_serverのフラグを落としておかないと Androidエミュレータでのテストができませんでした(筆者はこれに1日ハマったのでご注意ください)。Selenium Serverへのアクセスがいかない場合はここが原因かも知れません。
テストのファイルは spec/features/ 以下に書きます。たとえば以下のようになります。
#spec/features/hello_spec.rb
require 'spec_helper'
describe "Web Test", type: :feature, js: true do
it "Access to root" do
visit "/"
page.should have_content("Home")
sleep(2)
end
end
sleepを2秒入れているのはテストが終わった瞬間にWebブラウザが閉じてしまうので確認用としてです。Rspecの書き方として has_content?もあるのですが、これは true/falseを返すのでpage.shouldに対しては使えないようです。ご注意ください。
この例を見て分かる通り、 http://localhost:3000/ にアクセスすると Homeという文字を出すだけです。そのチェックをしています。テストに備えてサーバを起動します。
$ rails s
=> Booting WEBrick
=> Rails 4.1.6 application starting in development on http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Notice: server is listening on all interfaces (0.0.0.0). Consider using 127.0.0.1 (--binding option)
=> Ctrl-C to shutdown server
[2014-10-29 07:35:39] INFO WEBrick 1.3.1
[2014-10-29 07:35:39] INFO ruby 2.1.3 (2014-09-19) [i386-linux-gnu]
[2014-10-29 07:35:39] INFO WEBrick::HTTPServer#start: pid=4076 port=3000
母艦の環境を整える
Google Chromeの場合はさほど難しくありません。Selenium Serverを公式サイトからダウンロードします。Google Chromeは必要なのでダウンロード、インストールしてください。
ダウンロードしたらSelenium Serverを起動します。
$ java -jar selenium-server-standalone-2.43.1.jar
16:33:42.764 INFO - Launching a standalone server
16:33:42.825 INFO - Java: Oracle Corporation 24.60-b09
16:33:42.825 INFO - OS: Mac OS X 10.10 x86_64
16:33:42.853 INFO - v2.43.1, with Core v2.43.1. Built from revision 5163bce
16:33:42.960 INFO - Default driver org.openqa.selenium.ie.InternetExplorerDriver registration is skipped: registration capabilities Capabilities [{platform=WINDOWS, ensureCleanSession=true, browserName=internet explorer, version=}] does not match with current platform: MAC
16:33:43.042 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub
16:33:43.043 INFO - Version Jetty/5.1.x
16:33:43.045 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
16:33:43.046 INFO - Started HttpContext[/selenium-server,/selenium-server]
16:33:43.046 INFO - Started HttpContext[/,/]
16:33:43.095 INFO - Started org.openqa.jetty.jetty.servlet.ServletHandler@59bf8a16
16:33:43.096 INFO - Started HttpContext[/wd,/wd]
16:33:43.114 INFO - Started SocketListener on 0.0.0.0:4444
16:33:43.114 INFO - Started org.openqa.jetty.jetty.Server@70eae613
このように起動して4444ポートで待ちの状態になります。
テストの実行
テストは仮想環境側で行います。つまり母艦側にはRuby/Ruby on Railsの環境は不要ということです。
$ /usr/bin/ruby2.1 -S rspec ./spec/features/hello_spec.rb
.
Finished in 7.97 seconds
1 example, 0 failures
Randomized with seed 61665

このように 仮想環境から母艦側のSelenium Serverを呼び出して、母艦のGoogle Chromeから仮想環境のWebアプリケーションをテストできるようになります。ざっくりと図にするとこのようになります。

SafariやFirefoxの場合、ほぼ同じ設定でいけます。
# Safariの場合
Capybara.register_driver :safari do |app|
Capybara::Selenium::Driver.new app,
browser: :remote,
desired_capabilities: Selenium::WebDriver::Remote::Capabilities.safari,
url: "http://192.168.100.116:4444/wd/hub"
end
# Firefoxの場合
Capybara.register_driver :firefox do |app|
Capybara::Selenium::Driver.new app,
browser: :remote,
desired_capabilities: Selenium::WebDriver::Remote::Capabilities.firefox,
url: "http://192.168.100.116:4444/wd/hub"
end
browser: :remote の設定が肝になります。
まとめ
最も大きな利点として、母艦(WindowsやMac OSX)であればGUIなのでWebブラウザを簡単に用意できるということです。たとえばLinuxサーバ上でテストしようと思った場合、PhantomJSやQtを使ったWebブラウザを用意しなければなりません。これは本来本番環境には不要なものですし、Qtをインストールするのはサイズが大きかったりします。Vagrantを使った仮想環境でもそれは同じです。また、それを行った場合でもテストはFirefox、Google Chromeまでで、その他のIEやiOS、Androidでのテストはできないでしょう。
母艦側のGUI画面でWebブラウザを実行するのは、よりユーザの環境に近いところでテストができるということです。かといって母艦側に開発環境を整えると、プロジェクトごとに必要なライブラリバージョンが違ったり、実行環境を整備するのは大変です。Vagrantを使えばすぐに同じ環境が実現できます。
次回は iOSシミュレータ、Androidエミュレータでのテスト方法についてご紹介します。ハマりどころが多いのでお役立てください。
通常、デバッグを行う際には既存のコードのあちこちにデバッグログを差し込んだりします。それでは修正が終わった後にクリーンなコードに戻すのも大変ですし、必要な部分を消してしまって余計なバグを作ることにもなりかねません。
そこで使ってみたいのがアスペクト(AOP)という仕組みです。hifiveではコントローラとロジックに対してアスペクトが適用できるようになっています。

デモ
例えば次のようなHTMLがあります。
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="UTF-8">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="-1">
<link rel="stylesheet" href="h5.css">
<script src="jquery.js"></script>
<script src="ejs-h5mod.js"></script>
<!-- 各モジュールのソースJSを読み込む -->
<script src="h5.js"></script>
<!-- ここで作成したjsファイルを読み込む -->
<script src="step13-1.js"></script>
<title>hifive Aspectの適用</title>
</head>
<body>
<div id="container">
<input type="button" id="btn" value="hello world!">
</div>
</body>
</html>
コントローラは step13–1.js になります。
// step13-1.js
$(function() {
var helloWorldController = {
__name: 'HelloWorldController',
'#btn click': function() {
alert('Hello, World!');
}
};
// id="container"である要素にコントローラをバインド
h5.core.controller('#container', helloWorldController);
});
このコードを見て分かる通り、#btnのクリックイベントに対してアラートを出しているのみです。ここにアスペクトを適用します。コードは h5preinit.js です。
<!-- hifiveのpreinitイベントで処理をさせるために、h5.jsより先に読み込む -->
<script src="h5preinit.js"></script> <!-- ← 追加します -->
<!-- 各モジュールのソースJSを読み込む -->
<script src="../../archives/current/h5.js"></script>
h5preinit.jsの内容は次のようになります。
// h5preinit.js
$(document).bind('h5preinit', function() {
// Loggerのレベルの設定
h5.settings.log = {
defaultOut: {
level: 'trace',
targets: 'console'
}
};
var aspect = {
target: 'HelloWorldController',
interceptors: h5.core.interceptor.lapInterceptor,
pointCut: '#btn click'
};
h5.settings.aspects = aspect;
});
aspectというオブジェクトはコントローラ、補足するイベントに加えてインターセプターを定義しています。h5.core.interceptor.lapInterceptorは処理の開始と終了時間を出力します。コードは次のようになります。
var lapInterceptor = h5.u.createInterceptor(function(invocation, data) {
// 開始時間をdataオブジェクトに格納
data.start = new Date();
// invocationを実行
return invocation.proceed();
}, function(invocation, data) {
// 終了時間を取得
var end = new Date();
// ログ出力
this.log.info('{0} "{1}": {2}ms', this.__name, invocation.funcName, (end - data.start));
});
createInterceptorはインターセプト先関数の実行前と、後に実行される関数を定義します。inovocationという変数は以下のプロパティを持ちます。
- target
- インターセプト対象の関数が属しているコントローラまたはロジック
- func
- インターセプト対象の関数
- funcName
- インターセプト対象の関数名
- args
- 関数が呼ばれたときに渡された引数(argumentsオブジェクト)
- proceed
- インターセプト対象の関数を実行する関数。インターセプト対象の関数は自動では実行されません。 インターセプト先の関数を実行するには、 preに指定した関数内でinvocation.proceed()を呼んでください。 proceed()を呼ぶと対象の関数(invocation.func)を呼び出し時の引数(invocation.args)で実行します。 proceed自体は引数を取りません。
実際に実行するとDevToolsのコンソールに次のように出力されます。
[INFO]19:55:11,641: HelloWorldController.#btn clickが開始されました。
[INFO]19:55:11,646: Arguments[2]
[INFO]19:55:13,168: HelloWorldController.#btn clickが終了しました。 Time=1517ms
このようにして関数の実行前と後をチェックできるようになります。インターセプターは自作できますので、実際に稼働しているコードを編集することなくデバッグ作業を効率的に行えるようになります。
今回のコードはhifive Aspectの適用にて試すことができます。コンソールを開いてその出力結果をご覧ください。
HTML5で注目したいAPIの一つにWeb Storage(localStorage, sessionStorage)があります。いわばCookieのようにWebブラウザ内にデータを蓄積できる仕組みになりますが、Cookieとは違って外部のサーバに飛ばすことなく、ローカルでのみ使えるデータになります。
まだまだ利用実績としては多くありませんが、localStorageを扱うライブラリは増えてきています。そこで今回は先進的事例をもとに使い方をはじめ、実際どういった場面で活きてくるのかを紹介します。
