如何用Puppeteer模拟浏览器崩溃并触发disconnected事件?
我用Jest和Puppeteer运行大量测试,为避免复用浏览器导致不稳定,每次测试前都会通过puppeteer.launch()创建新的浏览器实例。批量运行所有测试时,浏览器偶尔会在启动后崩溃,我可以通过监听browser.on('disconnected', ...)事件检测到这种情况。
现在我想处理该场景,在需要时重新创建浏览器,但问题是如何强制Chromium浏览器崩溃并触发与真实崩溃相同的disconnected事件?我已尝试加载chrome://kill/这类特殊URL,示例代码如下:
import puppeteer from 'puppeteer'; async function getPage(url) { const browser = await puppeteer.launch({}); const page = await browser.newPage(); browser.on('disconnected', async () => { console.log('@@@@@@@@@@@@ browser crashed @@@@@@@@@@@@@'); }); await page.goto(url, {waitUntil: 'load'}); return page; }; describe('Raw Puppeteer Test', () => { let page; beforeEach(async () => { page = await getPage('chrome://kill/'); }); afterEach(async () => { await page.close(); await page.browser().close(); }); it('should relaunch the browser and re-run if the browser crashes', async () => { const el = await page.waitForSelector('h1'); expect(el).not.toBeNull(); }); });
虽然chrome://kill/和chrome://crash/确实会导致Chromium崩溃,但不会触发真实崩溃时的disconnected事件;尝试chrome://inducebrowsercrashforrealz/则返回net::ERR_INVALID_URL错误。
有没有办法在Puppeteer中模拟浏览器初始化失败或真实崩溃场景,触发对应的disconnected事件?
解决方案
方法1:直接终止浏览器进程
通过browser.process()获取Chromium的进程实例,调用kill()方法强制终止,这会直接触发disconnected事件,和真实崩溃的效果一致:
async function simulateBrowserCrash(browser) { if (browser.process()) { browser.process().kill('SIGKILL'); // 强制终止进程 } } // 在测试中使用示例 beforeEach(async () => { const browser = await puppeteer.launch({}); const page = await browser.newPage(); browser.on('disconnected', () => { console.log('浏览器已崩溃/断开连接'); }); // 触发模拟崩溃 await simulateBrowserCrash(browser); });
方法2:通过Chrome DevTools协议强制崩溃
使用Puppeteer的browser.send()方法发送Chrome DevTools协议的Browser.crash命令,这会让浏览器主动崩溃并触发disconnected事件:
async function simulateBrowserCrash(browser) { await browser.send('Browser.crash'); } // 使用示例 async function getPage() { const browser = await puppeteer.launch({}); const page = await browser.newPage(); browser.on('disconnected', () => { console.log('@@@@@@@@@@@@ browser crashed @@@@@@@@@@@@@'); }); // 触发模拟崩溃 await simulateBrowserCrash(browser); return page; }
方法3:模拟浏览器初始化失败
如果要测试浏览器启动阶段的失败场景,可以修改puppeteer.launch()的参数,让浏览器无法正常启动:
// 指定无效的用户数据目录,导致启动失败 async function simulateLaunchFailure() { try { const browser = await puppeteer.launch({ userDataDir: '/path/that/does/not/exist/and/cannot/be/created', args: ['--no-sandbox'] // 根据运行环境调整参数 }); } catch (error) { console.log('浏览器初始化失败:', error.message); // 此处可加入重试逻辑 } }
内容的提问来源于stack exchange,提问作者antun

