Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Screw.Unit, a new JS testing framework, version 0.1

Pivotal Labs
Monday, April 7, 2008

Screw.Unit is a Behavior-Driven Testing Framework for Javascript written by Nathan Sobo and Nick Kallen. It features nested describes. Its goals are to provide:

  • a DSL for elegant, readable, organized specs;
  • an interactive runner which can execute focused specs and describes;
  • and brief, extensible source-code.

What it is

Test Runner

The testing language is inspired by JSpec (and Rspec, obviously). Consider,

describe("Matchers", function() {
  it("invokes the provided matcher on a call to expect", function() {
    expect(true).to(equal, true);
    expect(true).to_not(equal, false);
  });
});

A key feature of Screw.Unit are nested describes and the cascading before behavior that entails:

describe("a nested describe", function() {
  var invocations = [];

  before(function() {
    invocations.push("before");
  });

  describe("a doubly nested describe", function() {
    before(function() {
      invocations.push('inner before');
    });

    it("runs befores in all ancestors prior to an it", function() {
      expect(invocations).to(equal, ["before", "inner before"]);
    });
  });
});

The Screw.Unit runner is pretty fancy, supporting focused describes and focused its:

Focused Runner

You can download the source from Github. Please see the included spec (screwunit_spec.js) to get up and running.

Implementation Details

Screw.Unit is implemented using some fancy metaprogramming learned from the formidable Yehuda Katz. This allows the describe and it functions to not pollute the global namespace. Essentially, we take the source code of your test and wrap it in a with block which provides a new scope:

var contents = fn.toString().match(/^[^{]*{((.*n*)*)}/m)[1];
var fn = new Function("matchers", "specifications",
  "with (specifications) { with (matchers) { " + contents + " } }"
);

fn.call(this, Screw.Matchers, Screw.Specifications);

Furthermore, Screw.Unit is implemented using the Concrete Javascript style, which is made possible by the Effen plugin and jQuery. Concrete Javascript is an alternative to MVC. In Concrete Javascript, DOM objects serve as the model and view simultaneously. The DOM is constructed using semantic (and visual) markup, and behaviors are attached directly to DOM elements. For example,

$('.describe').fn({
  parent: function() {
    return $(this).parent('.describes').parent('.describe');
  },
  run: function() {
    $(this).children('.its').children('.it').fn('run');
    $(this).children('.describes').children('.describe').fn('run');
  },
});

Here two methods (#parent and #run) are attached directly to DOM elements that have class describe. To invoke one of these methods, simply:

$('.describe').fn('run');

Bind behaviors by passing a hash (see the previous example). Using CSS3 selectors and cascading to attach behaviors provides interesting kind of multiple inheritance and polymorphism:

$('.describe, .it').fn({...}); // applies to both describe and its
$('.describe .describe').fn({...}); // applies to nested describes only

A typical Concrete Javascript Application is divided into 4 aspects:

  • a DOM data model,
  • CSS bound to DOM elements,
  • asynchronous events bound to DOM elements (click, mouseover), etc.,
  • synchronous behaviors bound to DOM elements (run and parent in the above example).

The Concrete style is particularly well-suited to Screw.Unit; to add the ability to run a focused spec, we simply bind a click event to an it or a describe, which runs itself:

$('.describe, .it')
  .click(function() {
    $(this).fn('run');
  })

Anyway, more details about Effen / Concrete Javascript in a later post.

Extensibility

Screw.Unit is designed from the ground-up to be extensible. For example, to add custom logging, simply subscribe to certain events:

$('.it')
  .bind('enqueued', function() {...})
  .bind('running', function() {...})
  .bind('passed', function() {...})
  .bind('failed', function(e, reason) {...})

Thanks to

  • Nathan Sobo
  • Yehuda Katz
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

10 Comments

  1. Brian Takita says:

    Very nice. The JsSpec runner can also be (easily?) adapted to support Screw.Unit. I’d like to help out with that.

    April 7, 2008 at 6:36 am

  2. Brian Takita says:

    I mean the JsSpec server, which could use a blog post too. :)

    April 7, 2008 at 6:41 am

  3. Nuno Job says:

    So the new thing on js world is to copy ruby?

    rspec all over

    You guys should learn ruby instead.

    April 7, 2008 at 8:17 pm

  4. Steve C says:

    Great point Nuno we’ll get right on that.

    April 7, 2008 at 11:29 pm

  5. Nuno Job says:

    Can I sense some kind of irony in that post? :P

    April 8, 2008 at 7:15 am

  6. Dav says:

    Nice! Looking forward to trying it out.

    Love the name too.

    April 8, 2008 at 3:39 pm

  7. qwe says:

    Prototype already has very similar testing framework (made a few years back). It would be great see what’s different from it, except Screw.Unit is jQuery based, for us to get it started and get excited about it.

    April 10, 2008 at 6:55 am

  8. nick kallen says:

    qwe – prototype has a testing framework, and it supports bdd style assertions. there is also jspec and jsspec, both javascript bdd style testing frameworks.

    jspec and screw.unit bear some similarity in their closure-based testing techniques which is fundamentally different and much more flexible and powerful than the hash technique of jsspec and prototype. screw.unit features, in particular, nested cascading describes which is imo one of the killer features of rspec; if bdd is just about saying “should” rather than “assert”, then bdd is nothing at all.

    Screw.Unit is designed to be the testing framework for advanced javascript users and testers. If you use rspec you know how important nested describes are. If you are a sophisticated javascript user, you know how important closures are for idiomatic javascript programming. In general, I have very little nice to say about prototype so I’ll stop talking now.

    April 10, 2008 at 7:02 pm

  9. Dr Nic says:

    There is also http://jsunittest.com which is a clone of prototypejs’ test framework without the prototype dependencies.

    April 10, 2008 at 10:15 pm

  10. TJ Holowaychuk says:

    Hey hey, just letting everyone know about some great recent advances in JSpec, moving ahead approaching a 1.0 release, lots of new goodies !

    http://github.com/visionmedia/jspec/tree/master

    February 23, 2009 at 6:11 am

Add New Comment Cancel reply

Your email address will not be published.

Pivotal Labs

Pivotal Labs

Recent Posts

  • Does the set of all sets contain itself?
  • Standup 3/8/2012
  • Standup 3/7/2012
Subscribe to Pivotal's Feed

Author Topics

riddles (1)
agile (167)
capistrano (2)
rails (26)
movember (1)
git (10)
railsdoc (1)
object-design (1)
bdd (3)
cucumber (3)
linkedin (1)
oauth (1)
ruby (17)
tdd (2)
lvh.me (1)
rails 3.1.1 (1)
selenium (6)
homebrew (1)
mysql (5)
rvm (1)
sproutcore (1)
paperclip (2)
pry (1)
amazon (1)
heroku (1)
rails3 (2)
jasmine (3)
design (3)
process (12)
productivity (8)
learning (1)
olin (1)
migrations (2)
mongodb (2)
devise (2)
javascript (13)
rubymine (4)
ipad (1)
whurl (1)
head.js (1)
pairing (2)
tools (4)
pair programming (1)
rspec (10)
rspec2 (1)
ruby19 (1)
incubation (3)
startup (5)
api (1)
presenter (1)
vanna (1)
pivotal tracker (5)
capybara (1)
fakeweb (1)
webmock (1)
intern (1)
ruby on rails (25)
meetup (1)
textmate (1)
testing (20)
solr (4)
nyc-standup (11)
community (1)
opensource (3)
activerecord (4)
chrome (1)
mp4 (1)
activeresource (1)
flash (3)
neo4j (1)
nginx (1)
rsoc (1)
meta programming (1)
agile standup (7)
government (3)
webos (4)
xss (1)
jquery (1)
bundler (2)
ci (3)
gems (5)
postgresql (1)
geminstaller (1)
gemcutter (1)
cloud (2)
rack (2)
refraction (1)
gem (5)
refactoring (1)
validations (1)
webrat (1)
engine-yard (1)
firefox (2)
jsunit (1)
mongrel (2)
thin (1)
unicorn (1)
facebook (1)
rubygems (5)
jruby (1)
actioncontroller (1)
rails 2.3 (1)
palmpre (1)
autotest (1)
mac (2)
hosting (1)
goruco (11)
database (3)
railsconf (11)
gogaruco (4)
deployment (4)
github (1)
ie (1)
ajax (1)
intellij (1)
json (1)
asset packaging (1)
polonium (1)
character encoding (1)
utf-8 (1)
test (3)
civics (1)
hpricot (1)
rake (3)
sms (1)
unicode (1)
iphone (1)
java (1)
safari (1)
memory leaks (1)
rr (3)
editor (1)
css (1)
nyc (3)
performance (5)
fun (5)
enterprise rails (1)
health (1)
new and cool (1)
general (2)
treetop (1)
errors (1)
stack (1)
trace (1)
cache (1)
cookies (1)
freesoftware (1)
conferences (1)
development (1)
driven (1)
proxy (1)
caching (1)
peertopatent (1)
languages (1)
rest (2)
rubyforge (1)
sake (1)
file (1)
upload (1)
constants (1)
osx (1)
terminal (1)
pairprogramming (2)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >