内容简介:本文内容涉及它由Chrome官方团队提供,通过Devtools协议在Node层提供了一系列API来控制chrome或者chromium,也就是说我们能够编写Node环境的代码即可对浏览器的行为进行控制。通过它我们可以做到以下行为:当然以上行为都是puppeteer能力中极小的一部分,更多的读者可以阅读Puppeteer的
本文内容涉及 ES6 async
、 jest
的相关知识,对于以上内容不太了解的读者可以先了解相关内容。
Puppeteer是什么
它由Chrome官方团队提供,通过Devtools协议在Node层提供了一系列API来控制chrome或者chromium,也就是说我们能够编写Node环境的代码即可对浏览器的行为进行控制。通过它我们可以做到以下行为:
-
生成页面快照:图片、pdf
-
抓取spa应用生成预渲染页面
-
自动化表单提交、UI测试、键盘输入
-
抓取应用的性能数据(chrome performance timeline)
-
测试chrome扩展
当然以上行为都是puppeteer能力中极小的一部分,更多的读者可以阅读Puppeteer的 文档 来了解,本文将介绍Puppeteer在E2E测试的实践
E2E测试
简单来说,就是模拟真实用户使用场景进行测试,预期应用能够正常响应用户的操作,其关键点在于模拟用户使用环境,模拟用户操作。
那对于Web应用来说,用户环境就是浏览器,用户操作主要是移动、点击,这些就是我们需要模拟的部分,下面就直接进入环境和实践部分。
环境部分
本文的例子采用 puppeteer
jest
jest-puppeteer
在mac环境实现
首先需要安装以上依赖,这里需要注意以下问题:
-
puppeteer会默认下载chromium,这里可以通过
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
跳过chromium下载 -
Node版本最好使用大于8的版本
接下来说明一下相关的配置
首先是jest相关的配置,在根目录创建 jest.config.js
//jest.config.js const config = require('config'); const _ = require('lodash'); module.exports = { preset: 'jest-puppeteer', //调用preset globals: _.assign({}, config.get('e2e.variable'), { //这里可以注入全局变量 ENV_URL: config.get('baseUrl') }), testMatch: ['**/__e2e__/**/*.test.js?(x)'] //指定需要进行测试的文件 }; 复制代码
接下来就是配置puppeteer,在根目录创建 jest-puppeteer.config.js
//jest-puppeteer.config.js module.exports = { launch: { headless: true, //设定运行模式,false的情况下将会工作在有GUI界面的模式,true则不开启GUI界面 executablePath: //设定本地Chrome路径,官方推荐使用Chrome Canary '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary' } }; 复制代码
实践部分
环境已经配置好了,是时候进入实践环节了。对于绝大部分系统尤其是管理系统来说,第一步要做的肯定是登录系统,因此,我们的第一个实践就是用puppeteer脚本模拟登录,这里的例子基于作者这边的一个系统的登录流程。
const loginFunc = page => async () => { await page.setViewport({ width: 1280, height: 720 }); //设置窗口大小 await page.goto(`${ENV_URL}/login`); //前往登录地址 const loginIframe = page.frames().find(f => f.name() === 'login-iframe'); //找到登录iframe await loginIframe.waitForSelector( '#login-tab-container > div.tab-item.tab-right' ); await loginIframe.click('#login-tab-container > div.tab-item.tab-right'); //切换登录TAB await page.waitFor(1000); //特殊用途,之后说明 const username = await loginIframe.waitForSelector('#username'); //找到输入框 await username.type(USERNAME); //输入用户名 const pass = await loginIframe.waitForSelector('#password'); await pass.type(PASSWORD); //输入密码 await loginIframe.click('#login-btn'); //点击登录按钮 await page.waitForNavigation(); //等待跳转导航完成 }; module.exports = { loginFunc: loginFunc }; 复制代码
在这个例子中,展示了打开登录页面,输入用户名、密码并进行登录的流程,主要涉及到了 setViewport
goto
frames
waitForSelector
click
waitFor
type
waitForNavigation
这些API,下面说说其中几个比较重要的API,更多的可以参考官方文档;
setViewport 设置窗口大小,返回一个promise waitForSelector 参数为CSS Selector,返回一个promise,直到指定的元素出现才会resolve,超时后会reject click 点击某个元素,返回一个promise type 向某个元素输入内容,返回一个promise waitForNavigation URL改变时触发,返回promise,导航结束时resolve,通过history api进行URL更改时也可以通过该方法等待导航结束 frames 可以获取页面中所有的iframe 复制代码
相信读者看完这段例子后也能感受到puppeteer的API设计是十分语意化的,非常好懂。但是实际上这个例子是存在几个踩坑点的,这里说一下笔者从这个例子中收获的经验:
-
waitForSelector只有当目标Selector原本不存在DOM中才会生效,如果目标元素是通过
display: none;
visibility: hidden
这类方式进行切换的话,这个方法是直接resolve的。 -
如果这个切换过程中还存在动画效果,那在这个动画效果的过程中,无论是click还是type动画过程中的元素,操作都是不会生效的,必须等到动画结束,因此在本例子中还增加了
waitFor(1000)
这句代码来等待动画的结束
至此我们已经完成了登录,接下来就可以和jest结合进行自动化测试了,先放出本部分的例子:
const utils = require('./utils'); jest.setTimeout(10000); describe('e2e test', () => { beforeAll(utils.loginFunc(page)); it('e2e test-1', async () => { const el = await page.waitForSelector( '#root > .services_C2FC97 > .ant-row > .ant-col-8:nth-child(1) > .service-card_C2FC97' ); expect(await el.$eval('p', node => node.innerText)).toBe('test'); //获取指定元素的innerText }); }); 复制代码
在这个例子里,我们先引入了上面编写的loginFunc来作为每一个测试的前置条件,由于使用了jest-puppeteer, 运行环境中会自动注入puppeteer的page和browser对象
,因此可以直接调用;这个例子中测试的是首页的一张功能卡片的标题是否为 test
;这个例子是很基础的,不过相信通过上面那个登录的例子,读者已经了解到编写E2E测试脚本的套路了。
不过这里还有一点需要说明, 由于puppeteer启动时间和打开网页的耗时比较难以估计
,需要通过 jest.setTimeout(ms)
来延长一个测试执行的时间,否则有可能因为执行超时导致失败,下面是这个例子最终的执行结果:
yarn e2e yarn run v1.9.4 $ cross-env NODE_ENV=test jest -c jest.config.js Determining test suites to run... DevTools listening on ws://127.0.0.1:54751/devtools/browser/7d8d289a-5335-4ffc-a65c-f7e98cb34de0 [1129/154120.584773:WARNING:spdy_session.cc(3152)] Received HEADERS for invalid stream 25 PASS __e2e__/demo.test.js (6.931s) e2e test ✓ e2e test-1 (1540ms) Test Suites: 1 passed, 1 total Tests: 1 passed, 1 total Snapshots: 0 total Time: 7.046s Ran all test suites. :sparkles: Done in 10.72s. 复制代码
至此,入门教程就结束了,是否感觉到很像按键精灵?但实际上通过puppeteer我们可以实现更强大的一些控制,包括监听网络请求,监听页面创建等等,基本上我们能在浏览器手动做到的,通过它提供的Node API也能够做到,这部分内容欢迎读者去阅读文档进一步的进行探索;
那E2E测试究竟能为我们带来什么呢?在笔者看来,对于一个长期迭代的项目,随着项目规模的扩大,功能的回归测试耗费的时间会不可避免的增加,在这种情况下,如果有自动化测试能够帮我们进行部分测试,将大大提高我们的效率;同时通过定时测试任务可以更早的发现产品功能上存在的问题,从而保证产品能够按时交付,这是它带来的最大的价值。
最后,推荐给大家一个小工具 puppeteer-recorder
,这是一个Chrome插件,可以方便的录制测试脚本,从而摆脱手动编写脚本的苦恼:smile:(由于同源策略,该 工具 不支持iframe内的操作录制)
@author: Monado
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Android自动化测试入门(四)单元测试
- golang分层测试之http接口测试入门
- iOS 单元测试和 UI 测试快速入门
- Kali无线渗透测试入门
- TiDB入门(三):简单测试
- Web测试入门——软件测试员必知的50个常见测试点
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Effective Java: Second Edition
Joshua Bloch / Addison-Wesley / 2008-05-28 / USD 54.99
Written for the working Java developer, Joshua Bloch's Effective Java Programming Language Guide provides a truly useful set of over 50 best practices and tips for writing better Java code. With plent......一起来看看 《Effective Java: Second Edition》 这本书的介绍吧!