23、自动化测试:使用 Puppeteer 编写 WebRTC 自动化测试脚本,模拟多用户连接

说实话,WebRTC 的调试和测试,一直是很多开发者的痛点。

我自己带团队做实时音视频项目时,最头疼的就是「多人同时连麦」的场景。手动开十几个浏览器窗口?太累了。而且每次测试结果还不一致,你根本分不清是代码 bug 还是操作失误。

所以,自动化测试必须上。今天我们就聊聊怎么用 Puppeteer 来搞定这件事。

为什么选 Puppeteer?

Puppeteer 是 Google 官方维护的 Node.js 库,可以控制 Chrome 或 Chromium 浏览器。说白了,它能帮你「假装」是一个真实用户,打开页面、点击按钮、获取视频流。

对于 WebRTC 来说,Puppeteer 有几个天然优势:

  • 原生支持 WebRTC:Chrome 内核本身就集成了 WebRTC,不需要额外安装插件。
  • 可以模拟多页面:一个 Puppeteer 实例可以打开多个页面,每个页面就是一个「虚拟用户」。
  • 能获取统计信息:通过 getStats() API,我们可以拿到实时的网络质量数据。
我的经验: 早期我试过用 Selenium 做 WebRTC 测试,但 Selenium 对 WebRTC 的支持不够好,尤其是获取媒体流的时候经常报错。换成 Puppeteer 后,问题少了很多。

核心思路:模拟多用户连接

我们模拟的场景是这样的:

  1. 启动一个信令服务器(比如用 Socket.IO 搭建的)。
  2. 用 Puppeteer 打开多个浏览器页面,每个页面都连接到同一个房间。
  3. 每个页面创建本地媒体流(可以用假视频流,避免依赖摄像头)。
  4. 触发信令交换,建立 PeerConnection。
  5. 验证连接是否成功,以及媒体流是否正常传输。

嗯,这里有个关键点:假视频流。你想想看,如果每次测试都要摄像头,那自动化就没法在服务器上跑了。所以我们要用 Chrome 的 --use-fake-device-for-media-stream 参数。

避坑指南: 我曾经在 CI 环境里跑测试,发现视频流一直黑屏。后来排查了半天,才发现是没加 --use-fake-ui-for-media-stream 参数。这个参数可以自动授权媒体权限,否则 Puppeteer 会卡在权限弹窗上。

代码实战:一个简单的多用户测试脚本

下面是一个完整的示例。我会逐步解释每一段的作用。

const puppeteer = require('puppeteer');

async function createUser(browser, roomId, userId) {
  const page = await browser.newPage();
  
  // 注入假媒体流
  await page.goto('http://localhost:3000/room/' + roomId);
  
  // 等待页面加载完成
  await page.waitForSelector('#local-video');
  
  // 模拟用户点击「加入房间」
  await page.click('#join-btn');
  
  // 等待远程视频出现
  await page.waitForSelector('#remote-video', { timeout: 10000 });
  
  console.log(`用户 ${userId} 已加入房间`);
  return page;
}

async function runTest() {
  const browser = await puppeteer.launch({
    headless: true,
    args: [
      '--use-fake-device-for-media-stream',
      '--use-fake-ui-for-media-stream',
      '--no-sandbox'
    ]
  });
  
  const roomId = 'test-room-001';
  
  // 创建 3 个虚拟用户
  const user1 = await createUser(browser, roomId, 'Alice');
  const user2 = await createUser(browser, roomId, 'Bob');
  const user3 = await createUser(browser, roomId, 'Charlie');
  
  // 等待几秒,让连接稳定
  await new Promise(resolve => setTimeout(resolve, 5000));
  
  // 检查每个用户的连接状态
  const stats1 = await user1.evaluate(() => {
    const pc = window.localPeerConnection;
    return pc.getStats().then(stats => {
      let result = {};
      stats.forEach(report => {
        if (report.type === 'candidate-pair' && report.state === 'succeeded') {
          result.connected = true;
          result.rtt = report.currentRoundTripTime;
        }
      });
      return result;
    });
  });
  
  console.log('Alice 的连接状态:', stats1);
  
  await browser.close();
}

