JestとPuppeteer:Web UIテストの自動化

この記事はイタリアのプログラマーValentino Gagliardiによって書かれました。 彼は、Puppeteerのリリース後すぐに、このライブラリとJestを使用してWebインターフェイスのテストを自動化することに興味を持つようになったと言います。 その後、彼は実験を始めました。







ここでは、Webフォームをテストする例によって、PuppeteerとJestで作業する基本について説明します。 また、ユーザーインターフェースを使用して、または使用せずにChromiumを使用する機能、およびWebページのテストと作業環境の整理のさまざまな側面に関するいくつかの有用なことについても説明します。 Valentinoは、Puppeteerは比較的新しいツールであり、APIは変更される可能性が高いものの、Web開発者の武器庫で正当な位置を占める可能性があると考えています。



問題のテストのいくつかの機能について



最近、インターフェイステストを書いたのと同時に Kent S. Doddsがdata-*



属性を使用してテストの安定性を改善するという記事に出会いました。 これは、一言で言えば、ほとんどすべてのHTML要素に設定できるカスタム属性です。 JavaScriptプログラムとのデータ交換を整理するときに特に役立ちます。



ケントの資料は非常に時間通りに来ました。それは、次の構造を使用したためです。



 await page.waitForSelector("#contact-form"); await page.click("#name"); await page.type("#name", user.name);
      
      





ここでは、主にサーバープログラミングを扱っていることに注意してください。 そして、私はまだテストでのdata-*



の使用をキャンペーンしていませんが、それにもかかわらず、これは素晴らしいアプローチであることを認めなければなりません。 これは特に大規模なアプリケーションで役立ちますが、ここでは、単純な例では、要素にアクセスする古典的な方法を使用します。



フィードバックフォームのテスト



したがって、私たちの目標は、私が取り組んでいるこのページのフィードバックフォームをテストすることです。 フォームは次のとおりです。









次の要素が含まれます。





テスト中、フォームの状態を確認する必要があります。つまり、サイト訪問者がフォームを使用して会社にリクエストを送信できることを確認する必要があります。



プロジェクトのセットアップ



始めるために、テストの自動化に使用するツールを詳しく見てみましょう。









Jestは、Facebookが開発したテストフレームワークです。 Jestは、自動テスト用のプラットフォームと、ステートメントを作成できるベースライブラリ(Expect)を提供します。



PuppeteerはNode.jsのライブラリで、ユーザーインターフェイスなしでChromiumブラウザを制御できます。 このツールは非常に新しいため、試してみて、特定のプロジェクトで必要かどうか、必要に応じて既存のエコシステムに統合する方法について考えてみましょう。



Fakerは、ランダムデータを生成できるNode.jsのライブラリです。 それらの中には、名前、電話番号、住所があります。 ちなみに、これはPHPのFakerのようなものです。



実験するプロジェクトが既にある場合は、次のコマンドで必要なライブラリをインストールできます。



 npm i jest puppeteer faker --save-dev
      
      





Puppeteerのインストールには時間がかかります。これは、とりわけ、ライブラリのインストール中にChromiumブラウザーもインストールされるためです。



Chromiumは、Google Chromeの基盤であるオープンソースのウェブブラウザです。 ChromiumとChromeの機能はほぼ同じですが、主な違いはライセンス機能にあります。



必要なものがすべてインストールされたら、 package.json



Jestを構成します。 test



コマンドは、Jest実行可能ファイルを指す必要があります。



 "scripts": { "test": "jest" }
      
      





さらに、Jestでは、この構造を使用することを好みます。



 import puppeteer from "puppeteer";
      
      





そこで、JestにBabelが必要です。



 npm i babel-core babel-jest babel-preset-env --save-dev
      
      





Babelのインストール後、プロジェクトフォルダーに次の内容の.babelrc



ファイルを作成します。



 { "presets": ["env"] }
      
      





これで準備が完了し、テストの作成を開始できます。



テストを書く



プロジェクトフォルダに新しいディレクトリを作成します。 test



またはspec



と呼ぶことができます。 次に、このディレクトリでform.spec.js



ファイルを作成します。



ここで、インポートセクションから始めて、テストコードを部分的に検討することを提案します。 以下に、このすべてのコード全体を示します。



まず、FakerとPuppeteerをインポートします。



 import faker from "faker"; import puppeteer from "puppeteer";
      
      





