Help us understand the problem. What is going on with this article?

AVAをブラウザ上で実行するAvaronを作った

More than 1 year has passed since last update.

この記事は「WACUL Advent Calendar 2017」の20日目です。
WACULでフロントエンドエンジニアをしている@bokuwebと申します。

はじめに

みなさんはお気に入りのテスト構成はあるでしょうか。よく耳にするのはjestAVAkarmaを用いた構成でしょうか。個人的には最近はAVAを使用することが多いのですが、その際の不満を解消するためにモジュールを作った話しを書きたいと思います。

つくったもの

https://github.com/bokuweb/avaron

AVAとは

avajs/ava: Futuristic JavaScript test runner

紹介記事は他にも色々ありますので多くは書きませんが、sindresorhus氏作の、曰く未来型のテストランナーです。若干古いですが以下に日本語での記述もあり、なぜAVAなのか?に特徴が記載してあります。

https://github.com/avajs/ava-docs/tree/master/ja_JP

例えばPromiseを使用したテストは以下のように記述できます。同様にObservableもサポートしています。

samples.spec.js
import test from 'ava';

test('Promise test', async t => {
    const result = await somePromise();
    t.is(result, 'Hogeeeeee');
});

以前は自分Karme + mocha + power-assertのような構成が多かったんですが、設定が非常に大変だったんですが、AVAの場合は設定がシンプルにできるのも良い点です。

また、AVAが使用しているmagic assert(これが正式な呼称かは知らないが、PRにはそう書いてあった)は以下のようにテスト失敗時の差分が見やすい点もお気にいりです。

image.png

他にもJestと同様のスナップショットテストを行えるなどの利点もあります。

解決したかった点

上記では良い点を書きましたが、当然不満な点もあります。webpackでローダーを駆使したプロジェクトとの相性が悪かったり、Typescript使用の場合一手間必要だったり細かい点はいくつかあるのですが、自分が解決したかったのは以下の2点です。

  • 1 本物のブラウザで実行したい
  • 2 スクリーンショットを取りたい

上記は独立しておらず、2を解決するには1を解決する必要があるんですが。。。

1 本物のブラウザで実行したい

AVANodeJSのプロセス上で動作する前提で設計されているのでブラウザ上で実行することができません。現状はbrowser-envを使用することでのテストを推奨しています。

https://github.com/avajs/ava/blob/master/docs/recipes/browser-testing.md

メンバーも本物のブラウザで動作させることはlow priorityだと言っておりそこまで関心は高くないようです。(長い間開いてたissueもいつの間にか閉じられてた・・・)

https://github.com/avajs/ava/issues/24#issuecomment-339391199

正直、ドラッグやファイルアップロードなどbrowser-envではまかなえないケースはレアですし、SPAなどのテストではここまで必要となるケースは少ないかもしれません。(こいったコンポーネントは切り出してPuppeteerなどでテストすることもできますし。)

自分の場合は前述したように、2の解決に1が必要であったのと、たまたまそのようなテストを行いたいコンポーネントがあったため、モチベーションのひとつとして記載しています。

2 スクリーンショットを取りたい

どちらかと言えば、こちらがメインのモチベーションです。弊社としても個人的にもVisual Testingを使用することが多いのでこちらは是非とも解決したい点でした。

Visual Testingについては@Quramyの以下の記事が詳しいです。Avaronも紹介してもらってます。

1日10万枚の画像を検証するためにやったこと - Qiita

Visual Testingというと思い浮かべるスコープは人やチームによってまちまちかと思います。E2Eレベルでのページ単位のスクリーンショットを思い浮かべる方も多いと思いますが、個人的にはコンポーネント単位で小さな単位でのスクリーンショット、すなわちjestsnapshot testの画像版のような使用方法がお気に入りです。そのへんの考え方は以下の資料にも記載しています。

煩悩レスなコンポーネントテストを目指して // Speaker Deck

Avaronについて

解決方法

資料にも少し記載はありますが、AVAforkするprocessをElectronに無理やり差し替えています。(現状かなり力技でイケてないんですが、中の人曰くこの辺りを抽象化してprocessを差し替えられるようにするアイディア自体はあるようですが、low priorityとなっており、実現は遠そうです。)

https://github.com/bokuweb/avaron/blob/master/lib/fork.js#L60

Electronさえ立ち上がれば後はrenderer processで実行させてやればChromium1
上でのテストが可能なりますし、Electronwin.capturePageを使用すればスクリーンショットも取れるので解決したかった点は両方解決されます。

使用方法

以下のように設定することでrendererでのテストが可能です。また、もともとAVAを使用していた方は"test": "ava"となっていた箇所を"test": "avaron"とすればそのまま使用可能ですし、AvaronAVA本体へ干渉することはないので、併用も可能(なはず)です。

windowOptionsElectronBrowserWindowへ渡すパラメータです。Windowのサイズなどその他いろいろここから設定可能です。また、fixtureはテストを実行するhtmlを指定することができます。(karmaで言うところのcustomContextFileです)

package.json
{
  "scripts": {
    "test": "avaron"
  },
  "devDependencies": {
    "avaron": "*"
  },
  "avaron": {
    "renderer": true,
    "fixture": "./fixture.html",
    "windowOptions": {
      "title": "avaron"
    }    
  }
}

例えば以下のようなテストでキャプチャが取得できます。

抜粋
import test from 'ava';
import React from 'react';
import { render } from 'react-dom';
import { screenshot } from 'avaron';

test('should capture react component screenshot', async t => {
    render(<Example />, document.querySelector('.main'));
    datePicker.show();
    const path = 'screenshots/date-picker-dialog.png';
    await screenshot(path);
});

上記は抜粋ですので、全体は以下を参照ください。

https://github.com/bokuweb/react-avaron-sample/blob/master/test/index.test.js

image.png

注意点

注意点としてはCIなどで動作させる場合、仮想ディスプレイが必要になるので注意してください。具体的にはXvfbなどを設定する必要があります。以下にサンプルを記載します。

使用例

Avaron自身の紹介からは少しはずれますが、@Quramy作のreg-suitを使用した例を紹介してみたいと思います。

https://github.com/reg-viz/reg-suit

リポジトリは以下で上記のカレンダーの日付を変更した際の例になっています。

https://github.com/bokuweb/react-avaron-reg-sample

この例ではmaterial-uiのコンポーネントを使用しているのですが、コンポーネントの見た目の変更を検出できています。

スクリーンショット 2017-12-20 8.09.20.png

また、先日ファミコンエミュレータの創り方 - Hello, World!編 -という記事を書いたんですが、このエミュレータ開発にもAvaronreg-suitを使用しています。テスト対象の解像度が低いので見にくいですが、エミュレータ用のテストROMを実行した際に差分がでた場合の例になります。(エミュレータのテストROMはエミュレータ上で実行されるためテストに落ちた場合の検出が困難で、見た目も含めて差分を検出できるこの仕組は有用でした。)

https://github.com/bokuweb/flownes

スクリーンショット 2017-12-20 8.14.53.png

さいごに

AVAをブラウザ上で実行する試みについて紹介しましたが、如何でしたでしょうか。
まだまだ不安定なところはあると思いますが、もし興味がありましたら、フィードバックやPRをいただけると幸いです。


  1. versionはElectronで使用しているものに縛られてしまうという欠点もありますが 

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away