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

Let us know how we can contact you.

Thank you!

We'll respond shortly.

  • Blog Navigation
Better Javascript testing through ScrewUnit

The following is an excerpt of ScrewUnit’s new copious documentation:

Writing Good Tests

A great test maximizes these features:

  • it provides documentation, explaining the intended functioning of the system as well as how the source code works;
  • it supports ongoing development, as you bit-by-bit write a failing test and make it pass;
  • it supports later refactorings and prevents regression as you add other features;
  • and it requires little modification as the implementation of the system changes, especially changes to unrelated code.

This section focuses principally on tests as documentation. To provide documentation, as well as support future modification, a test should be readable and well organized. Here are some recommendations on how to do just that.

Use Nested Describes to Express Context

Often, when you test a system (a function, an object), it behaves differently in different contexts. Use nested describes liberally to express the context under which you make an assertion.

describe("Caller#prioritize", function() {
  describe("when there are two callers in the queue", function() {
    describe("and one caller has been waiting longer than another", function() {

In addition to using nested describes to express context, use them to organize tests by the structural properties of your source code and programming language. In Javascript this is typically prototype and function. A parent describe for a prototype contains nested describes for each of its methods. If you have cross-cutting concerns (e.g., related behavior that spans across methods or prototypes), use a describe to group them conceptually.

describe("Car", function() {
  describe("#start", function() {

  describe("#stop", function() {

  describe("callbacks", function() {
    describe("after_purchase", function() {

  describe("logging", function() {

In this example, one parent describe is used for all Car behavior. There is a describe for each method. Finally, cross-cutting concerns like callbacks and logging are grouped because of their conceptual affinity.

Test Size

Individual tests should be short and sweet. It is sometimes recommended to make only one assertion per test:

it("chooses the caller who has been waiting the longest", function() {
  expect(Caller.prioritize()).to(equal, caller_waiting_the_longest);

According to some, the ideal test is one line of code. In practice, it may be excessive to divide your tests to be this small. At ten lines of code (or more), a test is difficult to read quickly. Be pragmatic, bearing in mind the aims of testing.

Although one assertion per test is a good rule of thumb, feel free to violate the rule if equal clarity and better terseness is achievable:

it("returns the string representation of the boolean", function() {
  expect($.print(true)).to(equal, 'true');
  expect($.print(false)).to(equal, 'false');

Two tests would be overkill in this example.

Variable Naming

Name variables descriptively, especially ones that will become expected values in assertions. caller_waiting_the_longest is better than c1.

Dividing code between tests and befores

If there is only one line of setup and it is used in only one test, it may be better to include the setup in the test itself:

it("decrements the man's luck by 5", function() {
  var man = new Man({luck: 5});

  expect(man.luck()).to(equal, 0);

But in general, it’s nice to keep setup code in before blocks, especially if the setup can be shared across tests.

describe('Man', function() {
  var man;
  before(function() {
    man = new Man({luck: 5});

  describe('#decrement_luck', function() {
    it("decrements the luck field by the given amount", function() {
      expect(man.luck()).to(equal, 2)



It is ideal, if there is any chance that your preconditions are non-obvious, to make precondition asserts in your test. The last example, were it more complicated, might be better written:

it("decrements the luck field by the given amount", function() {
  expect(man.luck()).to(equal, 5);

  expect(man.luck()).to(equal, 2)

Whitespace, as seen here, can be helpful in distinguishing setup and preconditions from the system under test (SUT) and its assertions. It is nice to be consistent in your use of whitespace (e.g., “always follow a group of preconditions by a newline”). But it is better to use whitespace as makes the most sense given the context. As with everything in life, do it consciously and deliberately, but change your mind frequently.

Behavioral Testing

Behavioral testing, that is, asserting that certain functions are called rather than certain values returned, is best done with closures. The dynamic nature of JavaScript makes mocking frameworks mostly unnecessary.

it("invokes #decrement_luck", function() {
  var decrement_luck_was_called = false;
  man.decrement_luck = function(amount) {
    decrement_luck_was_called = true;

  expect(decrement_luck_was_called).to(equal, true);

Extensive Documentation for ScrewUnit is now available. Download it here:

  • Parker Thompson

    Nice lecture on how to write better tests. Now, where’s the documentation :)?

  • Andy Kent

    I’m loving this!
    I felt a bit inspired so went away and knocked this up…

    it’s a JavaScript version of the RSpec mocking and stubbing functionality, it’s coming along well and best of all it plugs very nicely into your framework. :)

    I really recommend you check it out. Maybe we should even join forces? Feel free to mail me if you have any thoughts.

  • Nick Kallen

    Andy — Your stuff looks great. I’d like to provide better hooks so that your mocking framework can integrate without latching on to the Matchers object. I’ll get to this after RailsConf!

  • Have you tested ScrewUnit on MSIE? I really enjoy it, but my specs break in a strange way in IE (no output if a test has failed / suceeded, just a blank page with roman numbers) and this is a bit of a deal-breaker, as one of the things I want to test is consistency across browsers… It could be also the fault of my particular specs, I didn’t have the time to investigate it futher…

  • Nick Kallen

    Hi Stiff,

    Screw.Unit only supports Firefox and Safari at the moment, sorry. IE support will happen in the next release, in a week or so.



    When are we going to realize that *we* as developers have the power of choice. It is us who controls market share.

    *SORRY* This application doesn’t support that browser, it has been determined for the best possible experience in factors of reliability, security, and service to our shared experience that sub-standard technology that is invested in market share and profit – not usability – needs to be dropped. * I realize this sounds bitter and mal adjusted – it is still true.*

    It takes informing, position and facts to educate a community. Building a piece of software that educates and holds the users hand will take engineers that can educate, speak, guide, learn and elucidate users in a way that removes mystery and concentrates on practicality.

  • that said, i do check ie7, firefox and safari.
    the people at opera are in denial and need to concentrate on the mobile market.
    safari has some brilliant javascript engines that they need to focus on and firefox should stop being a monolithic mass of code.

  • Sam

    With regard to, “my specs break in a strange way in IE (no output if a test has failed / suceeded, just a blank page with roman numbers),” my tests are doing this still. How do I upgrade to the release version that has the fix for ie?

  • Can Screw Unit be run from ant? (I’ve been asked by a dev team I coach).

    In addition any hope of IE support?

Share This