e2e or end-to-end or UI testing is a methodology used to test whether the flow of an application is performing as designed from start to finish. In simple words, it is testing of your application from the user endpoint where the whole system is a blackbox with only the UI exposed to the user.
It can become quite an overhead if done manually and if your application has a large number of interactions/pages to test.
In the rest of the article I’ll talk about webdriverJS and Jasmine to automate your e2e testing, a combination which isn’t talked about much on the web.
What is WebDriverJS?
This was something which took me quite sometime to put my head around and I feel this was more or less due to the various available options for everything related to WebDriver.
So let’s take it from the top and see what its all about.
Selenium
As mentioned on the selenium website, Selenium automates browsers. That’s it.
This having support for almost all major browsers, is a very good alternative to automate our tests in the browser. So whatever you do in the browser while testing your application, like navigating to pages, clicking a button, writing text in input boxes, submitting forms etc, can be automated using Selenium.
WebDriver
WebDriver (or Selenium 2) basically refers to the language bindings and the implementations of the individual browser controlling code.
WebDriver introduces a JSON wire protocol for various language bindings to communicate with the browser controller.
For example, to click an element in the browser, the binding will send POST request on/session/:sessionId/element/:id/click
So, at one end there is the language binding and a server, known as Selenium server, on the other. Both communicate using the JSON wire protocol.
WebDriverJS
As mentioned, WebDriver has a number of bindings for various languages like Ruby, Python etc. JavaScript being the language of choice for the web, is the latest one to make it to the list. Enter WebDriverJS!
So as you might guess, WebDriverJS is simply a wrapper over the JSON wire protocol exposing high level functions to make our life easy.
Now if you search webdriver JS on the web, you’ll come across 2 different bindings namely selenium-webdriver and webdriverjs(yeah, lots of driver), both available as node modules. You can use anyone you like, though we’ll stick to the official one i.e. selenium-webdriver.
Say you have a JavaScript project you want to automate e2e testing on. Installing the bindings is as simple as doing:
npm install selenium-webdriver
Done! You can now require the package and with a lil’ configuration you can open any webpage in the browser:
var webdriver = require('selenium-webdriver'); var driver = new webdriver.Builder(). withCapabilities(webdriver.Capabilities.chrome()). build(); driver.get('http://www.wingify.com');
To run your test file, all you do is:
node testfile.js
Note: In addition to the npm package, you will need to download the WebDriver implementations you wish to utilize. As of 2.34.0, selenium-webdriver natively supports the ChromeDriver. Simply download a copy and make sure it can be found on your PATH. The other drivers (e.g. Firefox, Internet Explorer, and Safari), still require the standalone Selenium server.
Difference from other language bindings
WebDriverJS has an important difference from other bindings in any other language - It is asynchronous.
So if you had done the following in python:
// pseudo code driver.get(page1); driver.click(E1);
Both statements would have executed synchronously as the Python (as every other language) API is blocking. But that isn’t the case with JavaScript. To maintain the required sequence between various actions, WebDriverJS uses Promises. In short, a promise is an object that can execute whatever you give it after it has finished.
But it doesn’t stop here. Even with promises, the above code would have become:
// pseudo code driver.get(page1).then(function () { driver.click(E1); });
Do you smell callback hell in there? To make it more neat, WebDriverJS has a wrapper for Promise called as ControlFlow.
In simple words, this is how ControlFlow prevents callback hell:
- It maintains a list of schedule actions.
- The exposed functions in WebDriverJS do not actually do their stuff, instead they just push the required action into the above mentioned list.
-
ControlFlow puts every new entry in the
then
callback of the last entry of the list, thus ensuring the sequence between them.
And so, it enables us to simply do:
// pseudo code driver.get(page1); // Implicitly add to previous action's then() driver.click(E1);
Isn’t that awesome!
Controlflow also provides an execute
function to push your custom function inside the execution list and the return value of that function is used to resolve/reject that particular execution. So you can use promises and do any asynchronous thing in your custom code:
var flow = webdriver.promise.controlFlow(); flow.execute(function () { var d = webdriver.promise.defer(); do_anything_async().then(function (val) { d.fulfill(val); }) return d.promise; });
Quick tip: Documentation for JavaScript bindings isn’t that readily available (atleast I couldn’t find it), so the best thing I found to be useful was the actual WebDriverJS code. It heavily commented and is very handy while looking for specific methods on the driver.
Combining WebDriverJS with Jasmine
Our browser automation is setup with selenium. Now we need a testing framework to handle our tests. That is where Jasminecomes in.
You can install jasmine for your JavaScript project through npm:
npm install jasmine-node
If we were to convert our earlier testfile.js
to check for correct page title, here is what it might look like:
var webdriver = require('selenium-webdriver'); var driver = new webdriver.Builder(). withCapabilities(webdriver.Capabilities.chrome()). build(); describe('basic test', function () { it('should be on correct page', function () { driver.get('http://www.wingify.com'); driver.getTitle().then(function(title) { expect(title).toBe('Wingify'); }); }); });
Now the above file needs to be run with jasmine-node, like so:
jasmine-node testfile.js
This will fire the browser and do the mentioned operations, but you’ll notice that Jasmine won’t give any results for the test. Why?
Well…that happens because Jasmine has finished executing and no expect
statement ever executed because of the expectation being inside an asynchronous callback of getTitle
function.
To solve such asynchronicity in our tests, jasmine-node provides a way to tell that a particular it
block is asynchronous. It is done by accepting a done callback in the specification (it
function) which makes Jasmine wait for the done()
to be executed. So here is how we fix the above code:
var webdriver = require('selenium-webdriver'); var driver = new webdriver.Builder(). withCapabilities(webdriver.Capabilities.chrome()). build(); describe('basic test', function () { it('should be on correct page', function (done) { driver.get('http://www.wingify.com'); driver.getTitle().then(function(title) { expect(title).toBe('Wingify'); // Jasmine waits for the done callback to be called before proceeding to next specification. done(); }); }); });
Quick tip: You might want to tweak the time allowed for tests to complete in Jasmine like so:
jasmine.getEnv().defaultTimeoutInterval = 10000; // in microseconds.
Bonus for Angular apps
Angular framework has been very testing focused since the very beginning. Needless to say, they have devoted a lot of time on e2e testing as well.
Protractor is a library by the Angular team which is a wrapper on WebDriverJS and Jasmine and is specifically tailored to make testing of Angular apps a breeze.
Checkout some of the neat addons it gives you:
-
Apart from querying element based on id, css selector, xpath etc, it lets you query on basis of binding, model, repeater etc. Sweet!
-
It has Jasmine’s
expect
function patched to accept promises. So, for example, in our previous test where we were checking for title:
driver.getTitle().then(function (title) { expect(title).toBe('Wingify'); });
can be refactored to a much cleaner:
expect(driver.getTitle()).toBe('Wingify');
And more such cool stuff to make end-to-end testing for Angular apps super-easy.
In the end
e2e testing is important for the apps being written today and hence it becomes important for it to be automated and at the same time fun and easy to perform. There are numerous tools available for you to choose and this article talks about one such tool combination.
Hope this helps you get started. So what are you waiting for, lets write some end-to-end tests!
Using an e2e testing stack you want to share? Let us know in the comments.
Links & references
-
WebDriverJS user guide: https://code.google.com/p/selenium/wiki/WebDriverJs
-
WebDriverJS source: https://code.google.com/p/selenium/source/browse/javascript/webdriver/
-
JSON wire protocol: https://code.google.com/p/selenium/wiki/JsonWireProtocol
-
Jasmine: http://pivotal.github.io/jasmine/
-
jasmine-node: https://github.com/mhevery/jasmine-node
-
Protractor: https://github.com/angular/protractor
相关推荐
前端开源库-protractor-jasmine2-screenshot-reporter量角器-jasmine2-screenshot-reporter,在每个执行量角器测试用例后使用screenshot reporter捕获截图。
茉莉花节点jsdom-extjs-testing-tool 使用 jasmine-node 和 jsdom 的功能性前端 Ext.JS 测试自动化工具如果您已经安装了节点包模块( ),安装将为您获取所需的库。Ext.JS 设置使用 Ext.JS 包并遵循 Sencha cmd 企业...
e2e测试用业力和茉莉花记录使用量角器进行的端到端测试以及使用Karma和Jasmine对javascript和角度组件进行单元测试的过程。概述Jasmine是一个流行且广泛使用的框架,用于对JavaScript代码进行单元测试。 因果赛跑者...
6. **async testing**:对于异步测试,Jasmine 提供了 `done` 回调和 `async/await` 支持。插件可以帮助你在 Atom 中快速设置这些异步测试模式。 7. **custom matchers**:如果你需要自定义的匹配器,插件可能也...
标题中的“protractor-jasmine-matchers”是一个专为Protractor设计的扩展库,它提供了额外的Jasmine匹配器,以增强端到端测试的能力。在软件开发中,特别是Web应用程序的自动化测试,Protractor和Jasmine是两个重要...
git clone :e2e-boilerplate / protractor-es-modules-babel-jasmine-expect.git cd protractor-es-modules-babel茉莉花预期 npm安装 npm运行更新:webdriver npm运行测试 有关更多样板,请单击
nodejs-testing-karma-jasmine 使用 Karma 和 Jasmine 测试的示例 Node.JS 应用程序。 基于这篇博文: : “一个可以搜索与给定查询匹配的文件的 Node 应用程序”
标题“protractor-jasmine-typescript-master”暗示了一个项目,它结合了Protractor、Jasmine和TypeScript这三种技术,用于端到端(E2E)测试。这个项目的目的是利用TypeScript的强大类型系统和Jasmine的测试框架,...
npm install grunt-contrib-jasmine --save-dev 插件安装完成后,可以使用以下JavaScript代码在您的Gruntfile中启用它: grunt . loadNpmTasks ( 'grunt-contrib-jasmine' ) ; 茉莉花任务 使用grunt jasmine命令...
量角器样板 ...git clone :e2e-boilerplate / protractor-es-modules-babel-jasmine-assert.git cd量角器-es-模块-babel茉莉花断言 npm安装 npm运行更新:webdriver npm运行测试 有关更多样板,请单击
前端开源库-grunt-jasmine-node-coveragegrunt jasmine节点覆盖率,使用伊斯坦布尔运行jasmine以获取代码覆盖率报告的grunt任务。基于Omar Gonzalez(S9tpepper)的咕噜茉莉节点。
git clone :e2e-boilerplate / protractor-typescript-tsc-jasmine-assert.git cd量角器打字稿-tsc-茉莉花断言 npm安装 npm运行构建 npm运行更新:webdriver npm运行测试 有关更多样板,请单击
Jasmine 和 Karma 进行 Angular 单元测试 欢迎 关于课程/教程 大家好,我是Dinanath Jayaswal, Senior UI/Web Developer and Adobe Certified Expert Professional ,我想欢迎您Angular Unit Testing with Jasmine ...
茉莉花 ESLint茉莉花规则用法将eslint-plugin-jasmine安装为dev依赖项: npm install --save-dev eslint-plugin-jasmine 通过将插件添加到您的.eslintrc来启用该插件: plugins : - jasmine ESLint本身为Jasmine的...
npm install protractor-jasmine-cucumber --save-dev 要求在您的protractor.conf.js文件顶部 var cucumber = require('protractor-jasmine-cucumber'); 并使用助手功能将跑步者注入您的套房中 suites: { suite1...
本篇文章将深入探讨“grunt-template-jasmine-requirejs”这个前端开源库,它是如何整合Grunt、Jasmine和RequireJS这三者,以实现高效、规范的测试驱动开发的。 首先,我们来理解一下各个组件的基础知识: 1. **...
esri-js-testing-tools-and-patterns 来自 Dave Bouwman 和 Tom Wayson 在 Esri 2015 国际开发者峰会上发表的JavaScript 映射应用程序测试工具和模式演讲中的资源链接。 有关 2014 年演讲的链接,请参阅 2014/...
实验室茉莉花测试简介介绍本练习的范围是熟悉Jasmine测试框架并学习如何编写基本测试。到目前为止,您几乎已经在每个实验室中进行了测试。测试是事先编写的,您将根据测试开发解决方案。今天,您将有所不同,并为...