モンモンブログ

技術的な話など

Action Mailerのマルチパートメールでファイル形式の優先順位が変わっちゃう件

Action Mailer でマルチパートメールを送るようにしていて、かつ mail メソッドにブロックを渡す場合は注意が必要です。html 版、text 版の優先順位が意図せず変わってしまう場合があります。

環境

MacOSX Mavericks
ruby 1.9.3p547 (2014-05-14 revision 45962) [x86_64-darwin13.3.0]
rails-3.2.11
actionmailer-3.2.11

そもそもマルチパートメールって?

1通のメール中に複数の形式のメール本文を含められる機能です。

例えば html 形式と text 形式、両方のメール本文を含めれば、html 対応のメール表示ソフトではリッチな html 形式で表示させ、そうでなければ text 形式で表示させる、てことが可能です。

マルチパートメール on Rails

rails でマルチパートメールを送るのは超簡単。mailer のテンプレートとして複数の形式のファイルを用意しておくだけです。

app/views/user_mailer/password_reset.html.erb    # html版
app/views/user_mailer/password_reset.text.erb   # text版

あとは普通にメールを送信するだけ。

UserMailer.password_reset(user).deliver

送信されるメールの内容はこんな感じ。1本のメールに複数の形式が含まれてるのが分かると思います。

Sent mail to xxxx@skimatalk.com (1786ms)         # メールヘッダ
Date: Mon, 02 Feb 2015 11:09:00 +0900
From: noreply@skimatalk.com
To: xxxx@skimatalk.com
Message-ID: <xxxx>
Subject: xxxx
Mime-Version: 1.0
Content-Type: multipart/alternative;            # Content Type でマルチパート指定
 boundary="--==_mimepart_54cedc31b283f";        # 各パートの境界となる文字列を定義
 charset=UTF-8
Content-Transfer-Encoding: 7bit



----==_mimepart_54cedc31b283f                   # パート境界1 (text版ここから)
Date: Mon, 02 Feb 2015 11:09:00 +0900           # text版メールヘッダ
Mime-Version: 1.0
Content-Type: text/plain;
 charset=UTF-8
Content-Transfer-Encoding: base64
Content-ID: <xxxx>

44G744GS44G744GS44G744GS44G744GS44G744GS44G7    # text版メール本文 (base64 encoded)
44GS44G744GS44G744GS44G744GS44G744GS44G744GS
44G744GS44G744GS44G744GS44G744GS44G744GS44G7
44GS44G744GS44G744GS44G744GS44G744GS44G744GS

----==_mimepart_54cedc31b283f                   # パート境界2 (html版ここから)
Date: Mon, 02 Feb 2015 11:09:00 +0900           # html版メールヘッダ
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: base64
Content-ID: <xxxx>

44G744GS44G744GS44G744GS44G744GS44G744GS44G7    # html版メール本文 (base64 encoded)
44GS44G744GS44G744GS44G744GS44G744GS44G744GS
44G744GS44G744GS44G744GS44G744GS44G744GS44G7
44GS44G744GS44G744GS44G744GS44G744GS44G744GS

----==_mimepart_54cedc31b283f--                 # パート境界3 (メール末尾)

各形式の優先順位は ActionMailer::Basedefault メソッドparts_order の値をセットすることで指定出来ます。この値はデフォルトで ["text/plain", "text/enriched", "text/html"] となってます(参考)。各形式の内容はこの順番で出力されます(先ほどの例も然り)。

class UserMailer < ActionMailer::Base
  default parts_order: ["text/plain", "text/enriched", "text/html"]
  
  def password_reset(user)
    ...
  end
end

この順番だと、一番上に出力される text/plain 形式の内容が最優先で表示されそうですが、違います。 RFCに、表示の際の優先順位は逆順とするように定められており、この場合、一番下の text/html が最優先となります。

この理由もRFCにありました。もっともシンプルな形式を一番上に出力するようにしておけば、MIME非対応のメール表示ソフトであっても読みやすいよね、ということのようです。なるほどちゃん。

placing the plainest alternative first is the friendliest possible option when mutlipart/alternative entities are viewed using a non-MIME- compliant mail reader.

mail メソッドにブロックを渡すと parts_order 指定が無視されちゃう

