JP's blog

Tech talk with a french twist.

Welcome

Hi! My name is JP, I am a front end engineer living in San Francisco. I am passionate about web development in general and web performance optimization in particular. Welcome to my blog, I hope you’ll enjoy the reading.

Running Jasmine Tests With Phantom.js or Webdriver

Nick Gauthier was recently sharing how he was running his Jasmine test using Capybara with the Capybara Webkit headless driver. You can check out his capybara-jasmine project on GitHub.

In my recent blog post on TDD I mentioned that I had just put together a Javascript test suite using Jasmine. In my case, I’ve used Phantom.js for headless fast tests as well as Selenium Webdriver for real browser testing (I usually use headless during development to get quick feedback and use the real browsers as a safety check before commit). Nick Gauthier’s project inspired me to share my setup.

Test suite

For this blog post, I can not share the code I already built as it belongs to my employer. Instead, I will start from scratch using the Jasmine 1.2.0 standalone release. It includes a sample test suite which will be a perfect fit for this example. It includes the main test runner (an HTML page called SpecRunner.html) and the Jasmine distribution (under the lib/ directory). It also includes example code under spec and src. If you unzip the file and load SpecRunner.html in your browser, you should see the test suite pass without errors.

Phantom.js

To run the test suite using Phantom.js, I’ve used Joshua Carver’s Jasmine runner for Phantom.js. I copied the lib directory from the project under lib/phantom-jasmine in my source tree.

Next I changed the SpecRunner.html to add an additional reporter called ConsoleReporter - which is part of Joshua’s project.

Add script tag for ConsoleReporter
1
<script type="text/javascript" src="lib/phantom-jasmine/console-runner.js"></script>
Add ConsoleReporter to Jasmine environment
1
2
window.consoleReporter = new jasmine.ConsoleReporter();
jasmineEnv.addReporter(consoleReporter);

Third step: patch Jasmine to get a stack trace on test failure. The current version of Jasmine (1.2.0) does not show stack traces when executed throught Phantom.js. Thanks to a tip found on Stackoverflow I was able to fix that with a very simple patch and submitted a pull request.

Jasmine patch for stack traces
1
2
3
4
5
6
7
8
9
10
@@ -106,7 +106,9 @@ jasmine.ExpectationResult = function(params) {
   this.actual = params.actual;
   this.message = this.passed_ ? 'Passed.' : params.message;

-  var trace = (params.trace || new Error(this.message));
+  var err;
+  try { throw new Error(this.message); } catch(e) { err = e };
+  var trace = (params.trace || err);
   this.trace = this.passed_ ? '' : trace;
 };

Assuming that Phantom.js is installed and available in the $PATH, the test suite can be executed using the following command:

Running the Jasmine test with Phantom.js
1
phantomjs lib/phantom-jasmine/run_jasmine_test.coffee SpecRunner.html

Finally, I wrapped the above command in a Rake task so that I can just type rake phantomjs to run the test suite:

Rake task for Phantom.js
1
2
3
4
5
desc "Run Jasmine tests with Phantomjs"
task :phantomjs do
  # Note: we are assuming phantomjs is installed and available in $PATH
  sh %{phantomjs lib/phantom-jasmine/run_jasmine_test.coffee SpecRunner.html}
end

This is what the output looks like:

Webdriver

In order to execute the Jasmine test suite in real browsers, I am using Selenium Webdriver. I am using the selenium-webdriver gem to interact with it. In just a minute, I will show how I have added an additional task to my Rakefile to run the tests.

Also note that a webserver is required to serve the SpecRunner.html file and its dependencies. One could setup a webserver such as Apache but I think it is too much work and creates an external unnecessary dependency for the test runner (every environment where the tests are executed would need to configure an instance of Apache). Instead, I prefer to use the service_manager gem to spin up a simple web server on demand using the python -m SimpleHTTPServer command. With Service Manager, you define services that will be automatically started when the tests begin and stopped at the end. Because Python is widely available, no extra dependencies should be required. For more information, see service_manager documentation on GitHub.

The Rakefile in the end is fairly straightforward:

  • Require bundler and some gems
  • Start ServiceManager which will spawn the webserver process
  • Detect the browser passed as a command line argument
  • Instantiate Webdriver and load the SpecRunner.html file
  • Capture the output of the ConsoleReporter and display it
  • Finally, check the status for success or failure

The complete Rakefile looks like this:

Rakefile including task for Webdriver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
require 'rubygems'
require 'bundler/setup'

require 'selenium-webdriver'
require 'service_manager'


desc 'Run Jasmine tests with Phantomjs'
task :phantomjs do
  # Note: we are assuming phantomjs is installed and available in $PATH
  sh %{phantomjs lib/phantom-jasmine/run_jasmine_test.coffee SpecRunner.html}
end


desc 'Run Jasmine tests with Webdriver'
task :webdriver do
  # Use service_manager to start a simple web server
  ServiceManager.start

  # Detect which browser we want to run
  case ENV['browser']
  when 'chromium'
    # TODO: detect chromium path? I use Linux, this is the path on my machine
    Selenium::WebDriver::Chrome.path = '/usr/lib/chromium-browser/chromium-browser'
    driver = Selenium::WebDriver.for :chrome
  when 'firefox'
    driver = Selenium::WebDriver.for :firefox
  else
    raise ArgumentError, 'Unknown browser requested'
  end

  # Finally, we load the spec runner HTML page with WebDriver
  driver.navigate.to 'http://localhost:8000/SpecRunner.html'
  status = driver.execute_script('return consoleReporter.status;')
  output = driver.execute_script('return consoleReporter.getLogsAsString();')
  driver.quit

  print output

  # Make sure to exit with code > 0 if there is a test failure
  raise RuntimeError, 'Failure' unless status === 'success'

