Islands in the byte stream

Technical notes by a software engineer

JavaScript libraryのREADMEにブラウザ互換性表バッジを表示することについての諸々

ブラウザ互換性表 (a.k.a. browser matrix) とは、こういうやつです。

f:id:gfx:20190513093113p:plain
ブラウザ互換性表 powered by Sauce Labs

TypeScriptで MessagePack encoder/decoder を実装した - Islands in the byte stream で作った msgpack/msgpack-javascript にこのバッジをつけようとして苦労しました。今回は単に一度やってみたかったというのもあって頑張りましたが、いろいろ大変だったので記録を残しておきます。

しかし、どんなプロジェクトでもやるべきかというと微妙で、ブラウザの機能に大きく依存するライブラリでもない限りはバッジは頑張らなくてもいいかなあという結論です。ブラウザに依存した機能をもっと多用するのであれば、バッジの価値があるのかもしれません。

今回はブラウザテストをはじめてから1つだけIE11で発現するバグを直したんですが、修正サイクル自体はIE11 on VirtualBoxで回しましたしね。

一方で、CI環境という意味ではIE11などテストするのが少し面倒なブラウザでCIを回すのは意味があるとは思います。

ブラウザ互換性表バッジサービス

SauceLabsTestingBottestling などがあります…が、testlingは今は動いてなさそう? SauceLabs は時間制限があるもののfree trialがあって、OSSの場合は別途Open Sauceを申請することもできます*1

今回は一番つかわれてそうなSauceLabsにしました。なおSauceLabsにsignupしたら即アカウントがdisableされました…。問い合わせたら「乱用防止ロジックが誤動作したのかも。確認するのでテストしたいリポジトリを教えてくれる?」みたいなやり取りをして有効にしてもらったりしました。サポートのやりとり自体はスムーズにできたのでよかったです。

SauceLabsはそれなりに設定すればちゃんと動きます。が、今回使ったKarmaだと設定方法がいまいち不明で、githubで filename:karma.conf.js saucelabs などして動いているものをみつけて参考にする、などのがんばりが必要でした。

Karma

任意のユニットテストをブラウザで実行するフレームワークです。

karma-runner.github.io

karma-chrome-launcherkarma-firefox-launcher などを使ってヘッドレスブラウザで動かすとローカルでもサクッと動くしTravisなどでも実行できます。IE11も modern.IE のVMをもともとVirtualBoxにいれていて、 karma-virtualbox-ie11-launcher で無事テストできました。

SauceLabs用の karma-sacelabs-launcher もありましたが、READMEに書いてあることがあまり信頼できないわ複数のブラウザを起動するテストが進まないバグがあって1つづつ起動する必要があるわと、ほんとにこれメンテされてるのかってレベルで荒れてました。最終的には動きましたが、バッジを表示させるのでなければターゲットはIE11だけでいいかもしれません。

さらに、TypeScriptのためには karma-typescriptkarma-webpack (+ts-loader) を使う必要があります。前者は結局モジュールのバンドルを自前でやっているようで、それなら一般的に使われているであろうwebpackを利用する karma-webpack にしました。ただ karma-webpack もイマイチ安定していなくて、現行の karma-webpack 3.x + ts-loader だとなぜか node_modules/ 以下のdtsを読んでくれません。やむを得ず transpileOnly: true で型チェックはしないことに。とはいえ、いずれにせよ他のフェーズで型チェックはするのでこれによってテスト結果が信頼できなくなるということはないのでいいでしょう。

さらに、 msgpack-javascriptmocha + NodeJS assert module でテストを書いています。ブラウザで動かすにはこのassert moduleのpolyfillを行なわなければならず、webpackはデフォルトでこのpolyfill差し込みを行います。それを管理しているのがこのモジュール:

github.com

これによれば assert module のpolyfillは browserify/commonjs-assert なんですが、NodeJS用のテストを実際にブラウザで実行しても動きません。どうも commonjs-assert 1.x はベースにしているNodeJS assertが古かったようです。ちょうど最近 commonjs-assert が v2.0.0 になって最新のNodeJSに追従したんですが、 node-libs-browser のほうがまだこのメジャーバージョンアップに対応されていないので webpack 組み込みのpolyfillを無効化して事なきを得ました。というか、webpackがnodejs modulesのpolyfillを自動で差し込むのはいろいろ罠が多いのでデフォルト無効化してほしいくらいです。

最終的には karma.conf.ts はこうなりました。

https://github.com/msgpack/msgpack-javascript/blob/master/karma.conf.ts

ローカルのNodeJSテストが5秒くらいで終わるのに対して、Karma+ChromeHeadlessテストが8秒くらい、Karma+FirefoxHeadlessでのテストが15秒くらいです。これくらい高速に実行できるとブラウザでユニットテストを走らせるのも苦ではないですね。

まあしかし、設定は苦労しましたが、総じて見るとKarmaはよく出来てるなあと思います。Headless ChromeやHeadless Firefoxの安定版が普通に使えるようになったこともあり、ユニットテストをブラウザで実行するのはわりと簡単にできるようになりましたね。

*1:その後 Open Sauce 申請が通ったので時間制限なしで使えるようになりました