Evolving Bits

Sat Sep 28 2013

Testing Parse.com Cloud Code using Q Promises

I've been playing with Parse.com Cloud Code, and wanted to write more code offline so I didn't have to keep pushing to the cloud, plus wanted to use Test Driven Development.

I also had seen their blog post What’s so great about JavaScript Promises? and decided that was the best way to go for handling async logic.

For testing and mocking, I discovered the Q promise library which is fantastic. For a great intro listen to the 037 JSJ Promises with Domenic Denicola and Kris Kowal podcast and see Q Getting Started and Tutorial.

The problem I ran into was that the Parse.com promise library handles error-handling differently than the Promises/A+ spec (instead it follows jQuery's implementation) so then started trying to create a mock of a Parse.com promise, but this was a bit tricky and I wasn't happy with result.

Then I finally had the thought to replace the Parse.com promise implementation with Q. That way I could implement my Cloud Code with Q and also write my tests with Q.

Here's an initial experiment of using Q with Parse.com Cloud Code.

How to run: I just created a new Cloud Code project with the Parse command-line tool parse new and then grabbed q.js via an npm install q and copied q.js into the ./cloud directory.

{% gist 6747919 %}

Here's the code on gist.github.com


Tue Apr 09 2013

One Letter Repository Status for Git, Mercurial and Subversion

These days we're using a variety of version control systems and switching between them regularly.

My most used command is checking my working directory status, so I've distilled it down to a one-letter shortcut that determines which type of repository I'm in, then does an appropriate status for that system.

I just setup an alias like this:

s='~/s/s.sh'

So just type s and don't worry about which version control you're in.

{% gist 5118028 %}

Here's the code on gist.github.com


Wed Oct 24 2012

Testing JavaScript Code Running Google Closure Library using Mocha and PhantomJS (or Jasmine)

Here are several options for setting up JavaScript unit testing for code built with the Google Closure Library, albeit these options are helpful for testing a wide variety of JavaScript projects.

Google Closure Library is self-described as a "broad, well-tested, modular, and cross-browser JavaScript library."

We're using the LimeJS HTML5 game framework, which is built on this library.

Our Contestants

1. Headless testing with Jasmine 1.2

Jasmine works well. There are two approaches you can use: an HTML runner with jasmine.js, or the Ruby-based runner. Originally we were hoping to take the same approach as the Ruby-runner (with all batteries included, including easy headless testing) but using Mocha and Node.js instead to be on a full JavaScript stack. Though we ended up having to go to an HTML runner + mocha.js to get the DOM testing to work, in scenario 3 below.

In hindsight, by ending up with the HTML + JS approach in scenario 3, Jasmine and Mocha + PhantomJS are very similar approaches.

2. Mocha testing on Node.js

Mocha testing on Node.js works well (easy setup, no html test runner required), but I wasn't able to get headless DOM working. If your tests don't require DOM, this is a good way to go. One issue: It takes more effort to debug tests with breakpoints because the code is running on node.js. In the other scenarios, you can just add a debugger line and debug the tests in the browser.

3. Headless testing with Mocha and PhantomJS

Our winner: Headless testing with Mocha and PhantomJS via mocha-phantomjs allows us to use JavaScript tooling, headless DOM testing and a nice Jasmine BDD style for writing tests.

4. Testing with the Google Closure Library testing framework

You can use the Google Closure Library testing framework, which is more of a traditional JUnit style framework and not a BDD-style framework like Jasmine or Mocha. Please check out the Closure documentation for more info.

Let's Get Testing

Here's how each can be setup.

Assume you keep your tests in a my-project/spec folder and your code is under a peer my-project/scripts folder. Assume all test-related files discussed below are in the ./spec folder and that tests are kicked off via a script in that folder.

1. Jasmine

This is a personal favorite. It has all batteries included and doesn't need a separate HTML runner for DOM testing if using the Ruby Gem. We liked this approach, and tried to do it with Mocha + node.js (to get the same features as the Ruby Gem, but on a JavaScript stack) though ultimately went with Scenario 3 below.

For general setup of headless Jasmine testing, see my jasmine-headless-boilerplate repository.

Once setup, to tailor for Google Closure Library, in javascripts/support/jasmine.yml (setup by default with jasmine init) add your project's base.js and generated deps.js file to ./spec.

src_files:
    - scripts/libs/closure/closure/goog/base.js
    - scripts/deps.js

You can then just create a standard Jasmine test file with goog.require() statements at the top to bring in the module dependencies:

goog.require('the.module.I.am.testing');
goog.require('a.dependency');

describe("the.module.I.am.testing", function () {

});

2. Mocha Testing on Node.js

After setting up node.js and npm, you can create a package.json file to make it easy to setup all the dependencies by just running npm install in your ./spec folder.

If you have a script that kicks off the tests, you can optionally add that to the "scripts > tests" key like seen below so that you can just run npm test.

Also, you'll need to use the nclosure library to allow node.js to bring in dependencies via goog.require().

In ./spec create 3 files:

  • closure.json to tell nclosure library where your files are

  • package.json to setup all your node.js dependencies

  • a run script

Here are examples:

closure.json

{
  additionalDeps:['../scripts/deps.js'],
  closureBasePath:'/this/has/to/be/an/absolute/path/in/my/experience/scripts/libs/closure/'
}

It took some time to figure out the right file paths. Basically:

  • "additionalDeps" should be a relative path from where you're running the script that runs the tests. If you're running tests from a ./spec folder, and the code lives in a peer (to ./spec) ../scripts folder, use the example above.

  • However the closureBasePath only worked as an absolute path, plus you leave off the trailing /closure/goog (since often closure is in a lib/closure/closure/goog directory structure).

I assume this could be fixed with either a patch to nclosure or maybe I wasn't doing something correctly. I also tried setting this as a parameter to the actual require('nclosure').nclosure(); call at the top of the tests, but no difference. This would need to be solved to make it easy for a team to run tests locally.

package.json

{
  "name": "our-test-framework",
  "version": "0.0.0",
  "description": "## Unit Tests",
  "main": "index.js",
  "scripts": {
    "test": "sh runtests.sh"
  },
  "repository": "",
  "author": "",
  "license": "BSD",
  "dependencies": {
      "chai":"~1.3",
      "sinon": "~1.5",
      "nclosure": "~0.4",
      "mocha": "~1.6"
    }
}

runtests.sh

#!/bin/sh
./node_modules/.bin/mocha --recursive --timeout 10000 --reporter spec your/folder/to/your/specs

Here's an example test file:

require('nclosure').nclosure();

goog.require('my.module.goes.here');
goog.require('one.of.your.dependencies');

describe("my.module.goes.here test", function () {

});

3. Mocha Testing on PhantomJS (node.js not required)

This is the current winner for our specific needs. It's mainly JavaScript based, runs headless DOM tests, and supports a nice BDD syntax.

This has some additional dependencies beyond the setup above:

  • Install PhantomJS, which on OSX is as easy as brew install phantomjs via Homebrew.

  • Bring down mocha-phantomjs.coffee and the mocha-phantomjs folder from mocha-phantomjs and put those in your ./spec folder.

  • Bring in dependencies mocha.js and mocha.css from root of mocha repository

  • Bring in third-party libraries like expect.js and sinon.js used by test runner HTML below. (We started with Chai's "expect" assertion framework, but the assertion code didn't nicely pass linting, so went with the very similar expect.js)

Instead of using the ./mocha test runner, your run-script can call each test like so:

phantomjs mocha-phantomjs.coffee javascripts/mycontroller_spec.html

In addition to your test js file, you need an html file test runner to setup DOM for your tests.

Here's an example of mycontroller_spec.html:

<html>
  <head>
    <title>Unit Tests</title>
    <meta charset="utf-8">
    <link rel="stylesheet" href="../../../node_modules/mocha/mocha.css" />
  </head>
  <body>
    <div id="mocha"></div>
    <script src="../../../../scripts/libs/closure/closure/goog/base.js"></script>
    <script src="../../../../scripts/deps.js"></script>
    <script src="../../../javascripts/support/sinon-1.4.2.js"></script>
    <script src="../../../javascripts/support/mocha.js"></script>
    <script src="../../../javascripts/support/expect.js"></script>
    <script>
      mocha.ui('bdd'); 
      mocha.reporter('html');
    </script>
    <script src="mycontroller_spec.js"></script>
    <script>
      if (window.mochaPhantomJS) {
        mochaPhantomJS.run();
      } else {
        mocha.run();
      }
    </script>
  </body>
</html>

The mycontroller_spec.js test file doesn't require any special code, just using the normal goog.require():

goog.require('my.module.goes.here');
goog.require('one.of.your.dependencies');

describe("my.module.goes.here test", function () {

});

Other thoughts and ideas

  • For tests requiring DOM: Is it possible to substitute zombie.js instead of phantomjs? The main reason is that then the whole stack could be in node.js and has fewer dependencies (since it wouldn't require phantomjs and mocha-phantomjs).

  • Selenium is another option for testing code against DOM on real browsers.

References To Bookmark