简体   繁体   English

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

[英]How to force Puppeteer to wait until all rows in very large HTML table are fully loaded and displayed in the DOM

Problem 问题

Summary of problem: I'm writing several test suites (using Jest and Puppeteer) to automate tests of my AngularJS app's home page. 问题摘要:我正在编写几个测试套件(使用Jest和Puppeteer)以自动化对AngularJS应用程序主页的测试。 Note: Some of my ui components are powered by a framework called AngularJS Material. 注意:我的一些ui组件由名为AngularJS Material的框架提供支持。 One of the tests I would like to automate is a user pressing a button on the page that reloads a table. 我要自动化的测试之一是用户按下页面上的按钮以重新加载表格。 Unfortunately, this table is used to display a large amount of data, so in order for the table to be reloaded, the client first needs to make GET request to my server to extract the table data from the db, and only then can the table be displayed in the DOM. 不幸的是,该表用于显示大量数据,因此,为了重新加载该表,客户端首先需要向我的服务器发出GET请求以从db中提取表数据,然后该表才可以在DOM中显示。 All in all, this whole process takes about a second or two. 总而言之,整个过程大约需要一到两秒钟。 So here's my question: how can I write some Jest/Puppeteer test code to WAIT for the table to be fully loaded/displayed in the DOM (ie ALL table row data is displayed). 所以这是我的问题:我 如何向WAIT写一些Jest / Puppeteer测试代码,以使表完全加载/显示在DOM中(即显示所有表行数据)。

Edit for clarification: 编辑以澄清:

I cannot predetermine how many rows there will be in the table. 无法确定表中将有多少行。 I know like it may seem like I can based on the minimal example I provided. 我知道,根据提供的最小示例,我似乎可以做到。 But unfortunately, the number of rows in the table is determined by how much data the user adds. 但是不幸的是,表中的行数取决于用户添加的数据量。

Overview of my testing environment: 我的测试环境概述:

  • Puppeteer version: 1.19.0 木偶版本:1.19.0
  • Jest version: 24.8.0 开玩笑的版本:24.8.0

Code/ What I've tried so far 代码/到目前为止我尝试过的

Below you will see that I've tried several methods to wait for all row data to be displayed, but nothing has worked yet. 在下面,您将看到我尝试了几种方法来等待所有行数据的显示,但是还没有任何效果。

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

Another potential solution to this would be to wait for all the network connections to finish. 另一个可能的解决方案是等待所有网络连接完成。 I have another test that does this via: await page.goto('https://my-website.com', {waitUntil: 'networkidle0'}); 我有另一个测试可以通过以下方式完成: await page.goto('https://my-website.com', {waitUntil: 'networkidle0'}); ... but all the page methods that have the waitUntil option available to them involve navigating to different webpages/reloading webpages, and that's not what I want. ...但是所有具有waitUntil选项的页面方法都涉及导航到不同的网页/重新加载网页,而这不是我想要的。

Conclustion Conclustion

If any of you Jest/Puppeteer experts out there know of a solution for this, I'd really appreciate your advice :) 如果您当中的Jest / Puppeteer专家中有人知道解决方案,我将非常感谢您的建议:)

Waiting until the table is filled 等到桌子填满

The easiest way is probably to use page.waitForFunction to wait until the table is filled with enough rows. 最简单的方法可能是使用page.waitForFunction等待,直到表中充满了足够的行。 I imagine you know how many table rows are roughly expected, so you could use the following code: 我想您知道大概需要多少个表行,因此可以使用以下代码:

await page.waitForFunction(() => document.querySelectorAll('#table-selector tr').length >= 1000);

This pauses the script until there are at least 1000 rows inside of the table. 这将暂停脚本,直到表内至少有1000行。

As you mentioned, that the condition is "at least one row or a specific sentence", you could change it to this: 如前所述,条件是“至少一行或一个特定的句子”,您可以将其更改为:

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

This waits until the table has at least one row or until there is the text no results inside the given selector. 一直等到表至少有一行,或者直到给定选择器内no results文本的no results为止。

Waiting for the network response 等待网络响应

I recommend to not wait until there is no more network traffic, as your script might still need a few milliseconds to populate the table with data after downloading the data. 我建议不要等到不再有网络流量时,因为下载数据后,脚本可能仍需要几毫秒的时间才能用数据填充表。 In case, you still want to give it a try I recommend to specify which response to wait for before continuing: 万一您仍然想尝试一下,我建议您指定继续之前要等待的响应:

await page.waitForResponse(response => response.url().includes('/url-to-wait-for'));

Using page.waitForResponse , the code waits until the response of a specific URL is received. 使用page.waitForResponse ,代码将等待直到收到特定URL的响应。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM