Cypressを使った安定した製品のデリバリー
Fei Han
February 7, 2021
Apache APISIX Dashboardは、ユーザーがフロントエンドインターフェースを通じてApache APISIXを操作することを可能な限り簡単にするために設計されています。プロジェクトの開始以来、552のコミットと10のリリースがありました。このような急速な製品のイテレーションにおいて、オープンソース製品の品質を確保することが重要です。そのため、安定した製品の提供を確保するためにE2Eテストモジュールを導入しました。
フロントエンドE2Eとは何か?
E2Eは「End to End」の略で、「エンドツーエンド」テストと訳されます。これはユーザーの行動を模倣し、エントリーポイントから始めて、ステップバイステップでアクションを実行し、ジョブが完了するまで進めます。適切なテストは、コードの変更が元のロジックを壊さないようにします。
なぜCypressを選んだのか
選択研究期間中に、Taiko、Puppeteer、TestCafe、およびCypressを使用してルート作成のテストケースを書き、それぞれのテストフレームワークの特徴を体験しました。
Taikoはスマートセレクターを特徴としており、テキスト内容と位置関係に基づいて操作したい要素をインテリジェントに特定し、起動コストが低いため、テストケースを迅速に完了できます。しかし、テストケースを書く際にはユーザーフレンドリーではありません。ユーザーが誤ってターミナルを終了すると、書かれたすべてのテストケースが失われ、完全なテストケースを実行するには他のテストランナーと一緒に使用する必要があり、ユーザーの学習コストを増加させます。
Puppeteerは最高のパフォーマンスを持っています。しかし、テストはPuppeteerの焦点ではありません。ウェブクローラーとして広く使用されています。私たちのプロジェクトはANTDが公式に推奨するE2EテストフレームワークであるPuppeteerから始めましたが、しばらく使用した後、Puppeteerは非フロントエンド開発者にとってあまりフレンドリーではなく、他のユーザーを巻き込むのが難しいことがわかりました。ユーザーがテストケースを書く際、インテリジェントな要素の位置特定がないため、学習曲線が非常に高くなります。
TestCafeは驚くほど簡単にインストールでき、組み込みの待機メカニズムがあり、ユーザーがページの相互作用を待つために積極的にスリープする必要がなく、複数のブラウザでの同時テストをサポートしており、複数のブラウザの互換性テストに役立ちます。欠点は、そのデバッグプロセスがあまりユーザーフレンドリーではなく、各テストケースの変更後に新しいユースケースを実行する必要があることです。開発者にとっては、基本的なJavascript構文が必要です。次に、その実行速度は他のフレームワークに比べて比較的遅く、特にwithText()を実行して要素を見つける際に顕著です。
総合的な比較の後、最終的にCypressをフロントエンドE2Eフレームワークとして選択しました。主な理由は以下の4つです:
- シンプルな構文
Cypressテストで使用される構文は非常にシンプルで、読み書きが容易です。少し練習すれば、テストケースを作成することをマスターできます。これはオープンソースプロジェクトにとって重要です。なぜなら、E2Eテストケースに興味を持つコミュニティが最小限の学習コストでテストケースの作成に参加できるからです。
- 簡単なデバッグ
テストケースをデバッグする際、CypressのTest Runnerを使用できます。これは多次元のデータを表示し、問題を迅速に特定することを可能にします。
- テストケースの実行状況を表示し、成功、失敗、実行中の数を示します。
- テストセット全体の実行に費やされた総時間を表示します。
- 要素を特定するための組み込みのSelector Playgroundがあります。
- 各ユースケースの実行ステップを表示し、完了後に各実行ステップの情報を表示するスナップショットを形成します。
- 活発なコミュニティ
Cypressには大規模なユーザーコミュニティがあり、コミュニティ内で多くの人々が自分の経験やアイデアを共有しています。
これは問題に遭遇した際に役立ち、他の人が以前に遭遇した問題に遭遇する可能性が高いです。また、新しい機能が要求された場合、コミュニティに参加してCypressに追加したい機能を議論し、追加することができます。APISIXコミュニティで行っているように、コミュニティに耳を傾け、フィードバックを返します。
- 明確なドキュメント
Cypressのドキュメント構造はより明確で包括的です。使用の初期段階で、公式ドキュメントのガイドラインに基づいてCypressをプロジェクトに迅速に導入し、最初のケースを書くことができました。また、ドキュメントサイトには、ユーザーにベストプラクティスについて良いガイダンスを提供する大量のドキュメントがあります。
CypressとAPISIX Dashboard
現在、APISIX Dashboardには49のテストケースが書かれています。GitHub ActionにCIを設定し、各マージ前にコードが合格することを確認してコード品質を確保しています。Cypressのベストプラクティスを参照し、プロジェクトと組み合わせてAPISIX DashboardでのCypressの使用を共有します。
- よく使われる機能をコマンドとしてカプセル化します。
ログインを例にとると、ログインはシステムに入るための必須部分であるため、コマンドとしてカプセル化し、各ケースの実行前にログインコマンドを呼び出すことができます。
Cypress.Commands.add("login", () => {
cy.request(
"POST",
'http://127.0.0.1/apisix/admin/user/login',
{
username: "user",
password: "user",
}
).then((res) => {
expect(res.body.code).to.equal(0);
localStorage.setItem("token", res.body.data.token);
});
});
beforeEach(() => {
// init login
cy.login();
})
- セレクターとデータをパブリック変数として抽出します。
ユーザーがテストコードの意味をより直感的に理解できるように、セレクターとデータをパブリック変数として抽出します。
const data = {
name: 'hmac-auth',
deleteSuccess: 'Delete Plugin Successfully',
};
const domSelector = {
tableCell: '.ant-table-cell',
empty: '.ant-empty-normal',
refresh: '.anticon-reload',
codemirror: '.CodeMirror',
switch: '#disable',
deleteBtn: '.ant-btn-dangerous',
};
- cy.wait(someTime)を削除します
Cypressの初期にはcy.wait(someTime)を使用していましたが、cy.wait(someTime)はネットワーク環境とテストマシンの性能に依存しすぎており、ネットワーク環境やマシンの性能が悪い場合にテストケースがエラーを報告する可能性があることがわかりました。推奨されるプラクティスは、cy.intercept()と組み合わせて使用し、待機するネットワークリソースを明示的に指定することです。
cy.intercept("https://apisix.apache.org/").as("fetchURL");
cy.wait("@fetchURL");
まとめ
現在、APISIX Dashboardには49のテストケースが書かれています。今後、フロントエンドE2Eのカバレッジをさらに強化し、新しい機能やバグ修正の提出ごとにコミュニティがテストケースを書くことに同意することを要求し、製品の安定性を確保します。
世界クラスのゲートウェイ製品を磨くために、ぜひ参加してください。
プロジェクトアドレス: https://github.com/apache/apisix-dashboard