次に、フォームのURLを設定します。 おそらく、本番サイトに接続する代わりに、開発中のローカルで使用可能なフォームのバージョンをテストすることにします。



 const APP = "https://www.change-this-to-your-website.com/contact-form.html"
      
      





次に、Fakerを使用して、ダミーユーザーを作成します。



 const lead = { name: faker.name.firstName(), email: faker.internet.email(), phone: faker.phone.phoneNumber(), message: faker.random.words() };
      
      





次に、Puppeteerで作業するために必要ないくつかの変数を定義します。



 let page; let browser; const width = 1920; const height = 1080;
      
      





次に、Puppeteerの動作を設定します。



 beforeAll(async () => { browser = await puppeteer.launch({   headless: false,   slowMo: 80,   args: [`--window-size=${width},${height}`] }); page = await browser.newPage(); await page.setViewport({ width, height }); }); afterAll(() => { browser.close(); });
      
      





ここでは、Jest beforeAll



およびafterAll



を使用しafterAll



。 テストを実行する前に、Puppeteerを使用してブラウザーを起動する必要があるため、最初のものが必要です。 ブラウザを起動した後、新しいページを開くことができます。 テストが完了したら、ブラウザを閉じる必要があります。 これは、 browser.close()



コマンドを使用してafterAll



メソッドで実行されます。



afterAll



afterAll



だけに限定されないことに注意してください。 Jestのその他の機能については、このライブラリのドキュメントをご覧ください。 いずれの場合でも、個々のテストごとにブラウザーを開いたり閉じたりするのではなく、1つのブラウザーインスタンスを使用してテストスイート全体を実行することをお勧めします。



ここで、上記のコードスニペットについていくつかコメントしたいと思います。 つまり、 headless: false



パラメーターを使用してブラウザーをウィンドウモードで起動することに注意してください。 この場合、これは、ビデオの画面で何が起こっているかを記録し、テストプロセスを表示できるようにするために行われます。 説明したツールを使用して実際のテストを実行すると、通常、何が起こっているのかを観察する必要はありません。 インターフェースなしでブラウザを起動するには、 launch()



メソッドを呼び出すときに使用したパラメータを削除するだけです。



同じことはsetViewPort()



コマンドにもsetViewPort()



ますが、このコマンドも削除できます。 または、さらに良いことに、2つの異なるテスト環境をセットアップできます。 1つは視覚的なデバッグに使用されます(これについては以下で説明します)、2つ目はユーザーインターフェイスなしでブラウザーを操作するためです。



次に、テストコードを記述します。



 describe("Contact form", () => { test("lead can submit a contact request", async () => {   await page.waitForSelector("[data-test=contact-form]");   await page.click("input[name=name]");   await page.type("input[name=name]", lead.name);   await page.click("input[name=email]");   await page.type("input[name=email]", lead.email);   await page.click("input[name=tel]");   await page.type("input[name=tel]", lead.phone);   await page.click("textarea[name=message]");   await page.type("textarea[name=message]", lead.message);   await page.click("input[type=checkbox]");   await page.click("button[type=submit]");   await page.waitForSelector(".modal"); }, 16000); });
      
      





Jestでasync / awaitコンストラクト使用する可能性に注意してください。 ここでは、Node.jsの最新バージョンの1つを使用してテストが実行されることを前提としています。



これらのテストを検討してください。 ソフトウェア制御ブラウザが実行する手順は次のとおりです。





Jasmine test()



関数は、2番目のパラメーターとして、タイムアウト(16000)が渡されたことに注意してください。 これにより、ブラウザがページでどのように機能するかを正確に監視できます。



画面に表示されるブラウザを使用してテストし、タイムアウトを設定しないと、次のエラーが発生します。



 Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL
      
      





インターフェイスなしでブラウザを起動してテストを実行する場合、タイムアウトを削除できます。



これですべての準備が整い、次のコマンドでテストを開始できます。



 npm test
      
      





その後、ブラウザを監視するだけで、ブラウザ自体がページで動作します。





興味がある場合、この画面のビデオは、 recordmydesktop



と次のコマンドを使用してFedoraで記録されました。



 recordmydesktop --width 1024 --height 768 -x 450 -y 130 --no-sound
      
      





ただし、それだけではありません。



他のインターフェース要素のテスト



フォームを理解したので、他のページ要素をテストできます。



<title></title>