end

To run the webdriver task, just execute rake webdriver browser=firefox. You should see Firefox start and go through the tests. This is what the output looks like:

A remaining step is that I will need to add support for browsers other than Firefox or Chromium, as well as support for remote Webdriver instances (such as Internet Explorer running in a virtual machine).

Breaking stuff

Before wrapping up, I’d like to show a failure example. Let’s break some code by commenting out line 17 of src/Player.js. Running rake phantomjs fails as expected. Notice how I can see the full stack trace which points me to line 33 of spec/PlayerSpec.js.

Wrap up

Phantom.js, Webdriver and Jasmine are a really powerful combo to test drive code. Not only that, they are also really easy to set up. Kudos to the various Open Source contributors behind these projects for providing a great developer experience!

The next step of this adventure is continuous integration. I need to integrate the tests with our Jenkins instance. Hopefully, that should be trivial since I have my tests runner command ready to go.

If you want to see the code, it’s available on GitHub.

What do you think? Do you find this technique useful? What other tips do you use for running your Javascript tests? If you have feedback on this post, feel free to comment below or to contact me via Twitter (@jphpsf).

OMG, Test Driven Development Actually Works!

You often hear people advocate that writing tests (unit, functional, etc.) when building software leads to less bugs in production. How can one verify this statement? Usually, those people are already using TDD or BDD and might be working for companies that have a strong testing culture from day one. Then, how can one measure the impact of NOT writing tests? How can we verify that practicing TDD is actually producing less bugs? Can we stop writing tests for a period of time and look at the consequences it has on the defect count? That doesn’t seem very realistic.

In this post, I am trying to answer the question by analyzing real numbers from my current job. No tests were written originally and once tests were included, I became a strong advocate of the TDD methodology.

DRYing Up Your JavaScript Jasmine Tests With the Data Provider Pattern

Lately, I’ve been using Jasmine to unit test my JavaScript code. Jasmine is a great BDD framework. It has a very clean and easy syntax. It has a lot of useful features such as matchers/expectations and mock objects (spies).

However, one feature I have been missing is a data provider mechanism. I learned about that feature while using PHPUnit for PHP unit testing. The basic premise of a data provider is to feed a test with multiple test values to avoid repeating your test code over and over.

In this post, I will show you how you can leverage that data provider pattern with Jasmine.

Share the #webperf Love

August is Speed Awareness Month! This blog post was originally published yesterday on the Speed Awareness Month blog. Check it out to learn tips and tools for speeding up your website.

If you care about web performance, you are likely to know and use tools such as WebPagetest, HTTP Archive, YSlow, Boomerang, etc. Whether your level is novice or expert with these tools, using them is only one side of the coin. What about contributing back to them? Those tools are open source which means you - whether you are a novice or an expert - can help out.

Open source represents one aspect of the web performance community. User group (meetups) focused on web performance are another.

In this post, I will explain how you can get started and get involved in our continuously growing community.

Squeezing Octopress for Faster Load Times

This blog runs an out of the box Octopress setup. I love Octopress. It’s a great framework. It’s trivial to setup, gets out of your way and it just works.

Being passionate about web performance optimization, I decided to “eat my own dog food” and look at how I could improve the load time of my blog.

Backing Up Your Twitter Account With "t"

Are you backing up your data regularly? You probably are and if not you should :) What about your social media accounts, is that important to backup? For instance, Twitter: have you ever wanted to backup your tweets, direct messages, favorites…?

There are pleny of backup solutions for Twitter. However, it seems that most of them are 3rd party websites and I am not sure if you can automate them easily (to integrate them with a backup script for instance). Wouldn’t it be cool if you could drive this task using only the command line?

Recently, I came accross the Twitter CLI gem. It’s a very powerful tool to query Twitter from the command line. In this post, I will show you how to leverage it to backup your Twitter data.

Front End Performance Case Study: GitHub

A couple weeks ago, someone in my Twitter timeline retweeted the following tweets from DOM Monster:

In HTML5, quotes around attribute values are optional. Which means, omit them. Smaller, faster, less clutter.

Here’s an example. This page from GitHub contains about 4,517 quote characters. Most of these can be omitted.
https://github.com/rails/rails/commit/3756a3fdfe8d339a53bf347487342f93fd9e1edb

This is a very specific and interesting performance optimization suggestion. I never really thought about it much or even looked at it to see what kind of performance impact, the omission of quote characters might have on a web page. However, after reading these tweets, I started to wonder: how well is GitHub doing on front end performance?

Hello World

In December 2011, I wrote a guest post on the Performance Calendar blog (a project from Stoyan Stefanov). While I’ve been using the Internet for ages and reading blogs for a long time*, I actually never owned my own blog. The Performance Calendar article was a premiere for me.

This was a very interesting and enriching experience. I never thought I would have enjoyed writing so much. Not only that, I also really liked the preparation phase (researching and gathering the information I needed for my post). Finally, I liked getting some feedback after publication.

Earlier this year, my wife and I were chatting about our year 2011, looking back at it and discussing what we wanted to accomplish in 2012. One item on my list was: starting a blog. I enjoyed writing a guest post enough that I wanted to make it a recurring habit. Better get going!

So here we are, April 2012, introducing my blog “Tech talk with a french twist”. You can expect to read about web development in general and web performance in particular. I am also thinking to post book reviews (both technical and non-technical). Occasionaly, I may talk about gadgets or life in general.

Welcome to my blog, I hope you’ll enjoy the reading.

* If I recall properly, I have been using Intenet since 1999 and reading blogs since 2004/2005.