如何强制 Puppeteer 等待非常大的 HTML 表中的所有行完全加载并显示在 DOM 中

Els*_*rit 1 javascript angularjs jestjs angularjs-material puppeteer

问题

问题摘要:我正在编写几个测试套件(使用 Jest 和 Puppeteer)来自动测试 AngularJS 应用程序的主页。注意:我的一些 ui 组件由名为 AngularJS Material 的框架提供支持。我想要自动化的测试之一是用户按下页面上的按钮来重新加载表格。不幸的是,这个表用于显示大量数据,因此为了重新加载该表,客户端首先需要向我的服务器发出 GET 请求,以从 db 中提取该表数据,然后该表才能重新加载显示在 DOM 中。总而言之,整个过程大约需要一两秒钟。所以这是我的问题:如何编写一些 Jest/Puppeteer 测试代码来等待表在 DOM 中完全加载/显示(即显示所有表行数据)。

编辑以澄清:

无法预先确定表中有多少行。我知道根据我提供的最小示例,我似乎可以。但不幸的是,表中的行数是由用户添加的数据量决定的。

我的测试环境概述:

  • 傀儡师版本:1.19.0
  • 笑话版本:24.8.0

代码/到目前为止我尝试过的

下面你会看到我尝试了几种方法来等待所有行数据显示,但还没有任何效果。

<!-- index.html -->
<html>
  <body ng-app="myApp" ng-controller="myCtrl">
    <md-content class="tableContainer">
      <md-content class="table">
        <!-- UI component provided by Angular JS Material, appears while table is loading -->
        <md-progress-linear md-mode="indeterminate"></md-progress-linear>
        <table>
          <thead><!-- my table header --></thead>
          <tbody><!-- displays tons of data --></tbody>
        </table>
      </md-content>
    </md-content>
    <button id="reloadTableBtn" ng-click="myCtrl.reloadTableData()">Reload Table</button>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)
// index.spec.js
test('reload table', async() => {

  let reloadTableBtnSelector = 'button[id="reloadTableBtn"]';
  await page.waitForSelector(reloadTableBtnSelector, {visible: true, timeout: globals.timeouts.selector});
  await page.click(reloadTableBtnSelector);

  /* attempt #1: wait for progress bar to disappear from display - fails
     for unknown reason perhaps because the progress bar disappears when
     the client gets response from the server, instead of when
     all data has been rendered 
  */
  let progressLinearSelector = 'md-content.mdtTable md-progress-linear';
  await page.waitForSelector(progressLinearSelector, {hidden: true, timeout: 3000});
  await page.waitFor(2000);

  /* attempt #2: wait for tbody to be added to the DOM - fails 
     b/c tbody is added to the DOM before all rows have been rendered
  */
  await page.waitForFunction(() => document.querySelector('table tbody'));

  /* attempt #3: wait to tbody to be displayed in the DOM - fails. 
     Jest throws Timeout Error for unknown reason
  */
  await page.waitForSelector('table tbody', {visible: true, timeout: 3000});

  /* attempt #4: just wait n milliseconds for the full table to be displayed 
     - not reliable (and prone to failure) b/c table might take more or less
     time than n seconds to load (depending on how much data is being rendered)
  */
  await page.waitFor(2000);
});
Run Code Online (Sandbox Code Playgroud)

另一个可能的解决方案是等待所有网络连接完成。我有另一个测试通过以下方式执行此操作: await page.goto('https://my-website.com', {waitUntil: 'networkidle0'}); ...但是所有具有可用选项的页面方法都waitUntil涉及导航到不同的网页/重新加载网页,而这不是我想要的。

结论

如果你们中的任何 Jest/Puppeteer 专家知道这个问题的解决方案,我真的很感激您的建议:)

Tho*_*orf 7

等到桌子满了

最简单的方法可能是等待page.waitForFunction表填满足够的行。我想您知道大致预期有多少表行,因此您可以使用以下代码:

await page.waitForFunction(() => document.querySelectorAll('#table-selector tr').length >= 1000);
Run Code Online (Sandbox Code Playgroud)

这会暂停脚本,直到至少有1000这会暂停脚本,直到表内

正如您提到的,条件是“至少一行或一个特定句子”,您可以将其更改为:

await page.waitForFunction(
  () => !!document.querySelector('#table-selector tr') || document.querySelector('#noresults-selector').innerText.includes('no results')
);
Run Code Online (Sandbox Code Playgroud)

这会等到表至少有一行或no results给定选择器内有文本。

等待网络响应

我建议不要等到不再有网络流量,因为您的脚本在下载数据后可能仍需要几毫秒的时间来用数据填充表。如果您仍然想尝试一下,我建议您指定在继续之前要等待哪个响应:

await page.waitForResponse(response => response.url().includes('/url-to-wait-for'));
Run Code Online (Sandbox Code Playgroud)

使用page.waitForResponse,代码会等待,直到收到特定 URL 的响应。