mail メソッドにはブロックを渡すことが出来ます。下記のように、ファイル形式ごとにレイアウトを指定出来たりします。

class UserMailer < ActionMailer::Base
  default parts_order: ["text/plain", "text/enriched", "text/html"]
  
  def password_reset(user)
    mail to: 'xx@skimatalk.com', subject: 'hello!' do |format|
      format.text { render layout: 'mailer' }
      format.html { render layout: 'mailer' }
    end
  end
end

これで、

app/views/layouts/mailer.text.erb
app/views/layouts/mailer.html.erb

がメールのレイアウトとして使われるって寸法。

が、ここに落とし穴があります。

      format.text { render layout: 'mailer' }
      format.html { render layout: 'mailer' } # html形式が後

この順番を逆にして

      format.html { render layout: 'mailer' }
      format.text { render layout: 'mailer' } # text形式が後

ってしちゃうと、parts_order での指定を無視して、html 形式が先、text 形式が後に出力されます。 すると RFC のルール通り、text 版の方が優先して表示されちゃいます。html 版は決して表示されなくなります。なんと。

ActionMailer::Base のドキュメントを読んでもそんなこと書いてないですねえ。(該当箇所は "If you want to explicitly render only certain templates..." らへんから)

参考

ActionMailer overrides header[:parts_order] when a block is passed to #mail · Issue #7978 · rails/rails

Rails + Grape 構成で Grape API ファイルを自動再読み込みさせるには

RESTful な API が楽ちんに書ける graperails との組み合わせで使う場合も README に従うだけで簡単に出来ますが、なぜか自動再読み込み (auto reloading) されないって問題にぶち当たります。

development 環境だと model や controller への修正はブラウザをリロードするだけで即反映されますよね。でも grape の api ファイルはなぜか再読み込みされない。いちいち rails サーバを再起動しないといけなくて、非常に困っちゃんです。

(よく理解してませんが rails 上で別の rack フレームワーク(この場合 grape)を動かそうとするとrails の自動再読み込みの仕組みがうまく動かないみたいです)

で、解決方法ですが、grape api ファイルの更新を検知して、無理やり再読み込みさせてやります。

環境

古くてごめんなさい

MacOSX Mavericks
ruby 1.9.3p547 (2014-05-14 revision 45962) [x86_64-darwin13.3.0]
rails-3.2.11
grape-0.9.0

セットアップ

今回は既存の rails アプリに grape を追加しました。手順をざくっと書いておきます。

Gemfile に追記して、

gem 'grape'

インストール

bundle install

grape api ファイルを置くディレクトリを作って

mkdir app/api

Hello World なやつを書いた。(app/api/skimatalk_api.rb)

require 'grape' # この行は grape 単体で動かす場合に必要。rails との組み合わせでは不要
class SkimatalkApi < Grape::API
  format :json

  resource :ehehe do
    desc 'this is a test'
    get :hoe do
      {a: 1, b: 2}
    end
  end
end

rails と組み合わせて実験する前に grape 単体で動かしてみたかったので、同じディレクトリにテスト用の config.ru を作成 (app/api/config.ru)

# coding: utf-8
require './skimatalk_api.rb'
run SkimatalkApi

起動

$ cd app/api
$ rackup
Thin web server (v1.6.2 codename Doc Brown)
Maximum connections set to 1024
Listening on 0.0.0.0:9292, CTRL+C to stop
127.0.0.1 - - [22/Nov/2014 19:54:05] "GET /ehehe/hoe HTTP/1.1" 200 13 0.0971

http://localhost:9292/ehehe/hoe にアクセスすると JSON が表示された。わーい。

f:id:ymdsmn:20141122201157p:plain

(さっき作った config.ru はもう不要なので削除してよいです)

