Two Guys Arguing

QUnit-CLI: Running QUnit with Rhino

Posted in git, javascript, software testing by benjaminplee on 11.26.10

Rhino - wikimediaPreviously I talked about wanting to run QUnit outside the browser and about some issues I ran into.  Finally, I have QUnit running from the command line: QUnit-CLI

After a good deal of hacking and a push from jzaefferer, I gotten the example code in QUnit-CLI to run using Rhino and no browser in sight.  This isn’t a complete substitute for in-browser testing, but makes integration with build servers and faster feedback possible.

/projects/qunit-cli/js suite.js
PASS - Adding numbers
FAIL - Subtracting numbers
PASS|OK|subtraction function exists|
FAIL|EQ|Intended bug!!!|Expected: 0, Actual: -2
PASS - module without setup/teardown (default)
PASS - expect in testPASS - expect in test
PASS - module with setup
PASS - module with setup/teardown
PASS - module without setup/teardown
PASS - scope check
PASS - scope check
PASS - modify testEnvironment
PASS - testEnvironment reset for next test
PASS - scope check
PASS - modify testEnvironment
PASS - testEnvironment reset for next test
PASS - makeurl working
PASS - makeurl working with settings from testEnvironment
PASS - each test can extend the module testEnvironment
PASS - jsDump output
PASS - raises
PASS - mod2
PASS - reset runs assertions
PASS - reset runs assertions2
----------------------------------------
PASS: 22  FAIL: 1  TOTAL: 23
Finished in 0.161 seconds.
----------------------------------------

The first hurdle was adding guards around all QUnit.js’s references to setTimeout, setInterval, and other browser/document specific objects.  In addition I extended the test.js browser checks to include all of the asynchronous tests and fixture tests.  Finally I cleaned up a bit of the jsDump code to work better with varying object call chains.  My alterations can be found on my fork here.

The second hurdle was getting QUnit-CLI using my modified version of QUnit.js and adjusting how Rhino errors are handled.  Adding a QUnit submodule to the QUnit-CLI git repository easily fixed the first (I previously posted my notes on git submodules and fixed branches).  QUnit.js’s borrowed jsDump code is used to “pretty-print” objects in test messages.  jzaefferer ran into an issue when running QUnit’s own tests through QUnit-CLI resulting in the cryptic error:

js: "../qunit/qunit.js", line 1021: Java class "[B" has no public instance field or method named "setInterval".
at ../qunit/qunit.js:1021
at ../qunit/qunit.js:1002
at ../qunit/qunit.js:1085
at ../qunit/qunit.js:1085
at ../qunit/qunit.js:1085
at ../qunit/qunit.js:110
at ../qunit/qunit.js:712 (process)
at ../qunit/qunit.js:304
at suite.js:84

It turns out that errors objects (e.g. ReferenceError) throw in Rhino include an additional property of rhinoException which points to the underlying Java exception that was actually thrown.  The error we saw is generated when the jsDump code walks the error object tree down to a byte array off of the exception.  Property requests executed against this byte array throw the Java error above, even if they are done part of a typeof check, e.g.

var property_exists = (typeof obj.property !== 'undefined');

Once I figured this out, I wrapped the object parser inside QUnit.jsDump to properly pretty-print error objects and delegate to the original code for any other type of object.

...
var current_object_parser = QUnit.jsDump.parsers.object;
QUnit.jsDump.setParser('object', function(obj) {
  if(typeof obj.rhinoException !== 'undefined') {
    return obj.name + " { message: '" + obj.message + "', fileName: '" + obj.fileName + "', lineNumber: " + obj.lineNumber + " }";
  }
  else {
    return current_object_parser(obj);
  }
});
...

With these changes we have a decent command line executable test suite runner for QUnit.  With a bit more work QUnit-CLI will hopefully be able to print Ant/JUnit style XML output and/or include stack traces when errors bubble out of test code.

Tagged with: , , , ,

Tie Git Submodules to a Particular Commit or Branch

Posted in git, software development by benjaminplee on 11.14.10

While working on getting QUnit-CLI cleaned up and refactored a bit, I realized I needed to tie the example code in the Git repository to a particular version of QUnit.js (those guys are making changes too fast for me to keep up).  I have used SVN:externals prevsiously so Git submodules seemed like an obvious solution.  A single submodule should allow me to keep QUnit-CLI inherently pointing to a particular revision of QUnit.js without requiring me to seperately document which version I was testing against.

The man page for git-submodule as well as the Git Book chapter on Submodules do a good job of documenting the command with some simple examples, but none that were 100% clear for my needs.  In addition, I need my Git submodule to point to a specific commit (or branch) so that everyone cloning my code consistently can run my examples w/o fear that a new commit on HEAD will break something.

