web-dev-qa-db-ja.com

cypress.io:contains()が要素を待機していません

サイプレスを使用してUIテストを作成しています。これは通常、非常に簡単に使用できます。しかし、何度も何度も、退屈な待機問題に遭遇しました。

シナリオはかなり単純です。ユーザーが検索ボタンをクリックします。次に、特定のテキストを持つ要素の1つを選択します。これがコードです:

_cy.get('#search-button').click();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();
_

3番目のクリックイベントは失敗します。これは、すでにcy.contains('Test item 1')がページと要素のレンダリングを待機していないためです。テストステップで確認できることから、ページの中央をクリックするだけで、本質的に何もしません。したがって、後続のすべてのステップはもちろん失敗します。

ただし、次のような呼び出しの間にwait()を追加すると、

_cy.get('#search-button').click();
cy.wait(2000);
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();    
_

ページが正しくレンダリングされ、_Test item 1_が表示されてクリックされ、後続のすべての手順が成功します。

ベストプラクティス によると、wait()呼び出しは必要ないため、回避する必要があります。ここで何が悪いのですか?

10
Ash

tl; dr

containsのタイムアウトを大きくする:

_cy.get('#search-button').click();
cy.contains('Test item 1', { timeout: 4000 }).click();
cy.get('#cheapest-offer-button').click();  
_

説明

多くのサイプレスコマンドと同様に、オプションオブジェクトを受け入れる containsには2番目の引数があります 。次のように、コマンドがtimeoutキーで待機するミリ秒の量を渡すことができます。

_.contains('Stuff', { timeout: 5000 }) // Timeout after 5 secs
_

このように、コマンドは、前にwaitを追加した場合と同じように動作しますが、コマンドが成功した場合、waitのように常に待機することはありません。

タイムアウトに関するサイプレスの公式ドキュメント は、この手法について説明しています。それがどのように機能し、どのように実行する必要があるか、およびチェーンアサーションにどのように影響するかを示しています。

アイテムをクリックできない理由が可視性である場合は、.click({ force: true })を試すことができますが、実際のバグを隠す可能性があるため、これは最後の手段です。

3
totymedli

これは一般的な問題のようです https://github.com/cypress-io/cypress/issues/695

解決策は、Selenium Webdriverに基づくフレームワークのように、サイプレスにすべての非同期操作を待機させることです。 cy.wait()よりもはるかに高速です。メソッドを実装してください:

function waitForBrowser() { 
   cy.window().then(win => {
      return new Cypress.Promise(resolve => win['requestIdleCallback'](resolve));
   });
}

そして、次のように使用してください:

cy.get('#search-button').click();
waitForBrowser();
cy.contains('Test item 1').click();
cy.get('#cheapest-offer-button').click();

Angularを使用する場合、waitForBrowserの代わりにwaitForAngularを使用することをお勧めします

function waitForAngular() {
  return cy.window().then(win => {
      return new Cypress.Promise((resolve, reject) => {
        let testabilities = win['getAllAngularTestabilities']();
        if (!testabilities) {
            return reject(new Error('No testabilities. Check Angular API'));
        }
        let count = testabilities.length;
        testabilities.forEach(testability => testability.whenStable(() => {
            count--;
            if (count !== 0) return;
            resolve();
        }));
      });
  });
}
0
EvgenyV

特定の値のスパンに到達しようとすると、同じ問題が発生しました。ページ内のすべてのスパン要素を取得するのではなく、スパンへのより具体的なパスを提供することで修正しました。

cy.get('span').contains('Round ID') //not working
cy.get('.details span').contains('Round ID') //worked

したがって、ターゲットにしたいタイプの要素を取得するときに、より具体的にすることができます。別のオプションはwait()です...

0