今度はこれを rails 上で動かします。 config/routes.rb に以下を追加して /api/* へのリクエストを grape へ渡すようにします

  mount SkimatalkApi => '/api'

サーバ再起動してから、

rails s

http://localhost:3000/api/ehehe/hoe にアクセス。JSON が表示された。やったね。

f:id:ymdsmn:20141122201201p:plain

でも(さっきも言ったとおり)app/api/skimatalk_api.rb を修正してリロードしても変更が反映されません。困ったね。

解決方法

ここからが本題。 config/initializers/reload_api.rb を作って以下のように書きます

if Rails.env.development?
  api_reloader = ActiveSupport::FileUpdateChecker.new(Dir['app/api/*']) do # app/api/* は環境にあわせて変更すること
    Rails.application.reload_routes! # or do something better here
  end

  ActionDispatch::Callbacks.to_prepare do
    api_reloader.execute_if_updated
  end
end

これだけで、 app/api/* への修正を検知して自動再読み込みしてくれるようになりました。

仕組みは読めばなんとなく分かるよね。分かんなくてもいいよね。

参考

正直このエントリは stackoverflow のこれ↓を解説しただけです。ググって見つけるのに苦労したので書きました…
Ruby on Rails 3 - Reload lib directory for each request - Stack Overflow

jQuery プラグインを bower のレジストリに登録してみた

表題の通り、jQuery プラグイン jquery.narrowsbowerレジストリに登録してみた時の記録です。

bower とは?

こちらが非常に分かりやすかったです。

基礎編の冒頭から(勝手に)引用させて頂きますと、bower とは

Twitter社が作ったフロントエンド用のパッケージマネージャです。 Java で言う MavenRuby で言う gem、 Perl で言う cpan のようなものです。 Node.jsには npm と呼ばれるパッケージマネージャがありますが、それに強く影響を受けています。

ということです。

bower のパッケージは bower レジストリってところで管理されています。 登録済みパッケージの一覧は Bower components ってページで見られます。検索もできます。

この bower レジストリにおいらの jQuery プラグインをいっちょ登録したるぜ!と思い立ちました。

bower レジストリに登録すると何が嬉しいの?

ここに登録しておけば、

bower search で検索したり("sinon" は javascript のテスト用ライブラリです)

$ bower search sinon
Search results:

    sinon git://github.com/cjohansen/Sinon.JS.git
    sinon-chai git://github.com/domenic/sinon-chai.git
    sinonjs git://github.com/blittle/sinon.js.git
(以下略)

bower info でインストール可能なバージョンを調べたり

$ bower info sinon
bower sinon#*               not-cached git://github.com/cjohansen/Sinon.JS.git#*
bower sinon#*                  resolve git://github.com/cjohansen/Sinon.JS.git#*
bower sinon#*                 download https://github.com/cjohansen/Sinon.JS/archive/v1.7.3.tar.gz
bower sinon#*                  extract archive.tar.gz
bower sinon#*                 resolved git://github.com/cjohansen/Sinon.JS.git#1.7.3

{
  name: 'sinon',
  homepage: 'https://github.com/cjohansen/Sinon.JS',
  version: '1.7.3'
}

Available versions:
  - 1.7.3
  - 1.7.1
  - 1.7.0
(中略)
  - 0.6.0
  - 0.5.0
  - 0.2.3

You can request info for a specific version with 'bower info sinon#<version>'

bower install で指定したバージョンをダウンロードしたり出来ます。

$ bower install sinon#1.7.3
bower sinon#1.7.3               cached git://github.com/cjohansen/Sinon.JS.git#1.7.3
bower sinon#1.7.3             validate 1.7.3 against git://github.com/cjohansen/Sinon.JS.git#1.7.3
bower sinon#1.7.3              install sinon#1.7.3

sinon#1.7.3 bower_components/sinon

デフォルトで bower_components ディレクトリ以下にダウンロードされます。

$ ls bower_components/sinon
AUTHORS        LICENSE        build*         lib/           release.sh*
Changelog.txt  README.md      jsl.conf       package.json   test/

JavaScript ライブラリがコマンドラインだけでダウンロード出来ちゃうのがステキです。 いちいちググって、ダウンロードやら git clone やらして、って手間が不要です。

(あと npm の package.jsondependency や devDependency と同様の機能も備えますがここでは触れません)

bower レジストリ登録への道のり

  1. bower.json を作ってリポジトリにコミットして、
  2. リリースバージョン番号をタグ付けして、
  3. bower register コマンドを叩く

という感じ。簡単。順に説明します。

0. bower をインストール

npm でインストール。

$ npm install -g bower
$ bower -v
1.2.8

1. bower.json を作成

bower init コマンドを叩いて質問に答えていくと bower.json の雛形が生成できます。

$ bower init
[?] name: jquery.narrows
[?] version: 0.3.1
[?] description: jQuery Hierselect Plugin
[?] main file: jquery.narrows.js
[?] keywords: jQuery,select,hierselect
[?] authors: simon <xxxxx@gmail.com>
[?] license: MIT
[?] homepage: https://github.com/monmonmon/jquery.narrows
[?] set currently installed components as dependencies? Yes
[?] add commonly ignored files to ignore list? Yes
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry?
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry?
No

{
  name: 'jquery.narrows',
  main: 'jquery.narrows.js',
  version: '0.3.1',
  homepage: 'https://github.com/monmonmon/jquery.narrows',
  authors: [
    'simon <xxxxx@gmail.com>'
  ],
  description: 'jQuery Hierselect Plugin',
  keywords: [
    'jQuery',
    'select',
    'hierselect'
  ],
  license: 'MIT',
  ignore: [
    '**/.*',
    'node_modules',
    'bower_components',
    'test',
    'tests'
  ]
}

