首页 > 解决方案 > Docker 中 Puppeteer/Jest 测试中的竞争条件

问题描述

我使用 jest & puppeteer 编写了一个大型测试,它在我的应用程序中做了很多事情。

当我在本地运行测试时 - 一切都通过了 99% 的时间。

当我在 Docker 中运行测试时 - 测试在多个地方不一致地失败。几乎每次我运行测试时,它通常都会在等待选择器加载时失败。

不幸的是,我不能在这里分享我的代码,但是我可以根据我所做的研究来展示我为减轻失败所做的工作。

  1. waitFor(< x ms>)在导航发生之后或断言之前进行调用
  2. 按照puppeteer 文档中关于点击事件的建议实现Promise.all模式。像这样的东西:
async singleClickElement(selector, page) {
    try {
      await Promise.all([
        page.waitForSelector(selector),
        page.click(selector)
      ]);
    } catch (error) {
      console.error(error)
    }
  }
  1. 乱搞sloMo设置(考虑到我们默认的 css 过渡是 0.4 秒,对我来说,似乎 17 是最成功的数字)

  2. 用于screenshots在测试失败的地方拍摄之前/之后的照片

一些我忘记提及的编辑

  1. 我的参数--forceExit --runInBand --detectOpenHandles

  2. 我的超时时间增加到一分钟jest.setTimeout(60000)

  3. 浏览器参数'--window-size=2560,1080', '--no-sandbox', '--disable-setuid-sandbox', '--enable-logging=stderr', '--v=1'

我已经没有想法了,正在寻找关于在运行 UI 测试时如何缓解 Docker 中的竞争条件的建议。请随时提出您认为可能对我有帮助的任何建议。感谢:D

标签: dockerjestjspuppeteerrace-condition

解决方案


经过几个月的反复试验,我想我已经找到了一些在 Docker 中运行 Jest 和 Puppeteer 的好方法,而且几乎没有失败。

解决方案 #1:加载页面/组件时等待 HTTP 响应

Puppeteer 开箱即用waitForResponse,具有允许浏览器等待某些响应从服务器返回的功能。在 Chrome 开发工具中,查看Network并重新加载您所在的页面并等待响应。

示例:假设我正在加载某个页面,并且我正在等待来自服务器的响应以包含有关一系列品牌的一些信息。当我导航到该页面时,我会打电话

await page.waitForResponse(res => res.url().includes('brands'));

只有在收到此回复后,我才能继续进行测试。我发现这在所有其他方法中都很有效。

注意:每次重新加载页面时,您的响应可能会以不同的时间间隔出现。例如,我的品牌响应快到 300 毫秒,慢到 900 毫秒。尝试查找来自带有数据的服务器的响应或最常出现的最后响应(重新加载 10 次并观看)

chrome 中的服务器响应示例

解决方案#2:在继续之前检查某个元素的属性

假设您的页面将首先加载一个按钮。单击该按钮后,应在 0.5 秒的小过渡后出现另一个按钮。在继续之前,您可以检查按钮的文本内容。

.$eval文档

const saveBtn = await page.$eval('.btn-selector', btn => btn.textContent);
        if (saveBtn.includes('Save')) {
    ...
    }

您还可以检查单击后下拉列表的选定值是否出现在 DOM 中。

.$文档

        const brandsSelector = await page.$('select:nth-child(1)');
        const brandsSelectedValue = await page.evaluate(brandsSelector => brandsSelector.options[brandsSelector.selectedIndex].value, brandsSelector);

解决方案#3:长时间waitFor通话

有时上述两种解决方案是不够的,你克服困难的唯一方法就是打电话给 longwaitFor

await page.waitFor(3000);

我通常会尽量避免这些,但有时这是让我的测试通过并在 Docker 中的分阶段测试服务器上正常工作的唯一方法。

解决方案#4:visible使用时的属性waitForSelector

有时像waitForSelector函数这样简单的事情可能会被忽略,因为它们非常明显,但是这个函数需要一个options你可以传递给它的对象

await page.waitForSelector('.selector', {visible: true});

这会等待页面中的某些元素首先可见,然后再对其进行任何其他操作。

解决方案 #5:检查您的云提供商的负载

例如,如果您使用 AWS,请确保您的实例在某个时间段内具有足够高的请求容量。我的分阶段测试一直崩溃,直到 AWS 负载最大化以每秒处理更多请求,这使得一些间歇性故障得以平息。

解决方案#6:一起使用所有这些解决方案(显然)

祝你好运,在差异环境中进行测试时,端到端测试可能会很痛苦,尤其是分阶段的服务器。


推荐阅读