して、状況を確認しましょう。 ご存じのとおり、意味のあるページタイトルが必要です。



 describe("Testing the frontend", () => { test("assert that <title> is correct", async () => {   const title = await page.title();   expect(title).toBe(     "Gestione Server Dedicati | Full Managed | Assistenza Sistemistica"   ); }); //      });
      
      





ナビゲーションバーはどうですか? 彼女はページに存在する必要があります。 この場合、JestとPuppeteerに確認してください。



 // test("assert that a div named navbar exists", async () => {   const navbar = await page.$eval(".navbar", el => (el ? true : false));   expect(navbar).toBe(true); }); //
      
      





特定の要素に含まれるべきテキストが含まれているかどうかも確認できます。



 // test("assert that main title contains the correct text", async () => {   const mainTitleText = await page.$eval("[data-test=main-title]", el => el.textContent);   expect(mainTitleText).toEqual("GESTIONE SERVER, Full Managed"); }); //
      
      





検索エンジン最適化のためにページをテストするのはどうですか? たとえば、 正規リンクを確認します。



 describe("SEO", () => { test("canonical must be present", async () => {   await page.goto(`${APP}`);   const canonical = await page.$eval("link[rel=canonical]", el => el.href);   expect(canonical).toEqual("https://www.servermanaged.it/"); }); });
      
      





同じ原則により、他の多くのテストを作成できます。



その結果、すべてのテストが正常に完了しました。これは、緑色の心地よいメッセージで判断できます。









視覚的なデバッグ



Puppeteerを使用すると、ユーザーインターフェースを使用して、または使用せずに起動したChromiumで作業を自動化できると既に述べました。 次のコードスニペットを思い出してください。



 beforeAll(async () => { browser = await puppeteer.launch({     //       headless: false,     slowMo: 80,     args: [`--window-size=1920,1080`]   }); page = await browser.newPage(); /// });
      
      





さらに、グラフィカルインターフェイスでブラウザーを起動するときは、Jasmineタイムアウトパラメーターを渡す必要があることに注意する必要があります。 そうしないと、テストがすぐに予期せず終了します。 タイムアウトは、 test()



メソッドの2番目の引数です。



 describe("Contact form", () => { test(   "lead can submit a contact request",   async () => {   /////    },   16000 // <<< - Jasmine ); });
      
      





自動テストでは、ブラウザウィンドウを表示する必要はありません。そうしないと、少なくともいくつかの深刻なテストスイートの実行に時間がかかります。 ただし、コードから制御されたブラウザーで何が起こるかを見ると便利な場合があります。 インターフェイスのあるブラウザとないブラウザを使用して、テストを簡単に切り替える方法は?



この問題は、補助関数を作成することで解決できます。 これを実行して、 testingInit.js



ファイルに入れましょう。



 export const isDebugging = () => { let debugging_mode = {   puppeteer: {     headless: false,     slowMo: 80,     args: [`--window-size=1920,1080`]   },   jasmine: 16000 }; return process.env.NODE_ENV === "debug" ? debugging_mode : false; };
      
      





次に、テストコードを使用してファイルからアクセスし、最初にインポートしてから、ブラウザの起動時に使用します。



 /// import { isDebugging } from "./testingInit.js"; /// beforeAll(async () => { browser = await puppeteer.launch(isDebugging().puppeteer)); // <<<   page = await browser.newPage(); /// });
      
      





タイムアウトを設定するときに同じ関数が役立ちます。



 describe("Contact form", () => { test(   "lead can submit a contact request",   async () => {   /////    }, isDebugging().jasmine // <<< - Jasmine ); });
      
      





その後、インターフェースのないブラウザーでテストを開始するには、次のコマンドを実行するだけで十分です。



 npm test
      
      





ビジュアルモードでテストを実行するには、次を実行する必要があります。



 NODE_ENV=debug npm test
      
      





まとめ



まだ、PuppeteerまたはそのAPIを使用することに不安があるかもしれません。 分かりました。 そして、このプロジェクトの目新しさがその実用的な適用性に疑問を抱いているなら、たとえばサイプレスをご覧ください 。 ただし、Puppeteerは開発者に真に無限の可能性を与えます。 このライブラリに基づいてテストフレームワークが作成されています。 もちろん、時間の経過とともに、Puppeteer APIは変更される可能性がありますが、ここで説明した基本的なことはどこにも行き当たりません。 さらに、PuppeteerはJestとも相性が良いことに注意してください。 さらに、多くはPuppeteer E2Eテストを実行します



親愛なる読者! Webインターフェースのテストをどのように自動化しますか?



All Articles