- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 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
,它们是 sel
和 text
。但如果我尝试这样做,我会收到错误消息,告诉我这些对象没有这样的功能。
系统详情:
$ 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 存储库上。
可能的解决方法:
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/
基于这个 response ,有没有办法(像 casperjs/phantomjs)在 page.evaluate() 上下文中添加我们的自定义函数? 例如,包含一个带有辅助函数 x 的文件以调用 X
我有一个 Node.js Mocha 测试套件(我根据我试图为其创建自动化测试的真实应用程序创建了一个最小复制)。 package.json: { "name": "puppeteer-mocha
我是一名优秀的程序员,十分优秀!