使用 HeadlessChrome 来测试 WebRTC 应用

javascript/jquery

浏览数:202

2019-3-7

最近正在做 WebRTC 相关的开发,在配置 ci 测试时发现传统的测试方案都不太合适。WebRTC 的很多 API 是 jsdom 无法模拟的,于是想到了 headlessChrome 这个方案。这里主要记录下配置 headlessChrome 自动化测试的步骤和一些踩到的坑。

GoogleChrome/puppeteer

这是一款 google 开源的 headlessChrome nodejs API 。通过这个库让我们有能力使用 NodeJS 来操作 headlessChrome。

PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 npm install puppeteer --save-dev

puppeteer 默认会下载最新的 chromium 来运行 headlessChrome。但是因为下载速度蛋疼,所以最终我们使用系统已经安装的 Chrome 来运行 headlessChrome。我们通过 PUPPETEER_SKIP_CHROMIUM_DOWNLOAD 这个环境变量让它跳过下载 chromium 这个过程。

beforeAll(async () => {
  browser = await puppeteer.launch({
    headless: isCI,
    args: [
      `--use-fake-device-for-media-stream`,
      `--use-fake-ui-for-media-stream`,
      `--no-sandbox`,
    ],
    slowMo: 80,
    executablePath: !isCI ? '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' : '/usr/bin/google-chrome',
  });

  page = await browser.newPage();
});

这里我们选择使用 Jest 来作为测试框架,指定测试开始之前启动 headlessChrome 并且打开一个页面。这里 isCI 是判断是否处于 travis 环境,如果是就不启动 chrome 的图形界面,使用纯 headless 来运行。

需要注意的是 args 和 executablePath 这 2 个参数。

这里 args 分别是 使用模拟的采集设备、默认开启采集设备权限、关闭沙盒模式。前 2 者是测试 WebRTC 必需的参数,因为在测试过程中我们没法给 chrome 真正的摄像头去测试,关闭沙盒模式是因为 chrome 的安全设定会导致在 travis 环境下没法正常启动。

关于 executablePath 是因为我们默认跳过了 chromium 下载,所以这里我们需要手动指定 chrome 的运行路径。这里就是判定是否是 ci 环境来选择运行 mac 的 chrome 还是 ci 下的chrome。

关于 travisCI 的配置下文会提到,这里先不说明了。

举个栗子:测试一下采集吧

test("getUserMedia", async () => {
    handlePageError(page).then().catch(e => {
      throw e;
    });
    await page.click(Elements.homePage.nextButton);
    await page.waitForFunction(() => {
      const video = document.querySelector("video");
      if (video && video.srcObject && (video.srcObject as any).active) {
        return true;
      }
    }, { timeout: 10000 });
    await page.waitForSelector(Elements.roomPage.muteAudioIcon);
    await expect(page.$(Elements.roomPage.muteAudioIcon)).resolves.not.toBeNull();
    await expect(page.$(Elements.roomPage.muteVideoIcon)).resolves.not.toBeNull();
  });

这里 headlePageError 是自定义的一个工具函数,监听 page 的 onpageerror 事件,也就是页面的 console 报错。也就是说在测试过程中只要 console 出现未处理的错误都会判定为失败。

这里主要介绍的是 page.waitForFunction 这个函数。它的功能是在浏览器的 console 中运行一个你传入的函数,如果函数返回真值就会 resolve,否则就会按照你设定的运行频率不断尝试。(默认的运行频率为 requestAnimationFrame )。

我们通过这个功能检测我们的 video 标签在 10s 之内有没有活跃的流输入来判端我们的采集是否成功。

其他的一些语句主要是针对特定页面的一些 ui 和逻辑检测。

TravisCI 配置

好了,折腾完测试最终还是希望 travis 帮我们在每次 pr 和 push 的时候自动化测试一次。这里简单给出 travis 的 headlessChrome 的配置。

sudo: required
dist: trusty
os: linux
addons:
  chrome: stable
language: node_js
node_js:
  - "8"
before_install:
  - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.5.1
  - export PATH="$HOME/.yarn/bin:$PATH"
  -  PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 yarn install && npm run build
  - npm install http-server -g && cd ./dist && http-server -p 6120 &
  - sleep 3

script: yarn test
cache:
  yarn: true

通过指定 addons 让 travis 在测试的时候安装最新的 chrome (当然也可以指定多个版本)。最终 chrome 的运行路径在 /usr/bin 下。然后在 before_install 时安装依赖,打包并在后台起一个 http-server 好让我们的 chrome 去访问。

基本需要注意的就是这些点了,之后的工作就是补充各种测试情况了。

贴个效果。

https://www.zhihu.com/video/967353133848117248