サイプレスを使用して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()
呼び出しは必要ないため、回避する必要があります。ここで何が悪いのですか?
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 })
を試すことができますが、実際のバグを隠す可能性があるため、これは最後の手段です。
これは一般的な問題のようです 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();
}));
});
});
}
特定の値のスパンに到達しようとすると、同じ問題が発生しました。ページ内のすべてのスパン要素を取得するのではなく、スパンへのより具体的なパスを提供することで修正しました。
cy.get('span').contains('Round ID') //not working
cy.get('.details span').contains('Round ID') //worked
したがって、ターゲットにしたいタイプの要素を取得するときに、より具体的にすることができます。別のオプションはwait()です...