runTest();

关键点解析

参数/方法 作用 我的建议
--use-fake-device-for-media-stream 使用假摄像头和假麦克风 必加,否则在无头模式下会报错
--use-fake-ui-for-media-stream 自动授权媒体权限 必加,否则弹窗会卡住脚本
page.evaluate() 在浏览器上下文中执行 JS 用来获取 WebRTC 内部状态
waitForSelector() 等待 DOM 元素出现 比固定延时更可靠

SVG 流程图:多用户连接测试的核心逻辑

Puppeteer 多用户 WebRTC 测试流程 启动 Puppeteer 打开 Chromium 浏览器 创建多个页面 每个页面 = 一个虚拟用户 注入假媒体流 --use-fake-device 信令交换 & 建立连接 Offer / Answer / ICE Candidate 验证连接状态 getStats() 检查 RTT / 丢包率 ⚠️ 注意事项 • 信令服务器需提前启动 • 建议使用固定房间 ID

进阶技巧:处理 ICE 连接状态

在实际项目中,我发现很多自动化测试脚本只检查「视频是否显示」,但忽略了 ICE 连接状态。这其实不够。

我建议你在测试中加入以下检查:

// 检查 ICE 连接状态
const iceState = await page.evaluate(() => {
  const pc = window.localPeerConnection;
  return pc.iceConnectionState;
});

if (iceState !== 'connected' && iceState !== 'completed') {
  console.error(`ICE 连接异常: ${iceState}`);
  // 可以在这里截图保存现场
  await page.screenshot({ path: `ice-error-${userId}.png` });
}
注意: 在无头模式下,page.screenshot() 可能截不到视频流内容(因为 GPU 渲染不同)。如果你需要验证视频画面,建议使用 --headless=new 模式,或者直接检查 getStats() 中的 framesReceived 字段。

模拟网络条件变化

你想想看,真实场景下网络不会一直稳定。所以我们的自动化测试也要能模拟弱网环境。

Puppeteer 可以通过 Chrome DevTools Protocol 来模拟网络限速:

const client = await page.target().createCDPSession();
await client.send('Network.emulateNetworkConditions', {
  offline: false,
  latency: 200,           // 延迟 200ms
  downloadThroughput: 500 * 1024,  // 下载 500kbps
  uploadThroughput: 300 * 1024     // 上传 300kbps
});

我个人习惯在测试脚本中准备几组预设:

  • 正常网络:延迟 10ms,带宽 10Mbps
  • 弱网:延迟 200ms,带宽 500kbps
  • 极差网络:延迟 500ms,带宽 100kbps

然后循环测试,看看 WebRTC 的码率自适应机制是否正常工作。

常见问题与解决方案

问题 原因 解决方法
页面打开后视频黑屏 没有正确注入假媒体流 检查 --use-fake-device-for-media-stream 参数
ICE 连接一直卡在 checking 信令服务器没有正确转发 在 Puppeteer 中打印信令日志
多个用户同时加入时崩溃 浏览器资源不足 限制并发数,或者使用 --disable-gpu
getStats() 返回空 PeerConnection 已关闭 在调用 getStats() 前检查连接状态
我的小技巧: 调试时不要用 headless: true,改成 headless: false 并加上 slowMo: 100,这样你可以亲眼看到浏览器在做什么。等脚本稳定了再切回无头模式。

好了,以上就是用 Puppeteer 做 WebRTC 自动化测试的核心内容。说白了,就是让浏览器替我们干活,而且干得比人更稳定、更可重复。你只要把信令流程和连接检查写清楚,剩下的交给脚本跑就行了。


公众号:蓝海资料掘金营,微信deep3321