[?] Looks good? Yes

それを手直しして、コミット。

$ vim bower.json
$ git add bower.json
$ git commit
$ git push

ちなみに手直しした結果はこんな感じ。

{
  "name": "jquery.narrows.js",
  "version": "0.3.1", // <-gitでのバージョン番号を記述
  "description": "jQuery Hierselect Plugin",
  "license": "MIT",
  "main": "jquery.narrows.js", // <-パッケージのメインとなるファイル
  "ignore": [ // <-bower install した時にダウンロードさせたくないファイルのリスト
    "**/.*",
    "**/*.html",
    "Gruntfile.coffee",
    "node_modules",
    "README.md",
    "package.json",
    "lib",
    "spec"
  ]
}

さっきのBower入門(応用編)にも書かれていますが、 "main" と "ignore" をキチンと書かないと bower install した時に余計なものまでダウンロードしちゃって鬱陶しいので、気をつけて記述します。 (例えば Gruntfile.coffee はライブラリ利用者には不要なので "ignore" に含めてます。)

あと "version" にも要注意。ここに書いたバージョン番号を、次で git tag でタグ付けします。

2. リリースバージョン番号をタグ付け

bower.json に書いたバージョン番号をタグ付けしてやります。 bower はこのバージョン番号に基いてパッケージを管理します。

$ git tag 0.3.1
$ git push --tags
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:monmonmon/jquery.narrows.git
 * [new tag]         0.3.1 -> 0.3.1

バージョン 0.3.1 がリリースされました。

3. bower register

さていよいよ、ライブラリをレジストリへ登録します。コマンドの書式は

bower register <my-package-name> <git-endpoint>

です。

