この記事はテックタッチアドベントカレンダー 8 日目の記事です。
フロントエンドエンジニアの taka です。Amazon Black Friday でフットウォーマーを買ったのですが、冷え性の自分には最高でした。冷え性の方には是非使ってみてもらいたいです。
今回は、モダンなツールである Playwright と Puppeteer、Cypress を実際に触ってみたので、そこから得られた知見を紹介したいと思います。
要件の整理
テックタッチはブラウザ拡張であるため、一般的な Web アプリケーションとは少し要件が異なってきます。以下に、一般的な要件とテックタッチ特有の要件を書き出しました。
一般的な要件
- なるべく速く動作してほしい
- なるべく実装コストを抑えたい
- 特定のケースやエラー時にスクショや動画を取りたい
- API をモックして Pull Request 毎にテストしたい
- バックエンド起因でテストが失敗するのを回避するため
テックタッチ特有の要件
- ブラウザ拡張のテストをしたい
- タブ / ウィンドウを跨ぐようなテストをしたい
- ShadowDOM を含む環境で動かしたい
機能ごとの比較
いくつか項目を絞って、機能ごとに比較してみました。
Playwright | Puppeteer | Cypress | |
---|---|---|---|
サポートブラウザ | Chromium, Chrome, Edge, Firefox, Webkit (Safari) | Chrome, Firefox | Chrome, Edge, Firefox, Electron |
テストツールの有無 | ✅ | 🟡 (Jest を使えば可能) | ✅ |
複数タブ / ウィンドウ | ✅ | ✅ | 🛑 |
Shadow DOM | ✅ | 🟡 (aria または pierce セレクタを使えば可能) | ✅ |
ブラウザ拡張 | ✅ | ✅ | 🟡 |
要素の特定 | 🟡 | ✅ | 🟡 |
要素の自動待機 | ✅ | 🟡 | ✅ |
スクリーンショット | ✅ | ✅ | ✅ |
動画 | ✅ | 🛑 | ✅ |
実行速度 | ✅ | ✅ | ✅ |
テストツールの有無
Cypress と Playwright はテストツールと謳っていることもあり、独自のテスト機能を有していますが、Puppeteer はシンプルに Chrome を操作するための Node ライブラリと謳っていることもあり、Puppeteer 単体ではテストすることができません。Puppeteer でテストするには、Jest 等のテストフレームワークを併用する必要があります。
複数タブ / ウィンドウ
Playwright と Puppeteer は「ブラウザの外から操作する」ため、基本的にブラウザの機能を全て利用することができます。これに対し、Cypress は「ブラウザの中の iframe にテスト対象のページを描画し、それに対して操作する」ため、複数のタブ / ウィンドウを扱うことができません。 テックタッチはタブ / ウィンドウを跨いで動作するため、このようなユースケースをカバーするためには Playwright か Puppeteer を選択せざるを得ませんでした。
ShadowDOM
Playwright では、デフォルトで Shadow DOM を貫通して要素を特定できます。
Puppeteer では、公式には記載されていませんが、セレクタに pierce
または aria
を使うことで Shadow DOM を貫通して要素を特定できます。
Cypress では、 includeShadowDom
というオプションを利用すれば良いそうです。グローバルなオプションに設定することもできるようで、そうすると毎回オプションを指定しなくても良くなりそうです。
ブラウザ拡張
ブラウザ拡張は全てのツールで利用可能ですが、 Cypress は Puppeteer と Playwright とは違って、 iframe 内にページをロードします。そのため、ブラウザ拡張がページの状態を監視したり content script を埋め込むようなことをしているのであれば、 Cypress 用に特別な対応をしないといけません。 テックタッチのブラウザ拡張の content script は、 iframe 内では実行されないようにしているため、動かすためにはプロダクトそのものに手を加える必要がありました。
要素の特定
Cypress のセレクタは jQuery
と同等です。
Playwright のセレクタは独特で、 await page.click('text=Log in');
のように記述します。 Text や CSS, XPath など、多種多様なものが用意されています。React selectors というのがあるのは驚きました。試してはいませんが、React のコンポーネント名でも選択できるようです。ただ、ベストプラクティスは「 Text と CSS を使って text content や input placeholder など、めったに変わることがない user-facing attributes を使いましょう」とあるので、この2つさえ使えれば良いと思います。
Puppeteer のセレクタは querySelector
とほぼ同等ですが、 ARIA selectors が利用できます。これにより、より特定性の高いクエリを書くことができます。例えば、 <button>Submit</button>
のような要素は aria/Submit[role="button"]
で特定することができます。Playwright では、 button 要素は role attribute を持っていないので、 button >> Submit
のように書かざるを得ず、要素が button
タグではなく div
タグで role
attribute が設定されているような場合には div[role="button"] >> Submit
のように指定する必要があります。
スクリーンショット
全てのツールで利用することができますが、「テストが失敗した時にスクリーンショットを取りたい」という場合に、Puppeteer だと実現が難しいようでした。そこはテストツールと謳っている Playwright と Cypress に分がありそうです。
動画
Playwright と Cypress には録画機能はありますが、Puppeteer にはありません。 動画を撮りたい場合は、以下の記事のように自前で ffmpeg 等をセットアップする必要がありそうです。
puppeteer を使った E2E テストでも動画を撮ってみる - Tech Inside Drecom
実行速度
実行速度は実際に比較していませんが、こちらのサイトによると
Puppeteer ≒ Playwright > Cypress
のようでした。 ただ、実際に Playwright と Puppeteer + Jest (Puppeteer Testing Library) を比べてみたところ、明らかに Playwright の方が速く感じられました。 これはおそらく、Puppeteer Testing Library の selector は要素の表示検知をポーリングして行なっているのに対し、 Playwright はイベント・ドリブンなアーキテクチャであり、独自で Auto-waiting という機能を提供しているため、その差が出ていたのかもしれません。
まとめ
今回は Playwright と Puppeteer、Cypress の機能比較を行いました。 結果として、テックタッチのブラウザ拡張をテストするのであれば、 Playwright が良さそうであることがわかりました。
Playwright は「Puppeteer よりもサポートしているブラウザが多い」ぐらいの認識しかありませんでしたが、実際に細かく検証していくとかなり高機能であることがわかりました。 Playwright は元 Puppeteer の開発チームが開発しているだけあって、完全に上位互換のように感じられました。 しかし、Puppeteer にも Aria selectors が導入されるなど、まだ進化は止まっていないため、今後どういった方向に進化していくかが非常に楽しみです。