Close
Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

LABS
JsUnit moved to GitHub

We've moved JsUnit from SourceForge (where it's been hosted for over 8 years) to GitHub, under Pivotal's account:

http://github.com/pivotal/jsunit

The motivation is (1) to bring JsUnit development more officially in-house at Pivotal Labs, where it has a better chance of getting more attention than it has historically, and (2) to more easily allow the wider community to contribute.

Fork away!

JsUnit has a public Tracker project here and CI here.

PIVOTAL LABS
Standup 9/10/2009: "All Alias, All The Time"

Interesting Things

  • One team reported that Capistrano can't deal with host aliases in .ssh/config. Others use host aliases with capistrano without trouble. The problem could be related to multiple host aliases. All this led to the statement:

    If you are working with EY, you should go all alias, all the time.

  • Problems with JsUnit and Firefox 3.5. From Adam:

    If you're planning to use JsUnit, or you already use JsUnit and you plan to upgrade your Firefox to version 3.5, you may run into this problem. Apparently the security settings in Firefox were updated in 3.5 to restrict file access in a way that stymies JsUnit. If you don't fix this JsUnit will fail to open test files, and will simply hang on tests runs, with no error output. To fix it:

    • type 'about:config' in the Firefox URL bar
    • Filter by 'security.fileuri.strict_origin_policy'
    • Set this to false

LABS
Agile Python & JsUnit

Looks like JsUnit gets a few pages devoted to it (about a dozen, actually) in the new book "Foundations of Agile Python Development":

http://www.apress.com/book/view/1590599810

Thanks to Dave Smith for the pointer.

PIVOTAL LABS
Standup 08/06/2008

Interesting Things

  • If you're having problems with JSUnit not loading in Firefox 3, load the about:config settings and search for 'origin'. You'll want to change the security.fileuri.strict_origin_policy value from 'true' to 'false'. JSUnit should now initialize properly, although you still won't see a Browse button.

LABS
Taming JavaScript in practice: AJAX with Protoype

In a previous post I discussed how to unit-test client-side AJAX JavaScript code using JsUnit. In that post I dealt with raw XmlHttpRequests. What if you're using a library such as Prototype, which provides a layer between your JavaScript and the raw request? Let's look at how you can hook into Prototype's AJAX functionality in order to mock out the raw request.

In Prototype, there's an object called Ajax that has a method called getTransport, which returns an XmlHttpRequest. In our test page, we can replace getTransport with a different implementation:

Ajax.getTransport = createMockTransport;

var request;
function createMockTransport() {
  request = new MockXmlHttpRequest();
  return request;
}

That's basically it: we now have a mock request that looks to Prototype like a real one. There are a couple of gotchas, though.

setRequestHeader

Protoype calls setRequestHeader on the XmlHttpRequest. The latest version of JsUnit's MockXmlHttpRequest mocks out setRequestHeader, but some earlier versions did not. If you're using a version earlier than 2.2alpha22, you'll need to add this method to your mock request:

request.setRequestHeader = function(label, value) {
}

(You can hold on to the request headers, of course, if you want to test them.)

abort

If your request ever gets aborted by your code, Prototype may encounter issues. To simulate an abort in your mock request that makes Prototype happy, try adding the following:

request.aborted = false;

request.abort = function() {
  this.aborted = true;
  this.readyState = 4;
  this.onreadystatechange();
  this.responseIsSuccess = function() {
    throw new Error("simulating crash when attempting to access request.transport.status");
  }
}

LABS
Taming JavaScript in practice: AJAX

Commonly the JavaScript side of AJAX ends up untested, tightly coupled to the server-side code, and difficult to read. In a previous post, we saw how testability led to the ability to refactor our code to make it readable. This time we'll focus on ways to test AJAX (which is a fairly lengthy topic in itself) and take it as read that once our code is tested we'll be in a good position to refactor towards readability and to generally tame the complexities of client-side AJAX code.

Example