Step 1 : Add the submodule

Once the module is checked out, I need to add the QUnit submodule.  First grab the GitHub url for my QUnit fork (eventually this will be replaced with the main QUnit repo) and execute the “add” command from within your local repository root.

git submodule add git://github.com/asynchrony/qunit.git qunit

Afterward there will be two modified and staged objects in your repo: .gitmodules will contain the submodule’s local path and source URL and a new folder named qunit which contains a full clone of your source repository.

** Fraser Speirs has a good writeup on what is going on behind the scenes with the Git internals and how the key to all of this is in the index files of each repo and the modes the changes are committed with. **

Step 2 : Fix the submodule to a particular commit

By default the new submodule will be tracking HEAD of the master branch but will NOT be updated as you update your primary repo.  In order to change the submodule to track a particular commit or different branch change directory to the submodule folder and switch branches just like you would in a normal repo.

git checkout -b dev_branch origin/dev_branch

Now the submodule is fixed on the development branch instead of HEAD of master.  Just easily I could set it to specific commit or tag.

Step 3 : Commit everything

Now from your primary repository you still have two modified objects: .gitmodules file and qunit folder.  Commiting these changes will persist the new submodule tracking your desired branch.

Step 4 : Clone Recursive

The next time you (or someone else) clones this repo, they will need to do one of two things.

A) Add the –recursive flag to their git clone command

git clone REPO_URL --recursive

B) manually initialize and the submodules after the clone

git clone REPO_URL
git submodule update --init --recursive
Tagged with: , ,

hold my code for a second…

Posted in git by youngnh on 01.25.10

add, stash, edit, apply and reset

This is mostly a note on how I work with git. A lot of people used to subversion wonder why I’m so enamored of Linus Torvald’s latest project and I usually only explain enough of it to convince them that git is an elaborate and complicated tool for replicating a subversion workflow. This is a good example of a situation in which svn would fail you.

I try as much as possible to create a new branch every time I decide to work on a new unit of work. Oftentimes, I will just absent-mindedly start coding and be 4 or 5 commits deep before realizing that I forgot to branch (which is a situation git has tools to fix as well), but for this particular stretch of coding I was on a clean branch without any untracked files.

Shortly after starting, I found myself with 4 classes, none of which compiled. In a minimalist vein, at home I work with only emacs and ant when hacking on Java code. ant can cause a bit of scroll blindness when your code has compile errors, and the situation is only exacerbated when you don’t quite get Java generics.

One class was named WinLogicFactory, and it’s functionality was the end goal of this branch. The other 3 classes were support classes. They had resuable, general-purpose functionality that WinLogicFactory would use, but contained nothing specifically related to the application I was writing. I stole the idea of them from Haskell and the classes were named Either, Left and Right.

$ git status
# On branch winlogic_factory
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	src/com/twoguys/rps/WinLogicFactory.java
#	src/com/twoguys/util/Either.java
#	src/com/twoguys/util/Left.java
#	src/com/twoguys/util/Right.java

Before Either, Left and Right were fixed and compiling, I couldn’t fix WinLogicFactory, which would use them. A bit counter-intuitively I added WinLogicFactory to the index. This allowed me to stash my current index. That left only the generic classes in my working tree:

$ git add src/com/twoguys/rps/WinLogic.java
$ git stash
$ git status
# On branch winlogic_factory
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	src/com/twoguys/util/Either.java
#	src/com/twoguys/util/Left.java
#	src/com/twoguys/util/Right.java

Once I got Either, Left and Right compiling I could now start working on WinLogicFactory, so git stash apply restored the index with my broken factory in it. I had some more work to do to get it compiling and just to convince myself that I had really gotten my workspace back to it’s original state, so I ran a git reset, which effectively pulled any uncommitted changes out of staging in the index.

$ git stash apply
$ git reset
$ git status
# On branch winlogic_factory
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	src/com/twoguys/rps/WinLogicFactory.java
#	src/com/twoguys/util/Either.java
#	src/com/twoguys/util/Left.java
#	src/com/twoguys/util/Right.java

At this point, I could fix WinLogicFactory without worrying about simultaneous errors from Either, Left and Right.

Things that are worth noting:

  • staging content in git’s index is not simply another step that you have to perform before you can commit files you’ve edited. It’s how you tell git about any file you care about.
  • git can manipulate code that isn’t committed. commits are merely a little extra information attached to otherwise generally useful structures that git was already creating for you.
Tagged with: ,
Follow

Get every new post delivered to your Inbox.