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

标签 javascript jestjs puppeteer

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

下面是我的 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>

背景:我使用 Jest (v24.8.0) 作为我的测试框架。我正在使用 Puppeteer (v1.19.0) 启动并控制 headless 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);
  }); 

我可以这样做:

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

...但我希望能够摆脱我的 await delay 行,让测试精确地等待,直到元素消失。 await delay 的问题是它不可靠,因为根据元素显示的数据量,删除它可能需要比 await delay 指定的时间更多或更少的时间。

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

最佳答案

您可以使用带有选项 { hidden: true } page.waitForXPath 或使用 page.waitForFunction为此,编写一个函数来测试该元素是否不存在。

page.waitForXPath with hidden:true

await page.waitForXPath(elemXPath, { hidden: true });

替代方案:page.waitForFunction

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

await page.waitForFunction(() => !document.querySelector('#selector-of-element'));

如果你想使用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
);

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

关于javascript - 如何使用 Jest/Puppeteer 等待元素从 DOM 中移除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57400071/

相关文章:

javascript - 卡片翻转动画 Internet Explorer 11

javascript - AngularJS 的 $sce.trustAsHtml 被忽略

javascript - 为什么 express 的 res.download() 方法会导致 "request aborted"错误?

javascript - 如何模拟 axios 类

reactjs - 使用 toHaveBeenNthCalledWith 时 react Jest 测试错误

javascript - 在 puppeteers 监听器 page.on 的回调之外捕获错误

javascript - 努力使用 .querySelector 查询具有相同类名的特定元素

javascript - 加载图像时在 AngularJS 中动态添加 ng-click

node.js - 使用 Puppeteer 禁用生成的 PDF 中的超链接

reactjs - 使用 redux-mock-store 进行单元测试 - 如何使该单元测试通过?