Suppose we have a very simple calculator application: the user enters a number into a textfield and presses a button labeled "Double". The application sends the number to the server, and the server sends back a response containing twice the value of the number. The doubled value is then displayed in a second textfield. Of course, this is an artificial example, but the structure of the code is common enough to demonstrate practices for testing AJAX. Let's use raw XmlHttpRequests here; I'll post again separately with how to adapt this if you're using prototype.js. Our code might look like this:

<script language="javascript">
var request;
function calculate() {
  var enteredValue = document.entryfield.value;
  if (window.XMLHttpRequest)
    request = new XMLHttpRequest();
  else
    request = new ActiveXObject("Microsoft.XMLHTTP");
  request.onreadystatechange = callback;
  request.open("GET", "/calculate?value=" + enteredValue, true);
  request.send(null);
}

function callback() {
  if (request.readyState == 4) {
    if (request.status != 200) {
      document.outputfield.value = "Error: " + request.status;
      return;
    }
    var responseValue = request.responseText;
    document.outputfield.value = responseValue;
  }
}

</script>

<input type="text" name="entryfield">
<input type="button" onclick="calculate()" value="Double">
<input type="text" name="outputfield">

When the user presses the "Double" button, an AJAX request is sent to a servlet, passing the value the user entered in the "entryField" text field. When the server responds, the text in the response is displayed in the "outputField" text field. If the server didn't respond successfully, we display an error message in "outputField" containing the error code.

Starting a Test Page

Let's try to write a Test Page for our code:

<script language="javascript" src="/path/to/calculate.js"></script>
<script language="javascript">
function testClickCalculate() {
  document.entryfield.value = "5";
  calculate(); //but wait - we don't have a server
  //now what?
}
</script>

<input type="text" name="entryfield">
<input type="text" name="outputfield">
</body>

Hmm - how do we proceed? As things are, when we run our test, our request will get sent off to a server that isn't running. We don't have enough control over our environment to continue with the test.

So, how can we test AJAX?

The most important thing to bear in mind is that we are trying to write unit tests for our JavaScript - tests that exercise just a unit of our JavaScript code at a time. So we certainly don't want to bring a server into the picture - that's way out of scope for our JavaScript unit tests. Instead, what we want to do is insulate ourselves from the machinery of the request/response server interaction. The typical point at which we set up our insulation is at the level of the XmlHttpRequest: rather than a real request, we will use a mock version in our test - a pretend version of the request that we control.

Testing the request

Our first task, then, is to set things up so that our test uses a mock request and our code uses a real one:

function calculate() {
  ...
  request = createRequest();
  ...
}

function createRequest() {
  if (window.XMLHttpRequest)
    return new XMLHttpRequest();
  else
    return new ActiveXObject("Microsoft.XMLHTTP");
}

but in our Test Page, we implement createRequest differently. JsUnit comes with a library called jsUnitAjax.js, which contains a mock implementation of XmlHttpRequest.

<script language="javascript" src="/path/to/jsunit/lib/jsUnitAjax.js"></script>

function createRequest() {
  return new MockXmlHttpRequest();
}

Our Test Page's implementation overrides the real implementation of createRequest. Good: now we are able to call calculate without worrying about a real request getting sent to the server. Let's go back and continue with our test.

function testClickCalculate() {
  document.entryfield.value = "5";
  calculate();
  assertEquals("GET", request.method);
  assertEquals("/servlet?value=5", request.url);
  assertTrue(request.isAsync);
  assertTrue(request.sendCalled);
  assertNull(request.data);
  assertEquals(callback, request.onreadystatechange);
}

Notice that we're testing that calling calculate() sends the request, and how the request gets set up - its method, its URL, etc - by examining the mock request. We also verify that the correct callback method has been set up for when the server responds. We aren't using a real server, and we don't care (in this test) about a response.

Testing the response

So, that's half the story. How about testing the response? We need to simulate the server responding to the request. We've already tested that the correct callback is set up; let's take advantage of that now.

function testValidServerResponse() {
  request = new MockXmlHttpRequest();
  request.readyState = 1;
  callback();
  assertEquals("", document.outputfield.value);

  request.readyState = 2;
  callback();
  assertEquals("", document.outputfield.value);

  request.readyState = 3;
  callback();
  assertEquals("", document.outputfield.value);

  request.readyState = 4;
  request.status = 200;
  request.responseText = "50";
  callback();
  assertEquals("50", document.outputfield.value);
}

