92

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

extjs ベースの Web ページの自動テストの作成に成功した人はいますか? 多くのグーグルは、同様の問題を抱えている人々を見つけますが、答えはほとんどありません. ありがとう!

4

11 に答える 11

173

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>要素ではなく、ドキュメント ツリーの下部のどこかにドロップダウン リストが分離されたテキスト入力です。ComboBox の選択を適切にシミュレートするために、最初にドロップダウン矢印のクリックをシミュレートしてから、表示されるリストをクリックすることができます。ただし、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

フィールド検証

validationDelay検証用の正規表現または vtype が関連付けられているフォーム フィールド (Ext.form.* コンポーネント)は、ユーザーがテキストを入力した後、またはフィールドが失われた直後に、一定の遅延 (デフォルトで 250 ミリ秒に設定されているプロパティを参照) で検証をトリガーします。 focus -- またはぼかします (validateOnDelayプロパティを参照)。type Selenium コマンドを発行してフィールド内にテキストを入力した後にフィールドの検証をトリガーするには、次のいずれかを実行する必要があります。

  • 遅延検証のトリガー

    ExtJS は、フィールドがキーアップ イベントを受け取ると、検証遅延タイマーを起動します。このタイマーをトリガーするには、単純にダミーの keyup イベントを発行し (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"))]

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

要素固有のヒント

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'); }

最初に値を設定してから、オブザーバーが存在する場合に選択イベントを明示的に発生させます。

于 2008-10-20T19:01:39.017 に答える
5

このブログには大変お世話になりました。彼はこのトピックについてかなり多くのことを書いており、まだ活発に活動しているようです。男はまた、良いデザインを高く評価しているようです.

彼は基本的に、送信する JavaScript を使用してクエリを実行し、Ext.ComponentQuery.query メソッドを使用して ext アプリで内部的に行うのと同じ方法で内容を取得することについて話しています。そうすれば、xtypes と itemIds を使用でき、狂った自動生成されたものを解析しようとすることを心配する必要はありません。

特にこの記事はとても参考になりました。

ここでもう少し詳細なものをすぐに投稿する可能性があります-これを適切に行う方法をまだ頭に入れようとしています

于 2014-01-31T09:30:58.340 に答える
4

ExtJs Web アプリケーションをセレンでテストしています。最大の問題の 1 つは、グリッド内の項目を選択して何かを行うことでした。

このために、私はヘルパー メソッドを書きました (SeleniumExtJsUtils クラスで、ExtJs とのやり取りを容易にするための便利なメソッドのコレクションです):

/**
 * Javascript needed to execute in order to select row in the grid
 * 
 * @param gridId Grid id
 * @param rowIndex Index of the row to select
 * @return Javascript to select row
 */
public static String selectGridRow(String gridId, int rowIndex) {
    return "Ext.getCmp('" + gridId + "').getSelectionModel().selectRow(" + rowIndex + ", true)";
}

行を選択する必要がある場合は、次のように呼び出します。

selenium.runScript( SeleniumExtJsUtils.selectGridRow("<myGridId>", 5) );

これを機能させるには、グリッドに ID を設定し、ExtJ に独自の ID を生成させないようにする必要があります。

于 2008-10-08T23:38:55.543 に答える
4

その要素が表示されていることを検出するには、次の句を使用します。 not(contains(@style, "display: none")

これを使用することをお勧めします:

visible_clause = "not(ancestor::*[contains(@style,'display: none')" +
    " or contains(@style, 'visibility: hidden') " + 
    " or contains(@class,'x-hide-display')])"

hidden_clause = "parent::*[contains(@style,'display: none')" + 
    " or contains(@style, 'visibility: hidden')" + 
    " or contains(@class,'x-hide-display')]"
于 2009-09-24T11:35:51.597 に答える
3

extjs のテストで発生している問題の種類について、さらに詳しい情報を提供していただけますか?

私が便利だと思う Selenium 拡張機能の 1 つは、waitForConditionです。問題が Ajax イベントに問題があると思われる場合は、waitForCondition を使用してイベントが発生するのを待つことができます。

于 2008-09-20T06:21:25.927 に答える
3

Ext JS Web ページは、Ext JS グリッドのように生成される HTML が複雑なため、テストが難しい場合があります。

HTML5 ロボットは、動的ではない属性と条件に基づいて、コンポーネントを確実に検索して操作する一連のベスト プラクティスを使用することで、これに対処します。次に、対話する必要があるすべての HTML、Ext JS、および Sencha Touch コンポーネントでこれを行うためのショートカットを提供します。2 種類のフレーバーがあります。

  1. Java - 使い慣れた Selenium および JUnit ベースの API で、最新のすべてのブラウザーの Web ドライバー サポートが組み込まれています。
  2. Gwen - ブラウザー テストをすばやく簡単に作成および維持するためのヒューマン スタイルの言語で、独自の統合開発環境が付属しています。これらはすべて Java API に基づいています。

たとえば、"Foo" というテキストを含む Ext JS グリッド行を見つけたい場合、Java で次のように実行できます。

findExtJsGridRow("Foo");

...そして、グウェンで次のことができます:

extjsgridrow by text "Foo"

Ext JS 固有のコンポーネントを操作する方法については、 Javaと Gwenの両方について多くのドキュメントがあります。ドキュメントには、これらすべての Ext JS コンポーネントの HTML の詳細も記載されており、これも役立つ場合があります。

于 2013-11-06T01:24:36.750 に答える
2

ページ上のグリッドの Id を使用してグリッドを取得するための役立つヒント: この API からさらに便利な機能を拡張できると思います。

   sub get_grid_row {
        my ($browser, $grid, $row)  = @_;


        my $script = "var doc = this.browserbot.getCurrentWindow().document;\n" .
            "var grid = doc.getElementById('$grid');\n" .
            "var table = grid.getElementsByTagName('table');\n" .
            "var result = '';\n" .
            "var row = 0;\n" . 
            "for (var i = 0; i < table.length; i++) {\n" .
            "   if (table[i].className == 'x-grid3-row-table') {\n".
            "       row++;\n" . 
            "       if (row == $row) {\n" .
            "           var cols_len = table[i].rows[0].cells.length;\n" .
            "           for (var j = 0; j < cols_len; j++) {\n" .
            "               var cell = table[i].rows[0].cells[j];\n" .
            "               if (result.length == 0) {\n" .
            "                   result = getText(cell);\n" .
            "               } else { \n" .
            "                   result += '|' + getText(cell);\n" .
            "               }\n" .
            "           }\n" .
            "       }\n" .
            "   }\n" .
            "}\n" .
            "result;\n";

        my $result = $browser->get_eval($script);
        my @res = split('\|', $result);
        return @res;
    }
于 2009-01-14T02:43:38.680 に答える
2

カスタム HTML データ属性による簡単なテスト

Senchaのドキュメントから:

オブジェクト参照が利用できない場合、コンポーネントへの参照を取得する別の方法として itemId を使用できます。Ext.getCmp で ID を使用する代わりに、itemId または ID を取得する Ext.container.Container.getComponent で itemId を使用します。itemId はコンテナーの内部 MixedCollection へのインデックスであるため、itemId はコンテナーに対してローカルにスコープされ、一意の ID を必要とする Ext.ComponentManager との潜在的な競合を回避します。

Ext.AbstractComponentのメソッドをオーバーライドしてonBoxReady、カスタム データ属性 (各コンポーネントのカスタム プロパティに由来する名前testIdAttr) をコンポーネントのitemId値に設定します (存在する場合)。Testing.overrides.AbstractComponentクラスをapplication.jsファイルのrequires配列に追加します。

/**
 * Overrides the Ext.AbstracComponent's onBoxReady
 * method to add custom data attributes to the
 * component's dom structure.
 *
 * @author Brian Wendt
 */
Ext.define('Testing.overrides.AbstractComponent', {
  override: 'Ext.AbstractComponent',


  onBoxReady: function () {
    var me = this,
      el = me.getEl();


    if (el && el.dom && me.itemId) {
      el.dom.setAttribute(me.testIdAttr || 'data-selenium-id', me.itemId);
    }


    me.callOverridden(arguments);
  }
});

このメソッドは、コード内で記述的な識別子を再利用し、ページがレンダリングされるたびにそれらの識別子を使用できるようにする方法を開発者に提供します。説明的でない、動的に生成された ID を検索する必要はもうありません。

于 2013-10-25T12:58:19.937 に答える
1

WebDriver を使用して ExtJS アプリケーションをテストしていたとき、次のアプローチを使用しました。ラベルのテキストでフィールドを探し、ラベル@forから属性を取得しました。たとえば、ラベルがあります

<label id="dynamic_id_label" class="TextboxLabel" for="textField_which_I_am_lloking_for">
Name Of Needed Label
<label/>

そして、WebDriver にいくつかの入力をポイントする必要があります: //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)].

したがって、@for属性から id を選択し、それをさらに使用します。これはおそらく最も単純なケースですが、要素を見つける方法を提供します。ラベルがない場合ははるかに困難ですが、要素を見つけて、兄弟、下降/上昇要素を探して xpath を記述する必要があります。

于 2014-07-10T06:57:13.210 に答える
1

正式な HTML ではない複雑な UI の場合、xPath は常に信頼できるものですが、ExtJ を使用したさまざまな UI 実装となると、少し複雑になります。

Firebug および Firexpath を firefox 拡張機能として使用して、特定の要素の xpath をテストし、単純に完全な xpath をパラメータとして Selenium に渡すことができます。

たとえば、Java コードでは次のようになります。

String fullXpath = "xpath=//div[@id='mainDiv']//div[contains(@class,'x-grid-row')]//table/tbody/tr[1]/td[1]//button"

selenium.click(fullXpath);
于 2010-03-30T05:13:25.987 に答える