Playwrightでラクして行うブラウザ動作確認 第1回 ゆるE2Eのススメ

フロントエンドの現場では、テストの必要性を感じつつも、実装コストや優先度の問題から後回しにされがちです。本シリーズでは、Playwrightを使って最低限のE2Eテストを試します。テストを書く意味と効果を実感してみましょう。

発行

  • 高津戸 壮
  • 德田 和規
Playwrightでラクして行うブラウザ動作確認 シリーズの記事一覧

はじめに

このシリーズは、「E2Eテストって何?」「そもそもテストを書くってどういうこと?」「何がうれしいの?」といったレベルの理解からスタートします。包括的なテストフレームワークに触れたことのない読者に向けて、実際にPlaywrightというテストフレームワークを動かしながら、「こういったテストにはどんな利点があるのか」を実感してもらうことを目指すものです。

筆者とテスト

このCodeGridをお読みになってくださっている方は、Web制作やWeb開発に関わっている方が多くを占めるかと想像されます。そして、Web制作畑の方、そしてそこから開発に関わるようになった方もいらっしゃると思いますが、その中には、テストについてそこまで実践的に導入していないという方も多いのではないかと、筆者高津戸は想像しているのですがいかがでしょうか。

筆者もそのような人間の一人です。テストは書いたことがあったし、仕組みも理解しているけれど、実際のプロジェクトに導入してきたかというと、そういうわけでもありませんでした。

ですが、最近は必要性を感じて、そういったテストを入れるようにしています。度合いは開発の進み具合と相談ですが、もはや当然のようにそうしたほうが良いと考えるようになったのです。このシリーズでは、そういう話をしていこうと思っています。

テストが後まわしにされる理由

さて、まずは「ちゃんとテストしたほうが良いと決まっているであろうが、なぜ書かないのか?」ということを考えてみました。なぜなら、「テストが重要」みたいな話なんて、インターネットを眺めていればよく見かける話ではないかと思うからです。

私が考えるに、これはおそらく、我々フロントエンド周りの実装を担う開発者が作るものというのは、最終的にWebページであることが多いというのが原因として大きいかと考えています。

たとえばお問い合わせフォームのようなUIを実装することを考えてみます。メールアドレスは正しくバリデーションされるか、郵便番号から住所はちゃんと補完されるか、送信ボタンを押したらちゃんとメールが飛ぶかなど。

このようなWebページの機能を作るとき、これに対するテストの必要性をそこまで強く感じられないということは多いのではないでしょうか。それはなぜでしょう。

ここでは以下2つを理由として挙げ、これについて説明します。

  1. テストを書くのがある程度難しいし手間
  2. コスト的に許容されない

1. テストを書くのがある程度難しいし手間

まず理由の一つは、このようなUIに関わるテストを書くのは、そこそこ難易度が高いし、わりと手間がかかるという点が挙げられるかと思われます。

手間のかからない、書きやすいテストというのはあります。たとえば、1000というような数値が渡されたら、"1,000"と、3桁ごとにカンマを打った文字列として返すという関数があることを想像してみて下さい。

3桁ごとにカンマを入れる関数

