王士江的博客,学习认真活着。

我的视界,我的世界

My Word, My World

使用Puppeteer进行用户界面测试

Puppeteer是由Google Chrome 官方团队进行维护的一个Node库,提供了一组高级API, 通过DevTools协议控制无界面Chrome (headless chrome, 也就是无UI界面的chrome)。

简而言之,Puppeteer可以让用户界面测试变得很轻松。

什么是Puppeteer?

Puppeteer是一个用户界面自动化工具。 它组合了”Chrome无界面模式”和”DevTools协议”,通过提供一个更上层的API,让用户界面测试自动化变得轻而易举。

无界面Chrome是没有UI界面的Chrome。 它允许你从浏览器之外的环境(即命令行)与Chromium进行交互。

示例代码

我们通过一个示例,来探讨Puppeteer的使用方法:使用Puppeteer来访问百度源代码仓库地址请点击这里

示例代码的安装、执行

在安装依赖、执行示例代码之前,请先安装最新版的Node.js

# 建议使用cnpm进行安装,puppeteer需要下载Chromium (~170Mb Mac, ~282Mb Linux, ~280Mb Win)
sudo npm install -g cnpm

cnpm install

# 执行
npm start
# or npm run test

执行结果——无头

无头浏览执行结果

执行结果——有头

无头浏览执行结果

代码说明

/**
 * 下面是使用 puppeteer 的一个例子
 */
const puppeteer = require('puppeteer');

(async() => {
    // 1、打开 浏览器
    const browser = await puppeteer.launch({headless: true});
    // 2、打开 新页面
    const page = await browser.newPage();
    // 3、网址跳转到 百度
    await page.goto('https://www.baidu.com');
    // 4、在 百度的搜索框 输入 Puppeteer
    await page.type('#kw', 'Puppeteer', {delay: 50});
    // 5、点击 "百度一下" 按钮
    await page.click('#su');

    // 6、等待 1秒钟,等待百度传输结果
    await page.waitFor(1000);

    // 7、抽取所有结果的"标题"和"链接"
    const links = await page.evaluate(() => {
        const anchors = Array.from(document.querySelectorAll('.c-container h3.t a'));
        return anchors.map(anchor => anchor.textContent);
    });

    // 8、期待有结果
    console.log(links.join('\n'));

    // 9、关闭浏览器
    await browser.close();
})();

我们首先加载puppeteer模块——requireNode.js中用于加载模块的关键字。

然后我们将加载好的puppeteer模块放到名称为puppeteer的常量中—— constES6中用于定义常量的关键字

关于ES6,阮一峰写了一本免费、开源的电子书,点击这里查看

/**
 * 下面是使用 puppeteer 的一个例子
 */
const puppeteer = require('puppeteer');

接下来是一个匿名的立即执行函数(IIFE,Immediately Invoked Function Expression),里面是我们需要执行的测试代码, asyncES7中用于异步操作的关键字,表示内部是异步操作,返回一个异步操作的结果。

关于asyncawait的更详细的内容,参见阮一峰的开源电子书《ECMAScript 6 入门》 (电子书地址:http://es6.ruanyifeng.com/

(async() => {

})();

1、打开 浏览器

// 1、打开 浏览器
const browser = await puppeteer.launch();

我们通过puppeteer模块提供的launch方法,打开一个浏览器。

在打开浏览器的同时,我们可以提供一些配置项,比如不使用无头浏览器(headless设置为false)。

awaitES7中用于异步操作的关键字,表示等待异步操作结束、得到返回的结果,await只能用在异步函数async function中。

打开浏览器Puppeteer来说是一个异步操作(返回值是Promise), Puppeteer的其他API也是类似处理。

我们为了模拟人的输入方式、或者为了查看方便,我们还可以设置slowMotrue,这样浏览器会模拟人的输入方式、缓慢地进行输入。

// 1、打开 浏览器
const browser = await puppeteer.launch({headless: true, slowMo: true});

2、打开 新页面

// 2、打开 新页面
const page = await browser.newPage();

3、网址跳转到 百度

// 3、网址跳转到 百度
await page.goto('https://www.baidu.com');

4、在 百度的搜索框 输入 Puppeteer

// 4、在 百度的搜索框 输入 Puppeteer
await page.type('#kw', 'Puppeteer', {delay: 50});

百度的关键字”输入框”,是一个id属性为kw的’Input’,我们要在里面输入Puppeteer字符串, 为了模拟人类的输入效果,各个字符之间、我们加了50毫秒的延迟。

<!-- 百度的搜索框,是一个`id`属性为`kw`的'Input' -->
<input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off">

5、点击 “百度一下” 按钮

// 5、点击 "百度一下" 按钮
await page.click('#su');

百度的”百度一下”按钮,是一个id属性为su的’Submit Button’。

<!-- 百度的"百度一下"按钮,是一个`id`属性为`su`的'Submit Button'。 -->
<input type="submit" id="su" value="百度一下" class="bg s_btn">

6、等待 1秒钟,等待百度传输结果

// 6、等待 1秒钟,等待百度传输结果
await page.waitFor(1000);

由于”根据关键字进行查询”需要花一段时间,所以我们等1秒(1s,也就是1000毫秒,1000 ms)。

7、抽取所有结果的”标题”和”链接”

// 7、抽取所有结果的"标题"和"链接"
const links = await page.evaluate(() => {
    const anchors = Array.from(document.querySelectorAll('.c-container h3.t a'));
    return anchors.map(anchor => anchor.textContent);
});

百度的搜索结果,是放在样式类为c-containerDiv中,我们想要的是结果是——结果的标题—— 这样我们只需要找到样式类为th3标签、然后找到里面的a标签,取它的文本内容。

百度搜索结果截图

8、期待有结果

// 8、期待有结果
console.log(links.join('\n'));

9、关闭浏览器

// 9、关闭浏览器
await browser.close();

更多Puppeteer的API,请访问Puppeteer官方API地址

API 结构