Relief is a framework built on top of Google's Closure tools. Its purpose is to enable quick iteration on a project by providing infrastructure and architectural compoents such as a navigation manager and RPC service.

You can find the source code and documentation at

Tuesday, July 19, 2011

Request: Run the Tests!

It was important to me to provide significant test coverage of the various Relief components.  At 142 tests, I feel this goal was pretty well met.  I have confirmed that these tests pass on:

Mac OS X 1.6.1
  • Chrome 14
  • Firefox 5.0, 5.0.1
  • Safari 5.0.5
  • Opera 11.50
Windows Vista
  • Chrome 14
  • Internet Explorer 9
Windows XP
  • Chrome 14
  • Opera 11.50
  • Firefox 4.0, 5.0.1
  • Safari 5.0.5
  • Internet Explorer 8.0
Android 3.1
  • Built-in Android Browser

With your help, I would like to expand this list.  With the navigation manager in particular, I would be much happier with a broader browser and platform spread.

Running the Tests

If you're willing to help out by running the tests on a platform that isn't listed above, or even by confirming one of the listed platforms, doing so is easy.  Relief's "deps.js" file expects that Closure Library is checked out into a folder called "closure-library/", and that Relief is checked out into the same parent directory under the name "relief/".  To run the tests from a blank slate:

cd /devel (or wherever you like to do your development)
svn checkout closure-library
svn checkout relief
python -m SimpleHTTPServer

The above navigates to whatever directory you like, checks out the latest Closure Library revision, checks out the latest Relief revision, and then runs an HTTP server in the current directory.  You can test against whatever version you like as long as the Library directory is called "closure-library/".  Likewise, Relief expects that its root directory is "relief/".

Once you have the latest revisions and the HTTP server is running, point your browser to http://localhost:8000/relief/relief/all_tests.html.  You should see a multi-test runner like you do for the Closure Library tests (  Click Start and watch them go.  If you notice any tests fail, please create an issue at  Please provide as much information as you can think of, specifically:
  • Browser
  • Operating System
  • Closure Library revision
  • Relief revision
  • Specific error or test failure messages
  • The name of the test(s) that failed
The Python server that serves the test files can sometimes get jammed up when a lot of files are requested at once, as is the case when executing these test scripts for the first time.  Refresh the page a couple times so that most of the files will end up being cached, and only the ones that didn't make it the first time will get requested.  If you notice any test failures on the multi-test runner, click the "Run individually" link for that test page and see if they pass on their own.

Internet Explorer 8

When I ran the tests on IE 8, none of the test cases auto-discovered the test functions, so all tests failed.  After some poking around, I found that goog.testing.TestCase class uses something called the "RuntimeObject" (['RuntimeObject']) instead of searching directly on  testcase.js explains this by saying "...on IE we look in the little known RuntimeObject which holds references to all globals". This is not a problem when running the Closure Library tests because they declare their tests as simple function statements:
function testLibrary() {
  assertNotUndefined("'goog' not loaded", goog);
In Relief, tests are declared a little differently to allow for more easily-read test names:
var $ = window;
$['test getCommandID returns the given ID'] = function() {
  var cmd = createCommand();
  assertEquals('getCommandID returned an incorrect ID.',
               commandID, cmd.getCommandID());
This works well in all browsers (even IE9) except IE8. It turns out that, for some reason, the RuntimeObject does not pick up the global function properties defined on the "window" object. If the test declarations are changed to simple function expressions, they are properly picked up. I ran the tests on IE8 by temporarily changing the goog.testing.TestCase.getGlobals function to simply return This works just fine.

Wednesday, July 6, 2011

How I Found Relief

In early 2010, I re-discovered my love of web development, and picked up my dusty HTML/CSS/Javascript skills and began writing a fairly ambitious web app. Then, I discovered the Closure Tools. I quickly scrapped what I had and started over. Closure was great! A month or so and a few books later, I truly started understanding all the nuances of the language that I hadn't learned 5 years prior, when I had last done any real web development. Again, I started over and really made some good headway.

Later on, I had an idea for another app that I thought might be useful, so I began to write it. In the process, I ended up copying, pasting, and modifying a lot of the code from that previous one into this project. Then I started a third project. Anyone who's programmed for very long knows how this goes: "Hey, these things would probably be a great basis for a framework." So my third project turned into Relief. I spent a lot of time trying to generalize a few core components: Navigation, RPC, and Authentication/Authorization. In the end, I had what I believed to be a good mix of true boiler plate eradication and an API that would allow users to extend the functionality of these components in really powerful ways.

Relief is written in true Closure style. Type checking and JSDoc are woven throughout the source code. Each component's API defines specific classes and interfaces where developers can plug in their extension points while not having to worry about making another XHR request, listening for ONHASHCHANGE events, or parsing cookies for authentication details when they want to know the user's first name.

It's true that Relief is verbose compared to the JQuery style of doing things, just as Closure is. However, I believe there is true power in this verbosity. With the RPC Service, yes, you have to write a Command class, but you automatically get all the infrastructure for making the request, handling the response, detecting failures, and real in-app caching for free.

Try it. I think you might like it. If there are points you think could be better, by all means let me know. I'd love to hear from you.