function addCommas(num) {
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

// 使用例
console.log(addCommas(1000));     // "1,000"
console.log(addCommas(1000000));  // "1,000,000"
console.log(addCommas(123));      // "123"

このような関数に対するテストは、以下のように書けます:

テストコードの例(Jestなどのテストフレームワークを使用)

describe('addCommas関数のテスト', () => {
  test('1000は"1,000"になる', () => {
    expect(addCommas(1000)).toBe('1,000');
  });

  test('1000000は"1,000,000"になる', () => {
    expect(addCommas(1000000)).toBe('1,000,000');
  });

  test('123は"123"のまま', () => {
    expect(addCommas(123)).toBe('123');
  });
});

1000を渡したら"1,000"が、1000000を渡したら"1,000,000"が返される。こういったのを実際に動作させて確認する──というのがいわゆるユニットテストというものです。この例の場合はシンプルそうであることは、テストを書いたことがない方であっても、おわかりになるかと思います。

ですが、お問い合わせフォームの場合はどうか? と考えると、ブラウザ上であれこれ入力欄にフォーカスし、内容を入力したりなどしないと本当に動作しているのかを確認できません。だったらどうすれば良いのでしょうか? そもそも最終的にフォームを送信した後のことはどう考えますか? 実際にメールが飛ぶのを確認しますか?

なんだかそんなことを調べている間に、もう2つか3つぐらい、別の仕事ができそうな気もしてきます。結果、ブラウザで開いて動かしてみて動作OK。テストはよくわからないし、そこまで複雑でもないからこれでいいでしょと。そのようにしてテストを書くことの優先度が下がってしまうというようなケースがあるのではないでしょうか。

2. コスト的に許容されない

理由2つ目、テストを書くことに対するコストについて、クライアントに対する説明が困難という点があるように感じます。これはテスト自体にとって本質的ではありませんが、前述したようなテストを書く場合、それは当然、ただフォームを実装する以上の時間がかかる、つまりはその開発者の労働力としてのコストがかかります。

想像してみてください。「テストを書くと10万お見積もりが増えます」と、クライアントへ言っている姿を。「テスト? なんですかそれは? 10万払いたくないのでいらないです」という返事が返ってくると思いませんか? これはおそらく、開発を実際にしているクライアントとそうでない場合とで話の流れが異なるかと思われますが、私の経験からすると、開発をしていないクライアントにこのような聞き方をしたら100%拒否されます。「なるほど、時間ができたらやっていきたいですね……」というような反応です。

テストは、はっきり言えばなくても動くし、後まわしにされる理由はいくらでもあるということです。

受託案件の場合の、テストを書くコスト

テストを書くコストをどのように考えたら良いのかという問題は、特に受託の場合難しいケースが多いと思うのですが、個人的な結論としては、何かそれについて事前に確認を求めたりするのではなく、当然のように存在する開発の流れの一部として実装してしまうというのがオススメです。ただこのあたりの話は本トピックとは微妙にずれてくるので、ここでは深く触れません。

オススメしたいテスト

そんなテストですが、テストと一口に言っても、いろいろな方法があります。フロントエンドの文脈でテストというと、大きく分けると以下の2つになるかと思われます。

  • ユニットテスト
  • E2Eテスト

ユニットテストとE2Eテスト

ユニットテストは、前述したような小規模な単位のテストです。「3桁ごとにカンマが入れられているか?」というようなものをたくさん書いて、部分部分での動作が保証できているかをチェックするために導入します。モジュール単位とかコンポーネント単位とか、そこで完結するタイプのテストです。

E2Eテストのほうは全体を包括したテストです。このE2Eテストの意味する内容は広いですが、たとえばブログシステムの開発を想定するとしたら、以下のようなことがE2Eテストに相当します。

  1. 管理画面でログイン
  2. 記事一覧ページが表示される
  3. 記事投稿画面で記事投稿
  4. 投稿した記事が公開されている

このような、一連の作り上げた仕組みを、通しでチェックするのがE2Eテストであると言えます。

E2Eテストは難しい

E2Eテストがややこしくなる理由の一つに、テストの中でフロントエンドとバックエンドの両方が関わる点があります。

たとえば先ほど挙げたブログ記事の投稿処理では、画面操作に加えてAPIへのリクエストが発生し、それに対するレスポンスを正しく扱う必要があります。このような複数のシステムが連携する動作確認が必要になる点が、E2Eテストの難しさでもあります。

特に複雑なWebアプリケーションとなれば、必然的にAPIとの通信がUI操作の中に含まれてくるので、あれやこれやと準備をしないと、そもそもこのようなテストを実装することができません。

もしくは、API部分は切り離して考え、フロントで作ったものを一通りビルドした状態のテストをする、E2Eライクなテストをするというのも方法の一つ。その場合はAPIのリクエストはモックアップを使用するという方法が考えられます。ただ、そのようにするにしても、それをどのようにやるかという設計が必要になってくることは想像に難くありません。

そんなこんなで、いろいろと「テスト設計」のようなことをしないとならず、結果、「うーん、テストって難しいね」となってしまうわけです。

ライトなE2E的テスト

とはいえ、それは込み入ったケースになった場合に考えてほしい話です。今回の連載で目指すのはこれです。

  • ページをただ開き、JavaScriptエラーが出ていないことのテスト

これであればどうでしょう? 先ほど例のブログシステムのUIの操作だったり、APIのリクエストという点は気にする必要がなさそうです。ですが、少なくともこのようにエラーが発生していないことを、すべてのページについて確認するだけで、変更した内容により問題が起こっていないことを確認できると感じられないでしょうか。

ひとまず、この連載自体は、このテスト実現をゴールとして設定し、そこからテストについて理解を深めて行くきっかけになればというものです。

なお、このただ開くだけエラーチェックテストは、E2Eテストのほうに分類されるかとは思いますが、E2Eテストというほどに大それたものではないとは言えるでしょう(一般的には前述したような包括的なテストがE2Eテストなので)。

コラム: スモークテスト

このような、ごくごくライトなタイプの、エラーがないか程度の確認のためのテストは、スモークテストと呼ばれることがあります。スモークテストの語源は電子回路で、電源を入れてとりあえず煙が出ない(=どこかでショートしたりおかしい回路の接続がない)ことを確認するところから来ているようです。

スモークテストについては以下記事でも触れているので、参考にしていただければと。

Webアプリの運用と品質保証

前項で書いた、「ただエラーがないことを保証するテスト」をとりあえずオススメしたいのは、私の経験から来るものです。

ずっと前から運用をお手伝いしているWebアプリにて、このようなテストが入っていました。それを実装した人はそこまで意識して入れたわけではなく、ただ初期実装時に入れたままになっていたぐらいのものでした。しかし、実際に長期間開発を続けていると、このテストがそういえば結構役に立っていたことに最近気付きました。

機能やページが増えてくると、一箇所の変更ですべての画面の動作に影響がないかをチェックするのは困難です。これをごく単純にやるとすると、全画面、たとえば30ページとか50ページとかをブラウザで開き、問題がないことをチェックする必要があります。

これが初めのうちならまだ良いです。10ページ程度のアプリで、全部開いてちょっとUIを触ってヨシ、問題なし! と確認するようなことはあると思います。

ですが、当然のごとく、それは日々更新されていくWebサービスでは現実的ではありません。それに、そのように手動でチェックするというフローでは、どうしても主観性が入ってきてしまいます。「よし、この変更ならこの画面にしか影響がないはず。他の画面は見なくても平気でしょう」と思ってしまい、結果、一部しか見ずということになるわけです。

筆者が実際にやってしまったのがズバリこれです。「変更したのはこの画面の機能。だったらそこだけ見ればOK」と思っていましたが、関係ない箇所でエラーが発生し、ページが真っ白な状態になってしまっていたのです。そのエラー状態は2日間続いており、これはもう謝るほかありません。夜に慌てて直しました。

その事件があってから、ちゃんとリリース前に全画面をチェックするように、確認すべき画面をまとめるなどしました。ですが、そうやって画面を逐一開いてチェックするというのを繰り返しているうちに、そういえば別のプロジェクトでやっていたあのエラーなしチェックは大いに意味があったな……と気付かされた感じでした。

ただ、しっかりテストを書くには時間が必要です。それは前述したような、お問い合わせフォームをあれこれ操作するというところまでシミュレートしてテストするのか? というところです。テストを書くこと自体に時間はかかるわけでして、そのテストはUIや機能の変更に合わせて書き直したり削ったりする必要があります。これは、そもそもそのテストを書くかどうかという点から判断しなければならない、開発上の課題です。

ですので、今回はまずは第一歩として「画面を開いたときにエラーが出ていないことのテスト」というライトなテストをオススメしたいのです。

PlaywrightをライトなE2Eテストに使う

そんなわけでその「エラーなしテスト」をこの連載では紹介しますが、このテストを書くのに、Playwrightを使用します。

Playwrightは、Webサイトに、

Playwright enables reliable end-to-end testing for modern web apps.

と説明があるように、E2Eテストを実現するためのテストフレームワークです。

このPlaywrightを使うと、Node.jsで仮想的に(もしくは実際に開かせることも可)Chromium、WebKit、Firefoxなどのブラウザを立ち上げ、書いたテストを実行させ、問題が起こらないかをチェックさせることができます。

筆者は、最近技術系のオンラインイベントを拝聴する機会が多いのですが、そういったイベントで、E2EテストのためにPlaywrightを使っているという発表を何回か見かけました。この連載ではごく単純なテストを扱いますが、実際に大規模なWebサービスを運用している企業にとっては、システムのダウンが重大な損害につながることもあります。そうした問題を未然に防ぐために、Playwrightを活用しているという事例が紹介されていました。実際にこのようなテスト、そしてPlaywrightはそういった現場では当たり前のように取り入れられているということです。

大きな規模のWebサービスでのテストの重要性は察してあまりあるべしです。しかし、たとえば数十ページのWebサイトであったとしても、何か一つ更新する度に全画面でエラーをチェック……これを100回繰り返すという作業を考えたら、ちょっとがんばってテストを入れる労力を考えても十分すぎるほどにおつりが来るとは思わないでしょうか。

そんなわけで、この連載ではこのPlaywrightを使い、画面を開いてエラーがないことを確認するテストを紹介していきます。

詳しい説明は次回以降になりますので、今回はどんなデモアプリケーションを使うのかと、Playwrightでテストを実行するとどんな結果が得られるのかを見てみましょう。

デモアプリケーションは静的な3ページのアプリケーションで、それぞれのページにはタブUIが配置されています。

Playwrightを使い、以下の2点を「Chromium」「Firefox」「WebKit」ブラウザで確認するテストを実行できるようにします。

  • ページ読み込み時のエラーチェック
  • タブクリック時のエラーチェック

Playwrightでテストを実行すると、結果がレポートとして出力されます。レポートでは項目別にテストにパスしたかどうかが一覧でわかるようになっています。

次回より、Playwrightの使い方を詳しく見ていきましょう。