如何使用 Jest/Puppeteer 等待元素从 DOM 中移除

Els*_*rit 6 javascript jestjs puppeteer

问题总结:我正在编写几个测试套件(使用 Jest 和 Puppeteer)来自动化我的 AngularJS 应用程序主页的测试。我想要自动化的测试之一是用户按下页面上的按钮删除 DOM 中的元素。不幸的是,这个元素是用来显示大量数据的,所以为了删除元素,客户端首先需要向我的服务器发出POST请求从db中删除数据,然后才能删除元素从 DOM 中删除。总而言之,整个过程大约需要一两秒钟。更重要的是,我尝试删除的这个元素是动态添加到 DOM 中的,所以我能够访问该元素的唯一方法是使用 XPath,它通过它包含的文本来标识元素,而不是传统的 CSS 选择器. 现在这是我的问题:

这是我的 HTML 外观的概述,以便您了解我正在使用的内容:

<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>
Run Code Online (Sandbox Code Playgroud)

背景:我使用 Jest (v24.8.0) 作为我的测试框架。我正在使用 Puppeteer (v1.19.0) 来启动和控制无头 Chromium 浏览器。

到目前为止我尝试过的:

目前,我有这个代码

  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);
  }); 
Run Code Online (Sandbox Code Playgroud)

我可以做这样的事情:

  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);
  }); 
Run Code Online (Sandbox Code Playgroud)

...但我希望能够摆脱我的await delay线路,并让测试准确地等待元素消失。问题await delay在于它是不可靠的,因为取决于元素显示的数据量,它可能需要比await delay指定的更多或更少的时间来删除。

结论: 你们中的任何一个 Jest/Puppeteer 黑客以前遇到过这样的问题并且知道任何聪明的解决方案吗?

Tho*_*orf 6

您可以使用page.waitForXPathwith 选项{ hidden: true }page.waitForFunction通过编写一个测试元素是否不存在的函数来使用。

page.waitForXPath 与 hidden:true

await page.waitForXPath(elemXPath, { hidden: true });
Run Code Online (Sandbox Code Playgroud)

替代方案:page.waitForFunction

或者,您可以使用以下代码来使用简单的选择器:

await page.waitForFunction(() => !document.querySelector('#selector-of-element'));
Run Code Online (Sandbox Code Playgroud)

如果要使用 XPath 表达式,可以使用以下代码:

const elemXPath = '//div[contains(text(), "My Data")]';
await page.waitForFunction(
  xpath => !document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue,
  {},
  elemXPath
);
Run Code Online (Sandbox Code Playgroud)

这将您的选择器传递给函数并使用document.evaluate函数在浏览器上下文中运行 XPath 表达式。