写在前面
随着业务的增加,复杂性的增加,我们更需要保证页面不能出错,之前需要每次上线之前需要每次人工测试,如果有好多改动,为保证业务不出错,需要耗费更多的时间来测试,所以我们需要写一些测试来保证业务的逻辑。
端到端测试
测试有很多种,只是当前我们的业务对单元测试不太友好(之前写过redux的单元测试,例子在点我),代码耦合性略高,函数也非pure function。所以需要端到端的测试(End to End Testing)。端到端的测试可以确保一堆组件能够按照预先设想的方式整合起来运行的时候使用。
testcafe
之前调研了一些框架,选择了testcafe这个框架,之前是收费的,现在开源没多久,所以生态不是很好。之所以选中testcafe,很主要的原因是它的api简单和不需要任何依赖。
testcafe只需要全局安装这个库,并不需要安装lite chrome等等。还有一点就是它很具有前瞻性的支持了ts和众多es6,es7的特性。这是比较爽的。
我们开始编写一个测试试一下。
安装testcafe环境
sudo npm i -g testcafe
开始编写case
import { Selector } from 'testcafe';
引入选择器
fixture `open.toutiao.com test case`
.page `http://open.toutiao.com/`;
打开需要测试的网站(api比较简洁)。
test('should open.toutiao work as expected', async t => {
//some code there
});
这是一个测试的case
test('should open.toutiao work as expected', async t => {
const newsList = Selector('section');
await t.expect(newsList.exists).eql(true, 'should display news list');
})
这是一个最简单的例子,我们选择新闻列表,这个列表需要存在。
ok,我们运行一个命令来执行这个测试。
文件保存为index.js
testcafe chrome index.js
官网例子
import { Selector } from 'testcafe';
fixture `Github Search`
.page `https://github.com`;
test('should github search work as expected', async t => {
const searchInput = Selector('.js-site-search-focus');
const searchList = Selector('.repo-list-item');
const resultItem = Selector('.repo-list-item h3 a');
const repoContent = Selector('.repository-content');
await t.setTestSpeed(0.8);
await t.expect(searchInput.exists).eql(true, 'should search input visible');
await t.typeText(searchInput, 'testcafe');
await t.pressKey('enter');
await t.expect(searchList.count).eql(10, 'should show 10 results');
await t.click(resultItem);
await t.expect(repoContent.exists).eql(true, 'should repo detail visible');
const location = await t.eval(() => window.location);
await t.expect(location.pathname).eql('/DevExpress/testcafe', 'should testcafe repo found');
});
这个测试做的工作为打开github,期望github的搜索框存在,输入框输入testcafe,点击回车,期望搜索列表搜索结果多于10条,点击第一条结果,期望跳转的页面中存在返回的内容。
最后期望网址的域名搜索位置为/DevExpress/testcafe。返回。
可以运行测试
testcafe chrome index.js
我们的测试
我们的测试也挺简单的,再给个例子吧~
import { Selector, ClientFunction } from 'testcafe';
fixture `open.toutiao.com test case`
.page `http://open.toutiao.com/`;
test('should open.toutiao work as expected', async t => {
const newsList = Selector('section');
const detailItem = Selector('.list_content section a');
const getWindowLocation = ClientFunction(() => document.body.scrollTop);
let random = Math.floor(Math.random()*10);
await t.expect(newsList.exists).eql(true, 'should display news list');
await t.expect(newsList.count).gt(5,'news more than 5 ');//需要新闻列表页大于5条新闻
let a = detailItem.nth(random);
await t.click(a);//进入任意一条详情页
await t.debug();
await t.eval(() => {
document.body.scrollTop =$('.box-title')[0].offsetTop;//滚动到推荐
});
await t.expect(getWindowLocation()).gt(0,'should be scroll');//保证页面滚动
await t.expect(Selector('#pageletArticleContent').exists).eql(true, 'should display news and it is open.toutiao ');//文章是open下的文章
});
测试做的工作是打开open.toutiao.com,期望新闻列表页存在,期望多于5条新闻,随机点开一条新闻,文章滚动到“精彩推荐区域”,保证页面已经滚动,保证文章内容存在,且不是广告页。
具体的工作已经写在注释就不多说了。
测试效果
执行命令,自动打开浏览器。输入网址:
我们可以通过await debug
来进行调试,点击上图的step可以每步进行调试。
运行成功如图
如果点击到广告页,搜索不到新闻内容就会报错,我们也可以很容易的debug,如图:
我们可以看到哪一步出错,报什么错,来进行业务代码的快速debug,也可以配合插件进行log上报。
屏幕快照功能
await t
.click('#change-avatar')
.setFilesToUpload('#upload-input', 'img/portrait.jpg')
.click('#submit')
.takeScreenshot();
点击文件上传,上传文件,点击提交,然后拍一下照,保存。可以在命令行里加-s来指定文件位置。就不展示了。
注意
- testcafe不提供浏览器环境,所以如果我们需要什么浏览器就自行下载。只需要在命令行修改浏览器名称。比如 testcafe safari index.js。
- testcafe不支持function spy。
- testcafe支持异步,不需要为lazyload的dom特殊处理。可以直接选择。
- 在eval里不支持await
- ...具体参见其官网好了。