$ bower register jquery.narrows git@github.com:monmonmon/jquery.narrows.git
bower                          convert Converted git@github.com:monmonmon/jquery.narrows.git to git://github.com/monmonmon/jquery.narrows.git
bower jquery.narrows#*         resolve git://github.com/monmonmon/jquery.narrows.git#*
bower jquery.narrows#*        download https://github.com/monmonmon/jquery.narrows/archive/0.3.1.tar.gz
bower jquery.narrows#*         extract archive.tar.gz
bower jquery.narrows#*        resolved git://github.com/monmonmon/jquery.narrows.git#0.3.1
[?] Registering a package will make it installable via the registry (https://bower.herokuapp.com), continue? (Y/n)
bower jquery.narrows          register git://github.com/monmonmon/jquery.narrows.git

Package jquery.narrows registered successfully!
All valid semver tags on git://github.com/monmonmon/jquery.narrows.git will be available as versions.
To publish a new version, just release a valid semver tag.

Run bower info jquery.narrows to list the available versions.

ほんとに登録されたのか確認してみましょう。

$ bower info jquery.narrows
bower jquery.narrows#*          cached git://github.com/monmonmon/jquery.narrows.git#0.3.1
bower jquery.narrows#*        validate 0.3.1 against git://github.com/monmonmon/jquery.narrows.git#*

{
  name: 'jquery.narrows.js',
  version: '0.3.1',
  main: 'jquery.narrows.js',
  description: 'jQuery Hierselect Plugin',
  license: 'MIT',
  ignore: [
    '**/.*',
    '**/*.html',
    'Gruntfile.coffee',
    'node_modules',
    'README.md',
    'package.json',
    'lib',
    'spec'
  ],
  homepage: 'https://github.com/monmonmon/jquery.narrows'
}

Available versions:
  - 0.3.1

You can request info for a specific version with 'bower info jquery.narrows#<version>'

出た出た!

Bower components でも、検索フィールドに "jquery.narrows" って入力するとちゃんと表示されました。

試しに bower install してみる

今登録したライブラリがちゃんと bower install 出来るかも実験してみましょう。

$ bower install jquery.narrows#0.3.1
bower jquery.narrows#0.3.1      cached git://github.com/monmonmon/jquery.narrows.git#0.3.1
bower jquery.narrows#0.3.1    validate 0.3.1 against git://github.com/monmonmon/jquery.narrows.git#0.3.1
bower jquery.narrows#0.3.1     install jquery.narrows#0.3.1

jquery.narrows#0.3.1 bower_components/jquery.narrows

そしたらホラホラ!

$ ls -l bower_components/jquery.narrows
bower.json             jquery.narrows.js      jquery.narrows.min.js

ひゃっほい。

bowser.json の "ignore" をちゃんと書いたおかげで、余計なファイルを(ほぼ)含まずに js ファイルだけダウンロードすることが出来ました。(bower.json 自身だけ "ignore" に入れるのを忘れてたけど…笑)

というわけで

快適な bower ライフをお楽しみ下さい(とってつけた)

JSON 形式で設定ファイル書かせるの、やめてもらえません?

設定ファイルを JSON 形式で記述するライブラリやフレームワークって、

などなどいくつかあるけど(例が偏っててすみません)、

JSON って文法が結構デリケートなので、人間が(読む分にはいいけど)書くのには適してないと思うんですよね。

1. コメントが書けない!

JavaScript みたいにコメント書けません。

  ...
  "devDependencies": {
    //"grunt": "0.4.2", ちょっと退避
    "grunt": "0.4.1", // 古いバージョンに戻す
    "grunt-contrib-watch": "0.5.3",
    "grunt-contrib-uglify": "0.2.4"
  },
  ...

とか書けさえしたらどれだけ管理が楽になることか!

2. 連想配列やリストの要素を区切るカンマに注意する必要がある

↓は JSON としてはシンタックス違反ですが、どこが間違ってるか分かりますか?

  ...
  "devDependencies": {
    "grunt": "0.4.2",
    "grunt-contrib-watch": "0.5.3",
    "grunt-contrib-uglify": "0.2.4",
  },
  ...

答えは連想配列の最後がカンマで終わってるところです。正しくはこう。

  ...
  "devDependencies": {
    "grunt": "0.4.2",
    "grunt-contrib-watch": "0.5.3",
    "grunt-contrib-uglify": "0.2.4" // <- 最後に , があっちゃダメ
  },
  ...

これはリストでも同様です。

  ...
  "keywords": [
    "hoe",
    "hoehoe",
    "ehehe" // <- 最後に , があっちゃダメ
  ],
  ...

連想配列やリストに要素を追加したり並べ替えたりするのって頻繁にやるのに、その度にいちいちカンマに気を配るのって超めんどくさい。

もちろん、末尾のカンマだけでなく、要素と要素の間のカンマ忘れもありがちなミスですよね。

3. 文字列は必ずダブルクォートで囲まないといけない

JavaScript のオブジェクトリテラルでは

{
    "foo": "aaa", // ダブルクォートで囲んだり
    'bar': 'bbb', // シングルクォートで囲んだり
    buz: 'ccc',   // ていうか key はクォートで囲む必要すらない
}

って書けるけど、JSON では

  • 文字列はシングルクォートではなく、必ずダブルクォートで囲まないといけない
  • value だけでなく key も、文字列である場合はダブルクォートで囲まないといけない

ので、さっきの例は

{
    "foo": "aaa",
    "bar": "bbb",
    "buz": "ccc"
}

て書かないといけないです。

だからさー

設定ファイルは YAML 形式で書かせて下さいお願いします。。。

上で挙げた例すべて、YAML にするだけで一発解決ですよ。

ライブラリやフレームワークを管理してる方 or これから作るという方はどうぞご検討下さいm(_ _)m

jasmine + スクリーンショット作成サービスでWebアプリを複数ブラウザで一括動作確認!

この投稿は JavaScript - Client Side - Advent Calendar 2013 の13日目の参加記事です。

JavaScript のテスティングフレームワーク jasmine でテストを書いておくと、コードをいくらいじってもブラウザのリロード一発で動作確認できてそれだけでもステキです()。

でも更に、「スクリーンショット作成サービス」と組み合わせて利用すれば、複数の OS の複数のブラウザで一気にまとめて動作確認できてしまってステキングです。

このエントリでは、

  1. スクリーンショット作成サービスをいくつか紹介して、
  2. それら + jasmine による一括動作確認の方法について書いて、
  3. 最後に実際にやってみた例を紹介

します。

それではGO。

スクリーンショット作成サービス

を、2つ+αほど紹介。

1. browserstack.com の Screenshots

f:id:ymdsmn:20131211183553p:plain

動作確認したいページのURLを入力して、めぼしいブラウザを選択して(デフォルトで20ブラウザ選択済、最大25まで選択可)、画面一番下の "Generate screenshots" をクリックすると、

f:id:ymdsmn:20131211183558p:plain

こんな風にぞくぞくとスクリーンショットが送られてくる。

対応OS、対応ブラウザが盛りだくさんでステキ。なにより、スマホ対応なサービスってここしかないかも。

縦に長いウェブページも、画面の上から下までスクロールして撮ってくれます(確認した限り、多分全ブラウザで)。

欠点は、一度に25ブラウザまでしか選択できない点。(月額払えばこの制限はなくなる??)

また、無料で撮れるスクショ数はトータル100件までです。動作確認するブラウザを絞ってうまく利用しないといけない。Screenshots だけの利用であれば、月額$19でこのリミットはなくなるみたいです。

2. browsershots.org

f:id:ymdsmn:20131211190156p:plain

Linux, Windows, Mac, BSD に対応。

無料アカウント登録さえすれば、ブラウザ数の制限なしで、一気にまとめてスクショが撮れちゃうのがステキすぎる。アカウント登録なしでも1日あたり100ブラウザ?くらいまでなら多分利用可能。

LinuxBSD 対応ってのも、動作確認するサービスによっては重要でしょう。

撮ったスクショには有効期限があり、無料アカウント登録すれば30分、アカウントなしなら14分。

欠点としては、スクショを撮るホスト&ブラウザの提供を有志に頼っているため、対応ブラウザがちょこちょこ変動します。ついこないだは Mac の対応ブラウザは Safari が2つあったはずなのに、今みたら Mac の対応ブラウザ数ゼロになってた。。。

また、僕が見てる限り Mac の登録ブラウザ数が少ないです。(これはたまたまなのか、常にこうなのか?)

あと、スクロールの必要なページの場合でも、画面の1番上だけしか撮ってくれません。

とはいえ、Windows の対応ブラウザの多さと、無料でこれだけ多数のブラウザのスクショをまとめて一気に撮れるというのは強いです。

ちなみに、画面下の方のボタンで Windows ブラウザのみ全て選択、とか出来ます。

3. その他のサービス

screenshots.jp
月額払わないとスクショの撮れるブラウザが少なすぎるので試してないです(´・ω・`) 主要OSの主要ブラウザは対応しているようです。

browsershots.at
撮れるのは Windows VistaFirefox のみ(´・ω・`)

jasmine のテスト結果をまとめてスクリーンショット

さて、

これらスクリーンショット作成サービスで jasmine のテスト結果のスクショを撮れば、

色んな環境でズガッとまとめて動作確認出来ちゃうぜ!というのが今回のお話。

ブラボー!おお・・・ブラボー!!

f:id:ymdsmn:20131211185020j:plain

ただ、jasmine のテスト結果って画面一番下に表示されるから、1画面に収まるようなコンパクトなWEBアプリケーションでもない限り、スクショ一覧画面のサムネイルでは確認出来そうにないです。

いちいちサムネイルをポチポチクリックして、個別の画像を開いて、画像の一番下までスクロールして確認しないといけない。それってめんどくさい。(ていうか browsershots.org の場合は画面1番上しか撮れないのでそれすら無理。)

どうせなら、スクショ一覧画面でサムネイルを眺めるだけでテスト結果を確認したいですよね。

じゃー CSS or JavaScript で、jasmine のテスト結果を画面1番上に移動しちゃえばいいんじゃない?

jasmine テスト結果を画面1番上に表示させるには

jasmine-1.3.1 と jasmine-2.0.0-rc5 とで調べてみました。それぞれ、テスト結果を収めてるDOM要素がちょこっと異なります。

jasmine-1.3.1 の場合

テスト結果は id="HTMLReporter" な div に収められてます。

CSSでやるなら

#HTMLReporter {
  position: absolute;
  top: 0px;
  width: 100%;
  background-color: white;
}

