Puppteer 是 Google 推出的自动化工具,包含 Chromium 用于模拟用户侧操作,本文介绍如何 配合 Mocha 和 Chai 使用 Puppteer 开展自动化测试 资源链接 Puppteer Github 页面 Puppteer API 定义 Puppteer API 定义(中文版) 简介 Puppeteer 是 Chrome Developer Protocol 的上层封装。 将底层复杂的 CDP 协议封装为 Javascript 的 API,所以能实现代码模拟 chrome 操作。 对应用户操作 用 Puppteer 可以模拟用户侧的操作,内置的模型和用户操作 Chrome 的大致对应关系如下: 浏览器动作 实例化对象 打开 Chrome 浏览器窗口 browser 实例 浏览器 Tab page 实例 如果使用 async/await 语法编写 Puppeteer 脚本,会大大简化代码,而且更为接近用户的行为,因为我们总是眼睛看到某个事件发生后,再驱动手去做下一个动作。 比如,用户眼睛看到浏览器窗口出现后,手找到地址栏,填入想要浏览的网址。用代码描述这个过程,大致是这样的: page = await browser.newPage() await page.goto(url) 配合 Mocha 和 Chai Mocha 用来组织测试用例,Chai 用来实现断言 新建一个 package.json 如下 { "name": "behavior_test", "version": "1.0.0", "description": "behavior test with puppeteer and mocha", "scripts": { "test": "mocha" }, "dependencies": { "puppeteer": "1.13.0", "chai": "*", "mocha": "^6.0.2" } } 执行 npm install 后,将 node_modules/.bin 的绝对路径 加入 Path 变量,方便全局执行 mocha,比如 PATH=/path/to/your/puppeteer/project/node_modules/.bin:$PATH 其中的路径仅仅是举例子,具体到每个机器是不一样的 第一个测试代码 在项目目录里新建一个 test 目录,然后在目录下新建 first.js,内容如下: /** * @name first.js * @desc 第一个 Puppeteer 脚本 */ const puppeteer = require('puppeteer') const expect = require('chai').expect let browser, page const url = 'https://www.baidu.com' const width = 1600 const height = 900 const browserOption = { headless: false, ignoreHTTPSErrors: true, slowMo: 100, args: [ `--window-size=${width},${height}` ] } const viewport = { width: width, height: height } describe('百度页面测试', function() { before(async function () { this.timeout(5000); browser = await puppeteer.launch(browserOption) page = await browser.newPage() await page.setViewport(viewport) }) it('打开百度首页', async function () { await page.goto(url) logo = await page.waitForSelector('#lg') expect(logo).to.exist }).timeout(5000) it('搜索关键字', async function () { input = await page.waitForSelector('#kw') await input.type('puppeteer') btn = await page.waitForSelector('#su') await Promise.all([ btn.click(), page.waitForNavigation() ]) container = await page.waitForSelector('#container') expect(container).to.exist }).timeout(10000) after(async function() { await browser.close() }) }) 执行 mocha 后,应该能看到弹出 Chromium 窗口弹出,执行完后自动关闭,同时命令行里打出以下内容: 代码解读 上面代码的逐行解读如下: describe('百度页面测试', function() { describe 是测试集,第一个参数,是测试集的名称,将显示在命令行里。 before(async function () { before 和 after 是 mocha 的一种钩子函数,当某些关键时间点触发执行 async 关键字用来声明该函数使用 async/await 的语法,对这对关键字的理解可以看下一篇 《Promise 概念的理解》 this.timeout(5000); 指定 before 函数的超时时间为5秒钟。由于启动 Chromium 所需时间往往大于默认的2秒钟,如果不指定超时,会导致错误。 browser = await puppeteer.launch(browserOption) 初始化 browser 实例,传递一些参数都是为了方便调试,具体如下: headless: false 关闭 headless 模式,打开 Chrome 实体窗口,方便观察整个过程 ignoreHTTPSErrors: true 忽略 https 的报错,避免进入 chrome 的警告页面 slowMo: 100 所有动作之间增加 100ms 的暂停间隔,自动化过程是很快的,增加间隔方便观察 args: [—window-size=${width},${height}] 规定实体窗口的大小和视口大小一致,默认的窗口只有800x600,比实际可用的视口小 更为详细的参数配置,见这篇文章 《Puppteer 配置浏览器属性》 (Chromium Logo) 当 puppeteer.launch() 成功实例化后,将对象赋予 browser 变量 page = await browser.newPage() newPage() 用来生成 page 实例,相当于 Chrome 浏览器中的 一个个 tab await page.setViewport(viewport) setViewport() 设置页面视口 it('打开百度首页', async function () { it() 相当于一个测试用例,第一个参数用来描述用例的期望值,运行测试时会出现在命令行里;第二个参数是一个 async 函数 await page.goto(url) goto() 将页面导航至指定的地址,页面加载完后,接着执行下一步 logo = await page.waitForSelector('#lg') waitForSelector() 寻找 id 为 ’lg’ 的元素,如果找到后,赋值给 logo expect(logo).to.exist chai 模块的 expect 函数,断言 logo 元素存在 }).timeout(5000) timeout() 指定该测试用例的超时时间,需要根据网速和网页大小调整 第二个 it() 里的函数都能望文生义,不需要太多解释,这一段需要特别解释: await Promise.all([ btn.click(), page.waitForNavigation() ]) 这段代码的场景是处理点击触发页面跳转的通常写法。将点击事件和页面跳转包裹在一起,只有两件事情都完成后,整个Promise 才算完成。接下来的动作(比如寻找元素)都是在新页面里完成。 Promise 概念的理解可以看下一篇 Promise 概念的理解