We go through each readyState, ensuring that nothing happens until state 4. For state 4, we give the mock request a status of 200 and a responseText of "50", and then verify that calling callback() populates the outputfield correctly. Notice how we've tested just the response logic, without using a real server and without the need to set up a meaningful request.

Simulating a server-side error

We have one more test - we need to test what happens when the server responds unsuccessfully:

function testInvalidServerResponse() {
  request = new MockXmlHttpRequest();
  request.readyState = 4;
  request.status = 500;
  callback();
  assertEquals("Error: 500", document.outputfield.value);
}

This time we give the mock request a status of 500, and we verify that the output field contains the expected error message.

LABS
Taming JavaScript in practice: event handlers

Suppose we have some behavior attached to a button's onclick event: when clicked, the button should append "foobar" to the value in the text field with ID "output_field". We might do it like this:

<input type="text" id="output_field">
<button onclick="var textField = document.getElementById('output_field'); var currentValue = textField.value; textField.value=currentValue + 'foobar';">

Inline event handler code such as this is extremely common. It's easy to write, but it's not testable, reusable, or readable, and it's mixed up in the HTML world. The way it is currently, it's hard to think of it as code that can be refactored, added to, abstracted, generalized, etc. Of course, this is a contrived, simple example, and if it were real code, probably not worth worrying too much about. However, we can use it to demonstrate some techniques that we can apply to real-world situations.

Extracting the handler to a function

Let's attack it by considering it from the point of view of testability with JsUnit; very often this can the best way to move forward because it creates a second client to the code that is relatively independent of the HTML DOM. The first step is to extract the onclick event into a function, rather than having it inline:

<script language="javascript">
  function appendFoobar() {
    var textField = document.getElementById("output_field");
    var currentValue = textField.value;
    textField.value = currentValue + "foobar";
  }
</script>

<input type="text" id="output_field">
<button onclick="appendFoobar()">

Notice that even ignoring testability, this is a dramatic improvement. First, we don't a fragment of JavaScript floating around in an HTML element. Second, we have a name for our behavior (appendFoobar) that makes the code more readable: it's now much clearer that clicking the button should write the current date. Third, we can now reuse this code from more than just our onclick handler.

Writing a test page

The second step is to move our function to an external .js file, say appender.js, so that we can write a Test Page:

<script language="javascript" src="appender.js"></script>

<script language="javascript">
function testAppendFoobar() {
  assertEquals("initialvalue", document.getElementById("output_field"));
  appendFoobar();
  assertEquals("initialvaluefoobar", document.getElementById("output_field"));
}
</script>

<input type="text" id="output_field" value="initialvalue">

Our test is for our extracted function: our test, rather than the button element, calls our extracted function.

Injecting DOM dependencies

Now that we have a green test, and code that we can actually read, we might want to consider the following refactoring. The code and test both go out and grab an element from the DOM with a certain ID. The code would be more self-contained and reusable if rather than going out and finding the DOM element, we instead passed it in to appendFoobar. That is, we could inject the dependency on the DOM element:

function appendFoobar(textField) {
  var currentValue = textField.value;
  textField.value = currentValue + "foobar";
}

function testAppendFoobar() {
  var textField = document.createElement("input");
  textField.value="initialvalue";
  appendFoobar(textField);
  assertEquals("initialvaluefoobar", textField.value);
}

<button onclick="appendFoobar(document.getElementById('output_field'))">

Extracting an object

Let's do one more refactoring: objectifying our code. Obviously, at this point our simple example doesn't warrant this refactoring, but let's keep going to illustrate the point. We'll use prototype.js to keep things simple:

Appender.prototype = {
  initialize: function(textField) {
    this.textField = textField;
  },

  appendFoobar() {
    var currentValue = this.textField.value;
    this.textField.value = currentValue + "foobar";
  }
}

