Jest Puppeteer钩子超时问题:jest.setTimeout的正确使用位置
Jest Puppeteer测试超时及代码问题排查
问题描述
我是Jest Puppeteer新手,运行他人编写的测试套件时所有测试均失败,报错指向beforeEach钩子:
thrown: "Exceeded timeout of 5000 ms for a hook. Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
询问jest.setTimeout的正确放置方式,以及代码中是否存在其他配置错误或遗漏点。附上的测试代码如下:
const baseURL = "http://localhost:1234"; const puppeteer = require('puppeteer'); beforeEach(() => { // Reset mock function's states before each test. jest.clearAllMocks(); }); describe("chatbot", () => { beforeEach(async () => { const browser = await puppeteer.launch({headless: false, slowMo: 250,}); const page = await browser.newPage(); await page.goto(baseURL, { waitUntil: "load" }); // set the fade-ins to 0 ms to prevent timeouts in tests await page.evaluate(() => { window.animationDelay = 0 }) await page.click("#chat-circle"); await browser.close() }); it("should show contact info when the user enters 'contact'", async () => { // submit the form with a message, expect to see the response const message = "contact"; await page.evaluate(() => { // get this same const in the page's context const message = "contact"; $("#chat-input").val(message) }); await page.click("#chat-submit"); await expect(page).toMatch("We have 24 hour phone support. Our phone number is +01 312 555 8432. We look forward to hearing from you!"); }); it("should show credit card help message when the user enters 'credit card'", async () => { // submit the form with a message, expect to see the response const message = "credit card"; await page.evaluate(() => { // get this same const in the page's context const message = "credit card"; $("#chat-input").val(message) }); await page.click("#chat-submit"); await expect(page).toMatch("You can pay with any major credit card. Enter your card details and billing address at checkout."); }); it("should show payment help message when the user enters 'payment'", async () => { // submit the form with a message, expect to see the response const message = "payment"; await page.evaluate(() => { // get this same const in the page's context const message = "payment"; $("#chat-input").val(message) }); await page.click("#chat-submit"); await expect(page).toMatch("We have three payment options: credit card, paypal, or apple pay. Choose your preferred method at checkout."); }); it("should show help options when the users enters 'help'", async () => { // submit the form with a message, expect to see the response const message = "help"; await page.evaluate(() => { // get this same const in the page's context const message = "help"; $("#chat-input").val(message) }); await page.click("#chat-submit"); await expect(page).toMatch("Enter a keyword for help with a topic: contact, payment, credit card, destinations."); }); });
解决方案
一、解决beforeEach超时:正确放置jest.setTimeout
有三种可行方式,根据需求选择:
- 作用于整个describe块:放在describe内部最上方,对块内所有钩子和测试用例生效
describe("chatbot", () => { jest.setTimeout(15000); // 设为15秒,可根据实际加载速度调整 beforeEach(async () => { // ... 钩子代码 }); // ... 测试用例 });
- 作用于单个beforeEach钩子:直接在钩子内部设置
beforeEach(async () => { jest.setTimeout(15000); // ... 钩子代码 });
- 全局配置:在项目根目录的
jest.config.js中添加全局超时设置,对所有测试生效
module.exports = { testTimeout: 15000, // 其他Jest配置 };
二、代码中的其他致命错误修复
除了超时,原代码存在几个严重逻辑错误,是导致测试失败的核心原因:
- 提前关闭浏览器
原beforeEach最后执行了await browser.close(),但测试用例还需要操作页面,这会直接导致所有测试因浏览器已关闭而失败。正确做法是将浏览器和page实例提升到describe作用域,在afterEach钩子中关闭浏览器:
describe("chatbot", () => { let browser; let page; beforeEach(async () => { jest.setTimeout(15000); browser = await puppeteer.launch({headless: false, slowMo: 250,}); page = await browser.newPage(); await page.goto(baseURL, { waitUntil: "load" }); await page.evaluate(() => { window.animationDelay = 0 }) await page.click("#chat-circle"); // 移除此处的browser.close() }); // 每个测试完成后关闭浏览器 afterEach(async () => { await browser.close(); }); // ... 测试用例 });
测试用例中page变量未定义
原代码的page是beforeEach内部的局部变量,测试用例无法访问,必须将其提升到describe作用域(如上代码所示),否则测试用例中的page.evaluate、page.click等操作都会报错。page.evaluate的变量传递优化
原代码在page.evaluate内部重复定义message变量,可直接将外部变量传入,更简洁且避免冗余:
await page.evaluate((msg) => { $("#chat-input").val(msg); }, message); // 将外部的message作为参数传入
- 断言前等待内容渲染
await expect(page).toMatch(...)可能因页面内容未及时渲染而失败,建议配合page.waitForFunction等待目标文本出现后再断言:
await page.click("#chat-submit"); // 等待目标文本出现在页面中 await page.waitForFunction((text) => document.body.textContent.includes(text), {}, "We have 24 hour phone support..."); await expect(page).toMatch("We have 24 hour phone support. Our phone number is +01 312 555 8432. We look forward to hearing from you!");
内容的提问来源于stack exchange,提问作者Jessi
相关产品推荐
相关产品推荐

