gpt4 book ai didi

node.js - 为什么当我使用 "waitForSelector"时 Puppeeteer 导致我的测试套件挂起 30 秒,即使我在页面和浏览器上调用 "close"?

转载 作者:行者123 更新时间:2023-12-05 08:03:00 26 4
gpt4 key购买 nike

我有一个 Node.js Mocha 测试套件(我根据我试图为其创建自动化测试的真实应用程序创建了一个最小复制)。

package.json:

{
"name": "puppeteer-mocha-hang-repro",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"chai": "4.3.7",
"express": "4.18.2",
"mocha": "10.2.0",
"puppeteer": "19.6.2"
}
}

index.spec.js:

const expect = require('chai').expect;
const express = require('express');
const puppeteer = require('puppeteer');

const webServerPort = 3001;

describe('test suite', function () {
this.timeout(10000);

let webServer;
let browser;

beforeEach(async () => {
// Start web server using Express
const app = express();
app.get('/', (_, res) => {
res.send('<html>Hello, World from the <span id="source">Express web server</span>!</html>');
});
webServer = app.listen(webServerPort, () => {
console.log(`Web server listening on port ${webServerPort}.`);
});

// Start browser using Puppeteer
browser = await puppeteer.launch();
console.log('Browser launched.');
});

afterEach(async () => {
// Stop browser
await browser.close();
console.log('Browser closed.');

// Stop web server
await webServer.close();
console.log('Web server closed.');
});

it('should work', async () => {
const page = await browser.newPage();

await page.goto(`http://localhost:${webServerPort}/`);
console.log('Went to root page of web server via Puppeteer.');

if (process.env['PARSE_PAGE'] === 'true') {
const sel = await page.waitForSelector('#source');
const text = await sel.evaluate(el => el.textContent);
console.log('According to Puppeteer, the text content of the #source element on the page is:', text);
expect(text).eql('Express web server');
}

await page.close();
console.log('Page closed.');
});
});

如果我使用命令 npx mocha index.spec.js 运行测试套件,这会导致跳过第 45-48 行,测试套件通过并且 Mocha 进程快速结束:

$ time npx mocha index.spec.js  test suiteWeb server listening on port 3001.Browser launched.Went to root page of web server via Puppeteer.Page closed.    ✔ should work (70ms)Browser closed.Web server closed.  1 passing (231ms)real    0m0.679suser    0m0.476ssys     0m0.159s

请注意,它在 0.679 秒内完成。

如果我改为使用命令 PARSE_PAGE=true npx mocha index.spec.js 运行它,这不会导致我的任何代码被跳过,测试会很快通过,但进程会挂起大约 30秒数:

$ time PARSE_PAGE=true npx mocha index.spec.js  test suiteWeb server listening on port 3001.Browser launched.Went to root page of web server via Puppeteer.According to Puppeteer, the text content of the #source element on the page is: Express web serverPage closed.    ✔ should work (79ms)Browser closed.Web server closed.  1 passing (236ms)real    0m30.631suser    0m0.582ssys     0m0.164s

请注意,它在 30.631 秒内完成。

我怀疑这意味着我让事情保持打开状态,忘记调用像 close 这样的函数。但是,我在 Express Web 服务器、Puppeteer 浏览器和 Puppeteer 页面上调用 close。当我不跳过任何代码时,我尝试对我使用的对象调用 close,它们是 seltext。但如果我尝试这样做,我会收到错误消息,告诉我这些对象没有这样的功能。

系统详情:

$ node --versionv18.13.0$ npm --version9.4.0$ lsb_release -aNo LSB modules are available.Distributor ID: UbuntuDescription:    Ubuntu 22.04.1 LTSRelease:        22.04Codename:       jammy$ uname -r5.10.16.3-microsoft-standard-WSL

最佳答案

更新:此行为是由 #9612 修复的回归并部署为 19.6.3 .要解决此问题,请升级到 19.6.3(如果您出于某种原因使用较旧的 Puppeteer,则降级到 <= 19.6.0)。

请参阅下面的原始答案。


即使没有 Mocha,我也能够重现挂起。这似乎是 Puppeteer 版本 19.6.1 和 19.6.2 中的错误。这是一个最小的例子:

const puppeteer = require("puppeteer"); // 19.6.1 or 19.6.2

const html = `<!DOCTYPE html><html><body><p>hi</p></body></html>`;

let browser;
(async () => {
browser = await puppeteer.launch();
const [page] = await browser.pages();
await page.setContent(html);
const el = await page.waitForSelector("p");
console.log(await el.evaluate(el => el.textContent));
})()
.catch(err => console.error(err))
.finally(async () => {
await browser?.close();
console.log("browser closed");
});

罪魁祸首是 page.waitForSelector,它似乎在解析后仍运行其完整的 30 秒默认超时,以某种方式阻止进程退出。我打开了issue #9610在 Puppeteer 的 GitHub 存储库上。

可能的解决方法:

  • 降级到 19.6.0。
  • 避免使用 waitForSelector,因为您需要的数据位于静态 HTML 中(尽管可能不适用于您的实际页面)。
  • 调用 page.waitForSelector("#source", {timeout: 0}) 这似乎解决了问题,如果在脚本中使用则有永远停止的风险(不是问题mocha,因为测试会超时)。
  • 调用 page.waitForSelector("#source", {timeout: 1000}) 可以减少延迟的影响,如果元素花费的时间超过一秒则有误报的风险载入。这似乎没有叠加,所以如果你在许多测试中使用 1-3 秒的延迟,mocha 应该在所有测试完成后的几秒钟内退出,而不是所有 waitForSelector 的所有延迟的总和电话。不过,这在大多数脚本中并不实用。
  • 运行 npx mocha --exit index.spec.js。不推荐——这会抑制问题。

我不确定该行为是否特定于 waitForTimeout,或者它是否适用于其他 waitFor 系列方法。

顺便说一句,您的服务器监听和关闭调用在技术上是竞争条件,因此:

await new Promise(resolve =>
webServer = app.listen(webServerPort, () => {
console.log(`Web server listening on port ${webServerPort}.`);
resolve();
})
);

await new Promise(resolve => webServer.close(() => resolve()));

系统详情:

$ node --version
v18.7.0
$ npm --version
9.3.0
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Codename: jammy
$ uname -r
5.15.0-56-generic

我还确认了 Windows 10 上的行为。

关于node.js - 为什么当我使用 "waitForSelector"时 Puppeeteer 导致我的测试套件挂起 30 秒,即使我在页面和浏览器上调用 "close"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75292123/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com