【问题标题】:Jest test routinely fails because Puppeteer can't click on element in the DOMJest 测试经常失败,因为 Puppeteer 无法点击 DOM 中的元素
【发布时间】:2019-12-17 17:17:18
【问题描述】:

问题总结:我正在编写几个测试套件(使用 Jest 和 Puppeteer)来自动化我的 AngularJS 应用主页的测试。我想自动化的测试之一是填写一个包含多个md-select 字段的表单,我在自动选择特定md-option 时遇到了一些麻烦。由于某些莫名其妙的原因,似乎 Puppeteer 在单击 md-select 打开选项对话框后找不到该选项。这是我的 html 的样子,因此您可以了解我正在处理的内容:

免责声明:为了向这个社区提供minimal, reproducible example,我选择不复制和粘贴我的原始代码,而是写了一个更简单的示例。因此,如果您发现拼写错误,我可以向您保证,这不是我的问题的根源,因为我已经非常仔细地检查了我的原始代码是否存在拼写错误。对于以下代码中的任何拼写错误,我深表歉意。我很警惕,但我是人,所以我会犯错误。

<!-- index.html -->
<html>
  <body ng-app="myApp" ng-controller="myCtrl">
    <form name="myForm">
      <md-dialog-content>
        <md-input-container id="animalSelect">
          <md-select>"Kittens"</md-select>
        </md-input-container>
        <md-input-container id="nameSelect">
          <md-select>"Cosmo"</md-select>
        </md-input-container>
      </md-dialog-content>
    </form>
    <!-- this dialog appears when first <md-select> is clicked -->
    <div class="md-select-menu-container">
      <md-select-menu>
        <md-content>
          <md-option value="Kittens">Kittens</md-option>
          <md-option value="Puppies">Puppies</md-option>
        </md-content>
      </md-select-menu>
    </div>
    <!-- this dialog appears when second <md-select> is clicked -->
    <div class="md-select-menu-container">
      <md-select-menu>
        <md-content>
          <md-option value="Cosmo">Cosmo</md-option>
          <md-option value="Scout">Scout</md-option>
        </md-content>
      </md-select-menu>
    </div>
  </body>
</html>

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

我的破代码:

// index.spec.js
test('submit form', async() => {

    let formSelector = 'form[name="myForm"]';
    let animalSelector = '#animalSelect md-select';
    let animalOptionSelector = 'md-option[value="Puppies"]';

    let nameSelector = '#nameSelect md-select';
    let nameOptionSelector = 'md-option[value="Scout"]';

    await page.waitForSelector(formSelector, {timeout: 3000}); 
    await page.waitForSelector(animalSelector, {timeout: 3000}); 
    await page.waitForSelector(nameSelector, {timeout: 3000}); 

    // this works fine
    await page.click(animalSelector);
    await page.waitForSelector(animalOptionSelector, {timeout: 3000}); 
    await page.click(animalOptionSelector);

    // this fails: Jest says nameOptionSelector is not in the DOM (see error below)
    await page.click(nameSelector);
    await page.waitForSelector(nameOptionSelector, {timeout: 3000}); 
    await page.click(nameOptionSelector);
}); 

我的测试结果:

运行上述测试后,Jest 说 'submit form' 失败并提供以下错误消息:

Node is either not visible or not an HTMLElement

await page.click(nameOptionSelector);
           ^

这意味着当 Puppeteer 去点击 nameOptionSelector 时,它在 DOM 中找不到它。但是page.waitForSelector(nameOptionSelector, {timeout: 3000}) 似乎成功了,这告诉我nameOptionSelector 在调用page.click 时在DOM 中。

故障排除尝试:

'submit form' 通过的唯一方法是在page.click(nameOptionSelector) 上方添加这一行:

// this line tells the test to pause for 1 second before clicking
await page.waitFor(1000);

...但这是一个糟糕的解决方案,因为它不精确并且不能解决问题的根源。

我还阅读了 Puppeteer 的 page.select 方法,但在我的情况下这不起作用,因为我没有使用原生 HTML &lt;select&gt; 元素。

问题:你们中的任何 Jest/Puppeteer 黑客知道解决这个问题的方法吗?

【问题讨论】:

    标签: javascript angularjs jestjs puppeteer


    【解决方案1】:

    不幸的是,我也遇到了与您类似的问题,await page.waitFor(3000) 在我的情况下主要帮助了我。这是我用来继续向下滚动直到到达不断附加动态内容的页面底部的一段代码:

        let preCount = 0;
        let postCount = 0;
        do {
          preCount = await getCount(page);
          await scrollDown(page);
          await page.waitFor(3000);
          postCount = await getCount(page);
        } while (postCount > preCount);
        await page.waitFor(3000);
    
    

    当我尝试将等待时间从 3 秒降低到 1 或 2 秒时,有时我无法到达页面底部。我知道这一点是因为我在启动 puppeteer 时禁用了无头模式,所以我可以看到浏览器中发生了什么:

    {
      headless: false,
      defaultViewport: null,
      args: ['--window-size=800,600']
    }
    
    

    【讨论】:

      【解决方案2】:

      考虑到它的角度应用程序,我假设有一些 style disappear propertystyle="display: none" 由角度指令处理(我不熟悉角度,所以我可能错了)

      在这种情况下,您的单击触发事件会改变按钮的状态 -> 使其出现/消失(这需要一些时间,这就是 page.waitFor 函数似乎可以解决问题的原因)。

      page.waitForSlector(nameOptionSelector) 立即解析,因为选择器已经存在(您可以通过在控制台中运行 document.querySelector('md-option[value="Scout"]') 来检查它是否为真,然后单击 md-select 和之后。在这两种情况下,您都应该获得文档元素)

      但是page.click() 在尝试单击不可见的元素时会失败。因此,您可以尝试等待其他将正确设置角度属性的选择器。可能是说明元素是否可见的那个。

      顺便说一句,如果您的整个应用程序是用 Angular 编写的,请考虑使用其他框架进行测试 -> 例如。 protractor 因为它专用于 Angular 应用程序

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-04
        • 2019-11-28
        相关资源
        最近更新 更多