javascript - Jest/Puppeteer kullanarak bir element DOM'dan kaldırılana kadar nasıl beklenir
Sorunun özeti: AngularJS uygulamamın ana sayfasının testlerini otomatikleştirmek için birkaç test paketi (Jest ve Puppeteer kullanarak) yazıyorum. Otomatikleştirmek istediğim testlerden biri, sayfadaki bir düğmeye basan bir kullanıcıyı test etmektir; bu düğme DOM'daki bir öğeyi silmektedir. Ne yazık ki, bu öğe büyük miktarda veri göstermek için kullanılıyor, bu yüzden öğenin silinebilmesi için istemcinin önce sunucuma POST isteği yaparak veriyi veritabanından silmesi gerekiyor ve ancak o zaman öğe DOM'dan silinebiliyor. Genel olarak, bu tüm süreç yaklaşık bir iki saniye sürüyor. Üstelik, silmeye çalıştığım bu öğe DOM'a dinamik olarak eklendi, bu yüzden öğeye erişebilmemin tek yolu, geleneksel bir CSS seçicisi yerine içerdiği metin ile öğeyi tanımlayan bir XPath kullanmak. İşte sorum: Jest ve Puppeteer'un API'lerini kullanarak, bu öğenin artık var olmadığı (yani DOM'dan çıktığı) bir durumu BEKLEYEN bazı test kodlarını nasıl yazabilirim?
İşte üzerinde çalıştığım şey hakkında bir fikriniz olması için HTML’imin nasıl göründüğüne dair bir genel bakış:
<html>
<body ng-app="myApp" ng-controller="myCtrl">
<!-- Dynamically added div -->
<div>My Data
<table><!-- Displays tons of data --></table>
</div>
<form>
<button type="submit">Delete</button>
</form>
</body>
</html>
Arka Plan: Test çerçevem olarak Jest (v24.8.0) kullanıyorum. Headless Chromium tarayıcısını başlatmak ve kontrol etmek için Puppeteer (v1.19.0) kullanıyorum.
Şimdiye kadar denediklerim:
Şu anda, bu koda sahibim
test('deleted elem no longer exists', async() => {
elemXPath = '//div[contains(text(), "My Data")]';
// this is a function to pause the
// execution of the test for a given amount of milliseconds
// in order to wait for elem to be removed
await delay(2000);
// This fails because Puppeteer timeouts after 3000
// ms b/c elemXPath no longer exists
const elemExists = await page.waitForXPath(elemXPath, {timeout: 3000}) ? true : false;
expect(elemExists).toBe(false);
});
Böyle bir şey yapabilirim:
test('deleted elem no longer exists', async() => {
elemXPath = '//div[contains(text(), "My Data")]';
// wait for elem to be removed
await delay(2000);
try {
var elemExists = await page.waitForXPath(elemXPath, {timeout: 3000}) ? true : false;
} catch(err) {
var elemExists = false
}
expect(elemExists).toBe(false);
});
... ama await delay satırımı kaldırabilmeyi ve testin öğe tamamen kaybolana kadar tam olarak beklemesini istiyorum. await delay ile ilgili sorun, öğenin görüntülediği veri miktarına bağlı olarak silinmesinin await delay tarafından belirtilenden daha kısa veya uzun sürebilmesidir; bu yüzden güvenilmez olmasıdır.
Sonuç: Hiçbiriniz Jest/Puppeteer geliştiricilerinden biri böyle bir sorunla daha önce karşılaştı mı ve herhangi bir akıllıca çözüm biliyor musunuz?
Cevap #1
page.waitForXPath özelliğini { hidden: true } seçeneği ile kullanabilir veya bir elementin mevcut olmadığını test eden bir fonksiyon yazarak page.waitForFunction ile bunu yapabilirsiniz.
page.waitForXPath ile hidden:true
await page.waitForXPath(elemXPath, { hidden: true });
Alternatif: page.waitForFunction
Alternatif olarak, basit bir seçici kullanmak için aşağıdaki kodu kullanabilirsiniz:
await page.waitForFunction(() => !document.querySelector('#selector-of-element'));
Bir XPath ifadesi kullanmak istiyorsanız, bu kodu kullanabilirsiniz:
const elemXPath = '//div[contains(text(), "My Data")]';
await page.waitForFunction(
xpath => !document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue,
{},
elemXPath
);
Bu, seçicinizi fonksiyona geçirir ve XPath ifadesini tarayıcı bağlamında çalıştırmak için document.evaluate fonksiyonunu kullanır.
Cevap #2
Ya da şunu kullanabilirsiniz:
await page.waitForSelector(selector, { hidden: true });