jQuery でやるなら、

jasmineEnv.execute();

を呼んでる箇所の直後に

$('#HTMLReporter').remove().prependTo('body');

でオッケー。

jasmine-2.0.0-rc5 の場合

テスト結果は class="html-reporter" な div に収められてます。

CSSでやるなら

.html-reporter {
  position: absolute;
  top: 0px;
  width: 100%;
  background-color: white;
}

jQuery でやるなら、boot.js の下の方にテストをキックしてる箇所があるので、その直後に以下のように1行追加してやればいける。

  // ...
  window.onload = function() {
    if (currentWindowOnload) {
      currentWindowOnload();
    }
    htmlReporter.initialize();
    env.execute();                  // <-jasmineテスト実行
    // 以下を追加
    $('div.html-reporter').remove().prependTo('body');
  };
  // ...

実際にスクショを撮ってみた

拙作の jQuery プラグイン jquery.narrows.jsサンプルページ兼テストページ(の、テスト結果を一番上に移動したversion)で実験してみました。

まずは Screenshots

f:id:ymdsmn:20131212043922p:plain

サムネイルだけ眺めても大体分かりますよね?サムネイルのてっぺんに緑のバーが出ていれば成功、赤のバーならテスト失敗です。

  • Windows 7 の IE8(中段左から2番目)で赤いバーが出てるのが見える。テスト失敗してますがな。 元サイズの画像を開いて、エラーの内容も確認出来た。
  • Amazon Kindle Fire 2, Amazon Kindle Fire HD, Google Nexus 7 では、23個のテストすべて終了する前の時点のスクショが撮れてしまってた(そのため青っぽいバーが見えてます)。ひょっとして Kindle や Nexus は JavaScript の実行速度が遅いんでしょうか? iPhoneiPad はちゃんと成功してるのにな?
  • 一番最後の iPad 3rd (7.0)(びっくりマークのやつ)はタイムアウトした模様。ブラウザが多すぎると、最後の方のブラウザはこんな風にタイムアウトしてしまうっぽい。
  • IE6, IE7(上段右端、中段左端)だけ、テスト結果がどこにも表示されてませんでした…。JavaScript がオフなのか、jasmine が実行できてないのか、それともさっき追加した CSS がいけないのか、不明。

次に browsershots.orgWindows の全ブラウザのみ選択して、試してみました。

f:id:ymdsmn:20131211193108p:plain

105ものブラウザのスクショをリクエストしても粛々と任務遂行してくれるこの度量の深さ。ありがたいことです。(ここに表示してるのは一部のみです。)

  • MSIE 8.0, Firefox 1.0.8, Netscape 8.0.4, Netscape 7.1 でエラーを確認。 MSIE 8.0 でのエラーはさっきの結果と矛盾しません。それ以外のブラウザでのエラーは単に古すぎるためのようです。
  • いくつかのブラウザで、スクショ作成サーバの起動か何かに失敗していて、スクショが正常に撮れていませんでした(デスクトップにコマンドプロンプトだけ表示されてるやつとかです)。有志さん頼りな以上、こういうエラーはある程度仕方ないんでしょう。

こんな感じでした。なんだか色んなケースが確認出来てこれはいいサンプル(自画自賛)。

そして期せずして、jquery.narrows.js が IE8 で動作しないことが分かっちゃいました。直さなくちゃ…。僕Windowsマシン持ってないので、これ、そうそう気付けないバグですよ。

すごくない?(・ω・)-3

まとめ

みんな jasmine でテスト書こうよ。いいから書こうよ。