function testAppender() {
  var textField = document.createElement("input");
  textField.value="initialvalue";
  var appender = new Appender(textField);
  appender.appendFoobar();
  assertEquals("initialvaluefoobar", textField.value);
}

<button onclick="new Appender(document.getElementById('output_field')).appendFoobar()">

Summary

Our code has come a long way from being an inline event handler, muddled up with HTML code. In its new form, it's the kind of code that many developers are more comfortable working with. By aggressively refactoring even simple event handlers with these techniques, we can make working with our JavaScript a far more pleasant experience.

LABS
Taming JavaScript

The explosion of client-side JavaScript in Web 2.0 applications has taken many developers by surprise. I've often found that more senior members on web development teams shy away from JavaScript coding, preferring the known quantity (and perceived purity) of server-side development. After all, isn't JavaScript that flaky, inconsequential language that we used to use to make pretty pull-down menus, but that can't be relied on for any serious purpose? Since when did it become something that I can't leave to my UI designer? Can't I just Google for a script kiddy's website any more? Do I really have to start taking JavaScript seriously? Well, yes. These days, it's becoming inevitable that the majority of the team comes into contact with client-side JavaScript. But still some of us resist it, largely due to painful past experiences of long nights spent trying to get browser X to work the same as browser Y.

As a consequence, I consistently observe two patterns over the course of a project. First, the client-side effort doesn't get the benefits of the skill and experience held by seasoned object-oriented developers. Instead the JavaScript code is left to newer, less experienced members of the team; the rigorous practices that the more senior members of the team usually insist on aren't advocated for to the same degree on the client side. Second, because of the fear of JavaScript, opportunities to make the application slicker, more user-friendly and generally more modern are missed.

I don't mean to downplay the difficulty of JavaScript coding. There's no doubt about it: it's eccentric, it's not consistent between browsers, it's slow where you don't expect it, it does objects in a weird way, and the list goes on. But here's where we can turn the situation on its head. What does our experience tell us about how to attack a difficult area in our code? It certainly doesn't tell us to ignore it and hope it works out in the end. No, it tells us to shine a light on the painful area and apply our development practices even more strictly than usual: test-drive it, cover it with unit and functional tests, aggressively refactor it, separate concerns, extract the right objects, apply design patterns where they can help, and so on.

What I've seen work when it comes to JavaScript is to fight fire with fire. Rather than responding to the difficulties of JavaScript by shying away from it and rationalizing a lack of quality in our client-side code, we can choose to react by applying our practices more strictly, not less. We can ask ourselves how to better test their JavaScript, how to expose complexity more clearly, how to objectify concepts more naturally. We can break our JavaScript into layers, and apply typical MVC patterns as we might do in server-side Java or Ruby on Rails code. We can abstract our AJAX requests and responses in order to better simulate them in our tests. We can run our tests in a continuous build on all our target browser/platform combinations. Why not try to hold our JavaScript to the same standards as any other part of our code? It's not always easy, and it certainly takes practice and strict discipline. I've found that the learning curve is steeper and longer than with other languages. But I've also found that there's really no reason why we can't be as rigorous with our client-side development as we are anywhere else in our codebase as. We end up with all the usual benefits: better stability, fewer bugs, more malleability.

Getting started

Amongst other topics, over the next few weeks I'll be posting concrete ideas for ways to approach JavaScript development. Most of them will center around JsUnit, because in my experience it's the introduction of unit tests and test-driving that drive the most dramatic improvements in not only the software but how we think about our work.

So, what does it look like when a team attacks JavaScript in this way? As someone who has been through his fair share of pain coding JavaScript, it's thrilling to observe. I've seen teams at Pivotal Labs take a more disciplined and rigorous approach to JavaScript than I could have imagined even a couple of years ago. And the best part is that besides the benefits I already mentioned, there's a huge payoff to all this added discipline: rather than being afraid of JavaScript development, we sometimes enjoy it and look forward to it. It's simple, really: JavaScript is hard, so let's throw everything we know at the problem. I've found that if we do, we can tame JavaScript to the point where our progress becomes as predictable as we expect in the rest of the codebase.