什么是TestCafeA node.js tool to automateend-to-end web testingWrite tests in JS or TypeScript, run them and view results抓几个重点词语:1. E2E Web Testing 2.JSTypeScript 3. Node.js Tool。简单说就是Node.JS编写的Web端UI自动化测试框架。官网:http://devexpress.github.io/t…TestCafe VS Selenium这时我想你跟我都有个疑问,跟Selenium 有啥区别?这里个人简单阅读了下官方文档,写几个粗浅的对比。Selenium毕竟已经是Web自动化测试的W3C标准了,它有非常多的优势,但TestCafe 作为后起之秀我这还想夸夸Demo使用过程的几点优于Selenium的感受。TestCafe 不再像Selenium 通过各个浏览器提供的Driver来驱动浏览器,而是有点类似Selenium RC直接往页面注入JS来操作页面,所以使用过程中再也不用担心因为浏览器版本和Driver版本以及Selenium版本不匹配而照成的Case执行失败。TestCafe是一整套完整的自动化测试框架,不仅提供了Cases的管理,运行,失败自动重跑,错误自动截图,并发等,对页面和页面元素的等待也封装完善而且使用简单,不像Selenium需要借助其他框架或者二次封装智能等待或者使用隐示/显示等待而有点复杂。TestCafe 可以控制整体的执行速度,甚至可以细到某个操作的执行速度(这个有点类似慢放,用起来大家可以感受下,非常魔性)TestCafe 因为只要你的浏览器支持JS,所以支持桌面,移动端平台。TestCafe debug模式,通过代码配置或运行时设置,可以控制执行过程中失败时进入调试模式。PS:当然以上的感受并没有经过项目的积累,纯粹Demo过程中的总结,也不晓得真正用到项目中会有哪些坑得踩。跟大家推荐一个学习资料分享群:903217991,里面大牛已经为我们整理好了许多的学习资料,有自动化,接口,性能等等的学习资料!人生是一个逆水行舟的过程,不进则退,咱们一起加油吧!TestCafe 快速入门安装因为是Node.js 项目,可以直接通过npm安装,全局安装如下npm install -g testcafe快速Demo一个baidu.jsfixture baidu demo .page https://www.baidu.com;test(‘baidu search’, async t=>{ await t.typeText(’#kw’,“hao123”) .click(’#su’)});通过Chrome运行testcafe chrome baidu.js上面代码看不懂没关系,感受下TestCafe就行。Cases管理自动化测试,终归还是测试,是测试就离不开测试用例,那TestCafe如何组织管理测试用例?fixture 和 test一个js文件可以包含多个fixture,一个fixture可以包含多个test。 我们可以理解为fixture是个集合,test标注的每个函数模块是一个case。语法fixture(“测试集描述”)fixture 测试集合描述test(‘用例描述’,fn(t))Demofixture(“cases manage”).page(“https://www.baidu.com”);test(’this case 1’, async I => { console.log(“this is case 1”);});test(’this case 2’, async I => { console.log(“this is case 2”);});test(’this case 3’, async I => { console.log(“this is case 3”);});fixture(cases manage 2).page(https://testerhome.com/#gsc.tab=0);test(’this case 1-1’, async I => { console.log(“this is case 1-1”);});test(’this case 2-1’, async I => { console.log(“this is case 2-1”);});test(’this case 3-1’, async I => { console.log(“this is case 3-1”);});运行结果:其中你会发现每个test 执行之前都会执行fixture打开页面的操作,但只会启动一次浏览器。那这时又会一个新的问题,除了打开页面的前提条件,是否框架自带了更多的前提/后置条件的处理了,也就是各种beforexxx。当然!fixture 的前置条件fixture.beforeEach( fn(t) ):每个test执行之前都会被运行fixture.afterEach( fn(t) ):每个test执行之后都会被运行fixture.before(fn(t)):比beforeEach更早运行,且每个fixture只运行一次fixture.after(fn(t)):比afterEach更晚运行,且每个fixture只运行一次Demojfixture(beforeeach test1) .page(https://www.baidu.com) .beforeEach(async I => { console.log(’this is beforeEach’) }) .before(async I => { console.log(’this is before’) }) .after(async I => { console.log(’this is after’) }) .afterEach(async I=>{ console.log(“this is afterEach”) });test(“test beforeAndafter”,I=>{ console.log(“1111”)});test(“test beforeAndafter”,I=>{ console.log(“2222”)});运行结果:test的前置条件test.before(fun(t)):该test运行之前运行test.after(fun(t)):该test运行之后运行Demofixture(beforeeach test1) .page(https://www.baidu.com) .beforeEach(async I => { console.log(’this is beforeEach’) }) .before(async I => { console.log(’this is before’) }) .after(async I => { console.log(’this is after’) }) .afterEach(async I => { console.log(“this is afterEach”) });test .before(async t => { console.log(this is test's before) }) (“test beforeAndafter”, I => { console.log(“1111”) }) .after(async t => { console.log(this is test's after) });test(“test beforeAndafter”, I => { console.log(“2222”)});运行结果:注意: 从控制台输出看,test的before/after 会覆盖fixture中的beforeEach/afterEach。也就是说如果一个test里面包含了before/after 那么fixture中的beforeEach/afterEach对该test无效。跳过测试fixture.skip :跳过该fixture下的所有testtest.skip : 跳过该testfixture.only :只执行该fixture下的所有test,其余的fixture下的test全部跳过test.only : 只运行该test,其余全部跳过元素定位Demo1.创建Selectorsimport { Selector } from ’testcafe’;2.使用Selectors// 通过css定位 const osCount = Selector(’.column.col-2 label’).count; // 通过id定位 const submitButtonExists = Selector(’#submit-button’).exists;同时因为是JS注入方式,所以定位方式非常灵活,几乎JS中定位元素的方式都支持。 例如import { Selector } from ’testcafe’;fixture My fixture .page http://devexpress.github.io/testcafe/example/;const label = Selector(’#tried-section’).child(’label’);test(‘My Test’, async t => { const labelSnapshot = await label(); await t.click(labelSnapshot);});test(‘My test’, async t => { const secondCheckBox = Selector(‘input’) .withAttribute(’type’, ‘checkbox’) .nth(1); const checkedInputs = Selector(‘input’) .withAttribute(’type’, ‘checkbox’) .filter(node => node.checked); const windowsLabel = Selector(’label’) .withText(‘Windows’); await t .click(secondCheckBox) .expect(checkedInputs.count).eql(1) .click(windowsLabel);});同时还支持自定义扩展选择器,而且针对当前流行的React,Vue,Angular,Aurelia前端框架,还有特点的定位选择器,这里内容很多,有兴趣直接看官方文档:http://devexpress.github.io/t…操作元素操作其实上面例子我们已经用过点击,文本输入等方法了,官方也给了很全的api文档和demo:http://devexpress.github.io/t… ,这里就讲下一些比较特殊的元素或浏览器的操作。- resizeWindow():设置窗口大小- t.maximizeWindow( ):最大化窗口fixturedemo.page(‘https://www.baidu.com’);test(‘设置win窗口大小’, async I => { await I.resizeWindow(300, 500) ..maximizeWindow( );}); - getBrowserConsoleMessages():获取页面控制台消息 console.log(await I.getBrowserConsoleMessages())}); - wait():暂停test(‘暂停’, async I => { await I.wait(3000);});- switchToIframe():切换到iframe- switchToMainWindow():返回到主窗体fixtureiframe 处理 .pagehttp://www.w3school.com.cn/tiy/t.asp?f=jseg_alert;test(‘iframe ‘, async t => { await t .click(’#button-in-main-window’) // 切换ifrme .switchToIframe(’#iframe-1’) // 返回主窗体 .switchToMainWindow();});- 下拉框选取:其实就是定位下拉框,再定位到下拉框下的选项,然后点击两次。fixture下拉框选取 .pagefile:///C:/Note/selenium_html/index.html;test.only(‘下拉框选取 ‘, async t => { const phone = Selector(’#moreSelect’); const phoneOption = phone.find(‘option’); await t .click(phone) .click(phoneOption.withText(‘oppe’));});- 三种警告框的处理setNativeDialogHandler(fn(type, text, url) [, options]):fu返回true 点击确定,返回false点击取消,返回文本则在prompt输入文本,这个执行过程中就不会看到警告框弹出,直接处理掉。fixture警告框处理 .pagehttp://www.w3school.com.cn/tiy/t.asp?f=jseg_alert`;test('处理alert ‘, async t => { await t .switchToIframe(“iframe[name=‘i’]”) // return true 表示点击确定 .setNativeDialogHandler(() => true) .click(‘input[value=“显示警告框”]’) .wait(10000);});fixture警告框处理 .pagehttp://www.w3school.com.cn/tiy/t.asp?f=jseg_prompt;test.only(‘处理 提示框 ‘, async t => { await t .switchToIframe(“iframe[name=‘i’]”) .setNativeDialogHandler((type, text, url) => { switch (type) { case ‘confirm’: switch (text) { //false 点击 取消 case ‘Press a button!’: return false; // 返回 true 点击确定 case ‘You pressed Cancel!’: return true; default: throw ‘Unexpected confirm dialog!’; } case ‘prompt’: // 警告框填入值 hi vidor return ‘Hi vidor’; case ‘alert’: throw ‘我是警告框!!’; } }) .click(‘input[value=“显示提示框”]’) .wait(10000);});上传文件setFilesToUpload(),清空上传:clearUpload():fixtureMy fixture .pagehttp://www.example.com/;test(‘上传图片’, async t => { await t .setFilesToUpload(’#upload-input’, [ ‘./uploads/1.jpg’, ‘./uploads/2.jpg’, ‘./uploads/3.jpg’ ]) // 清除上传 .clearUpload(’#upload-input’) .click(’#upload-button’);});断言TestCafe自带了较为齐全的断言方法。断言都是通过expect()开始;import { Selector } from ’testcafe’;fixture My fixture;test(‘My test’, async t => { // 断言 通过CSS定位到的有3个元素,eql()表示相等,count表示定位元素个数 await t.expect(Selector(’.className’).count).eql(3);});test(‘My test’, async t => {// 断言ok()表示为true,exists表示元素是否存在 await t.expect(Selector(’#element’).exists).ok();});更多APIdemo查看官方文档:http://devexpress.github.io/t…特性在介绍几个TestCafe比较有意思的几个地方。执行速度testcafe 支持测试执行的速度控制。 speed(x),x支持0.01到1之间,1则表示正常速度执行。全局速度控制可以通过控制台执行命令控制:testcafe chrome xxxx.js –speed 0.1控制某个test的执行速度test(“test setTestSpeed”, I => { I.setTestSpeed(0.1); ……});控制某个步骤的执行速度test(“test setTestSpeed”, I => { I.click("#kw").setTestSpeed(0.5);});Chrome设备模拟在启动Chrome浏览器时,可以设定Chrome提供的模拟器。testcafe “chrome:emulation:device=iphone x” xxx.js设备模拟器更多参数查看:http://devexpress.github.io/t…PageObject demo大家都知道,做UI自动化测试,肯定得使用PO或者PF模式,下面简单Demo个例子看看TestCafe 可以如何组织PO模式。baiduPage.jsimport {Selector, t as I} from ’testcafe’class baiduPage { baiduInput = Selector(’#kw’); baiduButton = Selector(’#su’).withAttribute(‘value’, ‘百度一下’); async searchBaidu(text) { await I .typeText(this.baiduInput, text, { // 清空 replace: true, }) .click(this.baiduButton) };}export default baiduPage = new baiduPage();baiduCases.jsimport baiduPage from ‘./baidu_page’fixturebaidu search.pagehttps://www.baidu.com/;test(‘po demo’, async I => { await I.typeText(baiduPage.baiduInput, “test”); baiduPage.searchBaidu(“testCafe”); await I.typeText(baiduPage.baiduInput,“居于之前的字符串空两个字符中插入”,{ caretPos:2 })});参数化/数据驱动其实就是创建一个对象,用for … of … 循环遍历fixturetodoPage test cases.pagehttp://todomvc.com/examples/react/#/;const testCases = [ { todo: ‘123’, }, { todo: ‘!@#$’, } // 等等可能性的cases,这里随便造两个作为data driver];for (const todoText of testCases) { test(‘create todo list ’ + todoText.todo, async t => { await todoPage.createTodoList(todoText.todo); await t.expect(todoPage.firstTodo.innerText).eql(todoText.todo); });}运行方式RunnerTestCafe 可以通过命令行的方式来执行测试脚本,但是感觉实际过程中肯定不是很方便,特别如果运行时需要跟一堆参数的情况下,那么TestCafe 提供了Runner,更方便配置和运行。如下配置,我需要被运行的Cases,错误自动截图,并发,生成report,智能等待,执行速度,执行的浏览器等全部配到Runner里面,这样我就不需要通过命令行运行,而且在项目中使用非常方便。const createTestCase = require(’testcafe’);const fs = require(‘fs’);let testcafe = null;createTestCase(’localhost’, 1337, 1338) .then(tc => { testcafe = tc; const runner = testcafe.createRunner(); const stream = fs.createWriteStream(‘report.json’); return runner // 需要运行的cases .src( [ ‘../demo/podemo/*.js’, ‘../demo/setWindowsSize.js’ ] ) // 设置需要执行的浏览器 .browsers([ ‘chrome’, ‘firefox’ ]) // 错误自动截图 .screenshots( // 保存路径 ‘../error/’, true, // 保存路劲格式 ‘${DATE}_${TIME}/test-${TEST_INDEX}/${USERAGENT}/${FILE_INDEX}.png’ ) // 生成report格式,根据需要安装对应report模块, // 详细看:http://devexpress.github.io/testcafe/documentation/using-testcafe/common-concepts/reporters.html .reporter(‘json’, stream) // 并发 .concurrency(3) .run({ skipJsErrors: true, // 页面js错误是否忽略,建议为true quarantineMode: true, // 隔离模式,可以理解为失败重跑 selectorTimeout: 15000, // 设置页面元素查找超时时间,智能等待 assertionTimeout: 7000, // 设置断言超时时间 pageLoadTimeout: 30000, // 设置页面加载超时时间 debugOnFail: true, // 失败开启调试模式 脚本编写建议开启 speed: 1 // 执行速度0.01 - 1 }); }).then(failedCount => { console.error(‘Failed Count:’ + failedCount); testcafe.close();}) .catch(err => { console.error(err); });结语:跟大家推荐一个学习资料分享群:903217991,里面大牛已经为我们整理好了许多的学习资料,有自动化,接口,性能等等的学习资料!人生是一个逆水行舟的过程,不进则退,咱们一起加油吧!