PuppeteerとJestを使用したコンポーネントのテスト







Habréには、 PuppeteerJestを使用したライティングテストについて説明した出版物があります。 まだPuppeteerが何であるかわからない場合は、これに慣れることをお勧めします。 この記事では、Reactコンポーネントの例を使用して、コールバック関数の呼び出しをテストする方法について説明します。 たとえば、props onChange



持つコンポーネントがあり、一部のユーザーアクションで、予想されるパラメーターを渡してコールバック関数が呼び出されることをテストする必要があります。 これには、 Puppeteer-ioライブラリが使用されます。 しかし、最初に、ライブラリやフレームワークを参照せずに、htmlおよび純粋なjavascriptの小さな例を見てみましょう...



セレクターによって要素のイベントハンドラーをハングアップするaddEvent



関数があるとします。 イベントでハンドラーが呼び出されることを確認するテストを作成する必要があります。 index.htmlファイルを作成します。



 <button> </button> <script> function addEvent(selector, eventType, handler) { let elements = document.querySelectorAll(selector); Array.prototype.forEach.call(elements, element => { element.addEventListener(eventType, handler, false); }); } addEvent("button", "click", event => console.log("Button.click")); </script>
      
      





これは、テストが行​​われるページです。 クリックイベントハンドラーがハングするボタンがあります。 このイベントで、ハンドラーはconsole.log



を呼び出し、アクションの識別子文字列を渡しますconsole.log



これを受け取ると、テストが成功したことを意味します。 次に、Jestのテストコードを含むindex.html.test.jsファイルを作成します。



 const puppeteer = require("puppeteer"); const io = require("puppeteer-io"); test(`addEvent()    `, async () => { let browser = await puppeteer.launch(); let page = await browser.newPage(); await page.goto(`file://${__dirname}/test.html`); await io({ page, async input() { await page.click("button"); }, async output({ message }) { await message("Button.click"); } }); await page.close(); await browser.close(); });
      
      





Puppeteer-ioについて詳しく説明します。 このライブラリは、並行して実行される2つの非同期関数を受け入れます。 input()



関数はブラウザを制御します。たとえば、要素をクリックするかキーボード入力をシミュレートしますが、 output(api)



はブラウザからデータを受信して​​処理します。 この場合、 message



関数が使用され、そこに予期されるメッセージの識別子文字列が渡されます。 この識別子を持つconsole.log



がブラウザで呼び出されない場合、テストはフリーズし、Jestは失敗したと見なします。



Reactコンポーネントのテスト



例として、次のコンポーネントが使用されます。



 import React from "react"; import PropTypes from "prop-types"; const iItem = PropTypes.shape({ id: PropTypes.string.isRequired, text: PropTypes.string.isRequired }); export default class Select extends React.Component { static propTypes = { items: PropTypes.arrayOf(iItem).isRequired, onChange: PropTypes.func }; getChangeHandler() { return ({ target }) => { if (this.props.onChange) { this.props.onChange(this.props.items[target.selectedIndex].id); } }; } toOption(item, index) { return <option key={`id_${index}_${item.id}`}> {item.text} </option> } render() { return <select onChange={this.getChangeHandler()}> {this.props.items.map(this.toOption)} </select> } }
      
      





これは、標準選択の単なるラッパーです。 アイテムが選択されると、選択されたアイテムのIDが渡されるコールバック関数が呼び出されます。 実際に、この機能をテストします。 これを行うには、Puppeteerがブラウザーで開くテスト用の特別なページを作成します。



 import React from "react"; import ReactDOM from "react-dom"; import Select from "path-to/select-component.js"; const testItems = [ { id: "0e210d4a-ccfd-4733-a179-8b51bda1a7a5", text: "text 1"}, { id: "ea2cecbd-206c-4118-a1c9-8d88474e5a87", text: "text 2"}, { id: "c812a9dc-6a54-409e-adb5-8eb09337e576", text: "text 3"} ]; //    console.log("test-items", testItems); function TestPage() { const onChange = id => console.log("Select: change", id); return <div> <Select items={testItems} onChange={onChange} /> </div> } ReactDOM.render(<TestPage />, document.getElementById("application"));
      
      





そして、たとえばhttp:// localhost:8080というURLでこのページを展開します。 現在、2つの引数がconsole.log



渡されることに注意してくださいconsole.log



最初の引数はidで、2番目の引数はdataです。 次に、テストコードを記述します。



 const puppeteer = require("puppeteer"); const io = require("puppeteer-io"); test(` onChange   id`, async () => { let browser = await puppeteer.launch(); let page = await browser.newPage(); await io({ page, async input() { await page.goto("http://localhost:8080"); let select = await page.$("select"); await select.focus(); await select.press("Enter"); await select.press("ArrowDown"); await select.press("Enter"); }, async output({ dataFromMessage }) { let [,secondItem] = await dataFromMessage("test-items"); let selectedId = await dataFromMessage("Select: change"); expect(selectedId).toBe(secondItem.id); } }); await page.close(); await browser.close(); });
      
      





出力関数のコードを検討してください。 最初のステップは、テストデータを取得することです。 これを行うには、 page.goto



がページのpage.goto



イベントを予期しているため、入力ストリームでURLジャンプをトリガーすることが重要ですconsole.log("test-items", testItems)



その時点までにconsole.log("test-items", testItems)



既に機能し、メッセージは受信されません。 データを取得するには、 dataFromMessage



関数を使用します。この関数は、 console.log



渡される2番目の引数を返します。 テストデータを受信したら、選択したIDを待機し、結果を期待されるIDと比較できます。 機能テスト済み。



キャッチエラー



結論として、エラーの処理方法の例。 ページを作成します。



 <script> throw new Error("test-error"); </script>
      
      





エラーをキャッチするには、 error



関数を使用しerror



関数は、パラメーターとして文字列または正規表現を使用して、 message



プロパティの対応するテキストでエラーを検索し、エラーの全文を返します。 ページでエラーが発生したことを確認するテスト:



 const puppeteer = require("puppeteer"); const io = require("puppeteer-io"); test(`,     `, async () => { let browser = await puppeteer.launch(); let page = await browser.newPage(); await io({ page, async input() { await page.goto(`file://${__dirname}/index.html`); }, async output({ error }) { await error("test-error"); } }); await page.close(); await browser.close(); });
      
      





以上です。 html要素またはそれらのテキストコンテンツの存在をチェックするのではなく、結果を取得し、それを予想と比較することに基づいてテストする方法を検討しました。



All Articles