1. ホーム
  2. unit-testing

[解決済み] ブラウザでextjsのコードをテストするための提案、できればseleniumで?

2023-02-26 02:47:34

質問

私たちは、高レベルのWebサイトのテスト(モジュールレベルでの広範なPythonのdoctestsに加えて)を処理するために大きな成功を収めているseleniumを使用してきました。 しかし、現在、私たちは多くのページで extjs を使用しており、グリッドのような複雑なコンポーネントのために Selenium テストを組み込むことが困難であることが分かっています。

誰かがextjsベースのWebページのために自動化されたテストを書くことに成功したことがありますか? 多くのググりは、同様の問題を持つ人々を見つけますが、答えはほとんどありません。 ありがとうございます。

どのように解決するのですか?

SeleniumでExtJSをテストする際の最大のハードルは、ExtJSが標準のHTML要素をレンダリングしないため、Selenium IDEが単純に(そして当然)装飾として機能する要素、つまりデスクトップ全体のルック&フィールでExtJSを助ける余分な要素に的を絞ってコマンドを生成することです。ここでは、ExtJSアプリに対して自動化されたSeleniumテストを書きながら、私が集めたいくつかのヒントとトリックを紹介します。

一般的なヒント

要素を探す

Firefox上のSelenium IDEでユーザーのアクションを記録してSeleniumテストケースを生成するとき、SeleniumはHTML要素のidに基づいて記録されたアクションを基づかせるでしょう。しかし、ほとんどのクリック可能な要素に対して、ExtJS は "ext-gen-345" のような生成された ID を使用します。これは、たとえコードが変更されていなくても、同じページへの次の訪問で変更される可能性が高いです。テストのためにユーザーのアクションを記録した後、生成された ID に依存するすべてのアクションを調べ、それらを置き換えるための手作業が必要です。置き換えには2つのタイプがあります。

ID ロケータを CSS または XPath ロケータに置き換える

CSS ロケータは "css=" で始まり、XPath ロケータは "//" で始まります ("xpath=" のプレフィックスはオプションです)。CSS ロケータは冗長でなく読みやすいので、XPath ロケータよりも優先されるべきです。しかし、CSS ロケータでは対応できないため、XPath ロケータを使用しなければならない場合もあります。

JavaScript の実行

一部の要素は、ExtJSによって実行される複雑なレンダリングのために、単純なマウス/キーボード操作以上のものを必要とします。例えば、Ext.form.CombBoxは実際には <select> 要素ではなく、ドキュメントツリーの下部にあるドロップダウン・リストが分離されたテキスト入力です。コンボボックスの選択を適切にシミュレートするには、まずドロップダウン矢印をクリックし、次に表示されるリストをクリックするようにシミュレートすることが可能です。しかし、CSS や XPath ロケータを使用してこれらの要素を見つけるのは面倒です。代替案は、ComoBox コンポーネント自体を見つけ、そのメソッドを呼び出して、選択をシミュレートすることです。

var combo = Ext.getCmp('genderComboBox'); // returns the ComboBox components
combo.setValue('female'); // set the value
combo.fireEvent('select'); // because setValue() doesn't trigger the event

Seleniumでは runScript コマンドを使用すると、より簡潔な形式で上記の操作を実行できます。

with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

AJAXと遅いレンダリングへの対応

Seleniumは、ユーザーアクションがページ遷移または再ロードをもたらすとき、ページロードを待機するためのすべてのコマンドのために"*AndWait"のフレーバーを持っています。しかし、AJAXフェッチは実際のページロードを伴わないので、これらのコマンドは同期のために使用することができません。解決策としては、AJAX進捗インジケーターの有無や、グリッド内の行、追加コンポーネント、リンクなどの外観上の手がかりを利用することです。たとえば

Command: waitForElementNotPresent
Target: css=div:contains('Loading...')

ユーザーアクションによってビューが変更された後、ExtJSがコンポーネントをレンダリングする速度に応じて、ある要素が一定の時間後にのみ表示されることがあります。このような場合、恣意的な遅延を使用する代わりに pause コマンドで任意に遅延させるのではなく、関心のある要素が手の届くところに来るまで待つのが理想的な方法です。例えば、アイテムが表示されるのを待ってからクリックすることです。

Command: waitForElementPresent
Target: css=span:contains('Do the funky thing')
Command: click
Target: css=span:contains('Do the funky thing')

異なるブラウザや異なるマシンでテストを実行することによるタイミングの違いは、テストケースを不安定にするので、任意の休止に依存するのは良いアイデアではありません。

非クリック項目

一部の要素は、トリガーできないように click コマンドでトリガーできない要素もあります。それは、イベントリスナーが実際にはコンテナ上にあり、子要素のマウスイベントを監視し、それが最終的に親要素にバブルアップされるからです。タブコントロールがその一例です。タブをクリックするために mouseDown イベントをシミュレートする必要があります。

Command: mouseDownAt
Target: css=.x-tab-strip-text:contains('Options')
Value: 0,0

フィールドの検証

フォームフィールド(Ext.form.*コンポーネント)で、検証用の正規表現またはvtypesが関連付けられているものは、一定の遅延をもって検証を開始します( validationDelay プロパティを参照。デフォルトでは 250ms に設定されています)、ユーザーがテキストを入力した後、またはフィールドがフォーカスを失った時(またはぼやけた時)直ちに検証を開始します ( validateOnDelay プロパティを参照)。フィールド内にテキストを入力するために Selenium type コマンドを発行した後にフィールドバリデーションをトリガーするためには、次のどちらかを行う必要があります。

  • 遅延検証のトリガー

    ExtJSは、フィールドがキーアップイベントを受信すると、検証遅延タイマーを起動します。このタイマーを起動するには、単にダミーのキーアップイベントを発行し(ExtJSはそれを無視するので、どのキーを使用してもかまいません)、その後にvalidationDelayよりも長い短いポーズをとります。

    Command: keyUp
    Target: someTextArea
    Value: x
    Command: pause
    Target: 500
    
    
  • 即時検証のトリガー

    即時検証をトリガするために、フィールドにブラーイベントを注入することができます。

    Command: runScript
    Target: someComponent.nameTextField.fireEvent("blur")
    
    

バリデーション結果の確認

バリデーションの後、エラーフィールドの有無を確認することができます。

Command: verifyElementNotPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

Command: verifyElementPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

エラーフィールドが一度表示され、その後非表示にする必要がある場合、ExtJSはエラーフィールドをDOMツリーから完全に削除するのではなく、単に非表示にするため、 "display: none" のチェックが必要であることに注意してください。

要素固有のヒント

Ext.form.Buttonをクリックする

  • オプション1

    コマンド:クリック ターゲット:css=button:contains('Save')

    ボタンのキャプションで選択する

  • オプション2

    コマンド:クリック ターゲット:css=#save-optionsボタン

    ボタンをidで選択する

Ext.form.ComboBoxから値を選択する

Command: runScript
Target: with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

まず値を設定し、オブザーバがいる場合は明示的に select イベントを発生させます。