Home / Blog / ruby /

Loris: Autotest for Javascript

November 6th, 2009

I’ve previously written a number of posts on javascript and autotest. Explaining how to integrate javascript lint, unit tests, and growl with the ruby Autotest project.

While this all worked, it felt a little clunky as Autotest doesn’t natively support the idea of running multiple tasks one after the other. Rather than hack at the Autotest codebase, I thought I’d get some ruby experience by rolling my own autotest-style framework. Not great for reuse of code, but a great way for me to learn :)

Loris

Loris will monitor your project and run Javascript Lint and JS Test Driver whenever a file changes, it will report the results to the command line and using Growl. If required, Loris will automatically start the JS Test Driver server and register your default browser with it.

Installing

Loris is hosted on Gemcutter, so you need to install their gem if you haven’t already.

sudo gem update --system
sudo gem install gemcutter
gem tumble

Then to install Loris, just run the following:

sudo gem install loris

Loris has no command line options, and no configuration file (at the moment). It looks for configurations files to decide which tasks to run.

Configuring Javascript Lint

To enable Javascript Lint, create a jsl.conf file in the folder where you run Loris. This should be a standard Javascript Lint config file. If you need here is an example Javascript Lint config file

You just need to specify which files Javascipt Lint should process. For example:

### Files
# Specify which files to lint
# Use "+recurse" to enable recursion (disabled by default).
# To add a set of files, use "+process FileName", "+process Folder\Path\*.js",
# or "+process Folder\Path\*.htm".
#
+process src/js/*.js
+process tests/js/*.js

If no jsl.conf file is found, the Javascript Lint task is silently skipped.

Configuring JS Test Driver

To enable JS Test Driver, create a jsTestDriver.conf file in the folder where you run Loris. This should be a standard JS Test Driver config file.

This should specify which files JS Test Driver should process, and how it connects to the JS Test Driver server. For example:

server: http://localhost:9876
 
load:
  - tests/qunit/equiv.js
  - tests/qunit/QUnitAdapter.js
 
  - src/js/*.js
  - tests/js/*.js

If no jsTestDriver.conf file is found, the JS Test Driver task is silently skipped.

To make it really simple to run JS Test Driver tests, if the server is set to run on localhost, and Loris doesn’t detect one running, it will automatically start one, and register your default browser with it.

This makes it a one step process to get automated tests up and running.

Running

To run, open a command line window, navigate to the root folder of your project, and run:

loris

Loris will run Javascript Lint, and JS Test Driver tasks (if it finds their configuration files), and will output the results on the command line.

Example output

Javascript Lint
success
All files are clean
 
0 error(s), 0 warning(s)
JS Test Driver
success
All tests pass
[PASSED] GreeterTest.testGreet
  [LOG] JsTestDriver Hello World!
[PASSED] GreeterTest.testGoodbye
[PASSED] GreeterTest.testSetName
[PASSED] GreeterTest.testSetNameAndNameParamter
[PASSED] Asserts.test OK true succeeds
[PASSED] Asserts.test Equals succeeds
  [LOG] about to call assertEquals
[PASSED] Asserts.test Same assert succeeds
[PASSED] Lifecycle.test Setup and Teardown are run, and can contain assertions
Total 8 tests (Passed: 8; Fails: 0; Errors: 0) (3.00 ms)
  Firefox 1.9.1.4 MacIntel: Run 8 tests (Passed: 8; Fails: 0; Errors 0) (3.00 ms)

Every time you make a change to a Javascript file, or a configuration file, Loris will automatically re-run Javascript Lint and JS Test Driver. So you can instant feedback on your changes.

Loris will clear the command line when re-running tasks. So the latest run is always at the top of you command line.

Loris will also report a summary of each task using Growl (if it is installed). This allows you to get quick feedback without needing to refer back to the command line on every change.

Requirements

JS Test Driver is written in Java, so you will need to have Java installed to run it.

To get Growl notifications, you will need to install either Growl for OSX or Growl for Windows. Growl for Windows requires the .NET Framework 2.0+.

Caveat

Loris is pretty limited at the moment, I just wired up the basics to get it running for a work project.

It doesn’t have any configuration options at the moment, so you have to follow it’s assumptions for now. I’m happy to add configuration options for any element as required.

Loris only comes with a few tasks (Javascript Lint, JS Test Driver, JSpec, and RSpec), but I hope to allow it have new tasks added via new gems (kind of similar to Autotest).

It comes packaged with a version of Javascript Lint, and JS Test Driver, and will use it’s own versions. It only includes the OSX and Windows versions of Javascript Lint.

If you want to modify the code, just fork the Loris github project

At 7digital we use Cucumber and Watir for running acceptance tests on some of our websites.

These tests can help greatly in spotting problems with configuration, databases, load balancing, etc that unit testing misses.

But because the tests exercise the whole system, from the browser all the way through the the database, they can tend be flakier than unit tests. Then can fail one minute and work the next, which can make debugging them a nightmare.

So, to make the task of spotting the cause of failing acceptance tests easier, how about we set up Cucumber to take a screenshot of the desktop (and therefore browser) any time a scenario fails.

Install Screenshot Software

The first thing we need to do is install something that can take screenshots. The simplest solution I found is a tiny little windows app called SnapIt. It takes a single screenshot of the primary screen and saves it to a location of your choice. No more, no less.

Tell Cucumber to Take a Screenshot When a Scenario Fails

Now we need to tell Cucumber to take a screenshot. To do so we’ll add a function to the Cucumber World that will take a screenshot if needed, and run this in the After scenario hook. To do this modify your features/support/env.rb file.

env.rb

class DefaultWorld
 
  # Screenshot directory, relative to this env.rb file
  DEFAULT_SCREENSHOT_PATH = File.expand_path(File.dirname(__FILE__) + '/../../../output/cucumber/screenshots/')
 
  # Absolute location of SnapIt
  SNAPIT_PATH = 'C:\\Tools\\SnapIt.exe'
 
  def take_screenshot_if_failed(scenario)
    if (scenario.status != :passed)
      scenario_name = scenario.to_sexp[3].gsub /[^\w\-]/, ' '
      time = Time.now.strftime("%Y-%m-%d %H%M")
      screenshot_path = DefaultWorld::DEFAULT_SCREENSHOT_PATH + '/' +  time + ' - ' + scenario_name + '.png'
      cmd = DefaultWorld::SNAPIT_PATH + ' "' + screenshot_path + '"'
      %x{#{cmd}}
    end    
  end
 
  # [...] Other DefaultWorld code here if needed
 
end
 
World do
  DefaultWorld.new
end
 
After do |scenario|
  take_screenshot_if_failed(scenario)
 
  # [...] Other After hook code here if needed  
 
end

Just modify the constants in the above code to point to the locations of SnapIt and a directory to save the screenshots too.

What the Code Does

The code will only take a screenshot if the scenario fails to pass.

It then extracts the name of the scenario, and converts it to a filename friendly string (e.g. Monkey's should eat "things" => Monkey s should eat things). It then prepends the current date and time, and uses this string as the filename for the screenshot.

This allows you to easily find screenshots for a specific scenario or time.

Run a Failing Test and Check Out the Screenshot

Now you can run Cucumber as normal, watch a test fail, and you should see a screenshot appear in the directory you specified. And hopefully it will help you work out what went wrong, enjoy!

If the screenshot fails to appear, it could be because of an error in the ruby code. But Cucumber seems to hide any execptions within the After hook, so you may need to add puts statements to work out what is going wrong.

In a previous post I detailed changes I made to add Growl for Windows support to Autotest Growl.

These changes have now been integrated back into the autotest-growl gem. Along with some major improvements to the analysis of test results, and the details in the notifications. Thanks to Svoop, the creator of autotest-growl.

This gem isn’t yet available on Rubyforge, but you can grab a copy from my fork on GitHub until it is:

gem install karl-autotest-growl --source http://gems.github.com

This should be a drop in replacement for the previous version of karl-autotest-growl, the only thing you should notice more detail from the growl notifications!

I’ll post again once the official gem is available on Rubyforge.

I previously posted an update that enables Growl notifications for Autotest in Windows.

Which is nice, but what about other Ruby programs, they might want to send Growl notifications too. To this end Vision Media have produced a Ruby Growl gem which makes it easy for any Ruby program to send Growl notifications.

But the visionmedia-growl gem only works on OSX.

Now With Added Windows Support

So I had a go at adding Windows support. The short version is that it works, but the code is seriously ugly and not well tested (you have been warned!).

Check out my visionmedia-growl fork. Or just install the gem:

sudo gem install karl-growl --source http://gems.github.com

Packaging growlnotify

First up I decided to package both the OSX and Windows versions of growlnotify with the gem.

This is a departure from the existing gem, which requires that you have installed growlnotify yourself. I wanted to be able to include this gem in new projects without having to bother users to download extra dependencies.

Choose the Right growlnotify

I decide which growlnotify to use by checking which platform we are running on:

51
52
53
54
55
56
57
58
59
60
61
62
63
64
  def self.is_windows?
    processor, platform, *rest = RUBY_PLATFORM.split("-")
    platform == 'mswin32'
  end
 
  ##
  # Execute +args+ against the binary.
 
  def self.exec *args
    bin = PACKAGED_BIN
    bin += '.com' if is_windows?
 
    Kernel.system bin, *args
  end

Different Switches on Different Operating Systems

The biggest headache with adding Windows support was adding the ability to generate Windows style command line arguments.

Example OSX command line:

growlnotify --message llamas --title Llama! --image images/llama.png

Example Windows command line:

growlnotify.com llamas /t:Llama! /i:images/llama.png

Note that in the Windows command line, switches are specified with /x: prefix, and no space. The names of the switches don’t correspont exactly with the OSX ones.

Also, with the Windows version of growlnotify you don’t give an switch for the message body, just include it as the first argument.

Adding Support for Windows Style Switches

The first part of adding this support was to map the OSX switches to their Windows counterparts (where they existed).

204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
    switch :title,      :t
    switch :sticky,     :s
    switch :priority,   :p
    switch :host,       :host
    switch :password,   :pass
    switch :port,       :port
 
    switch :name,       :a
    switch :message,    :EMPTY
    switch :image,      :i
    switch :identifier, :id
 
    switch :iconpath,   nil
    switch :appIcon,    nil
    switch :icon,       nil
 
    switch :udp,        nil
    switch :auth,       :hash
    switch :crypt,      nil

As you can see, not all OSX switches are available in the Windows version of growlnotify. I dealt with this at the moment, by just stripping out any switches that won’t work in Windows.

Finally I altered (hacked?) the Growl run method, to produce parameter strings for either OSX or Windows.

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
    def run
      raise Error, 'message required' unless message
      self.class.switches.each do |name, win_name|
        if send(:"#{name}?")
          value = send(name).to_s if send(name) && !(TrueClass === send(name))
          if is_windows?
            next if win_name.nil?
 
            switch = (win_name == :EMPTY) ? "" : "/#{win_name}:"
            args << switch + value
          else
            args << "--#{name}"
            args << value
          end
        end
      end
      Growl.exec *args
    end

The main points of interest here are the The windows switches don’t have any space between the switch name and the value. So instead they are concatenated together into a single string.

Finally we deal with the special case where using the Windows version of growlnotify we need to add the message parameter without a switch, so we use the special token :EMPTY to deal with this.

The Result

The results of this is a Ruby gem that supports Growl notifications in Windows. The gem can be installed with the following commands:

sudo gem install karl-growl --source http://gems.github.com

And used in your Ruby program as follows:

Growl.notify {
    self.message = 'Hello World'
    self.image = File.join 'path', 'to', 'image.png'
  }

For more usage examples see the karl-growl site.

Known Issues

There are a few known issues. The biggest of which no support for normalised icons.

To support OSX and Windows always give a path to an image, e.g.

  :image => 'path/to/image.png'

There are a number of switches that only work in OSX, and are ignored in Windows. Unsupported switches are:

  :iconpath
  :appIcon
  :icon
  :udp
  :crypt

The gem has only received the most cursory of testing, so there may be a whole host of other issues, be warned!

The Future

I’m treating the current version of this gem, as a design spike, a proof of concept that shows we can have cross Operating System support. The code is a real mess, and has no unit tests, but I’m releasing it here to follow the ‘better now beats best later’ rule.

I hope to refactor the code into something more production worthy when I get a chance.

Autotest Growl for Windows

July 10th, 2009

In a previous blog post I detailed how to get Autotest Growl notifications on Windows using Snarl. But, there now exists an official Growl client for Windows.

So how about we update autotest-growl to support Windows (on top of it’s existing support for OSX).

If you don’t want to know all the gory details, you can just install my fork of the autotest-growl gem, that includes native Growl Windows support:

gem install karl-autotest-growl --source http://gems.github.com

Obviously, you’ll need to have Growl for Windows installed as well!

Updating Autotest Growl to support Windows

First up download and install Growl for Windows (if you haven’t already).

Updating Autotest Growl turns out to be pretty simple. We need to download growlnotify for Windows, and add it to the growl/ directory.

Then we can update the autotest-growl code to decide which growlnotify to use depending on the Operating System.

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  def self.is_windows?
    processor, platform, *rest = RUBY_PLATFORM.split("-")
    platform == 'mswin32'
  end
 
  ##
  # Display a message through Growl.
  def self.growl title, message, icon, priority=0, stick=""
    growl = File.join(GEM_PATH, 'growl', 'growlnotify')
    image = File.join(ENV['HOME'], '.autotest-growl', "#{icon}.png")
    image = File.join(GEM_PATH, 'img', "#{icon}.png") unless File.exists?(image)
 
    if is_windows?
      growl += '.com'
      cmd = "#{growl} #{message.inspect} /a:\"autotest\" /r:\"Autotest\" /n:\"Autotest\" /i:\"#{image}\" /p:#{priority} /t:\"#{title}\""
    else 
      if @@remote_notification
        cmd = "#{growl} -H localhost -n autotest --image '#{image}' -p #{priority} -m #{message.inspect} '#{title}' #{stick}"
      else
        cmd = "#{growl} -n autotest --image '#{image}' -p #{priority} -m #{message.inspect} '#{title}' #{stick}"
      end
    end
 
  system cmd
  end

You’ll notice that the command line flags are slightly different for the Windows version of growlnotify, the using the /x: format, rather than the OSX -x format.

The Windows version also adds the flat /r:"Autotest" to ensure the Autotest application is registered the first time it is run.

There is no need to deal with the @@remote_notification settings, as Growl for Windows does not have the same problem with intermittent notification loss that OSX does.

Installing updated Autotest Growl gem

I have rolled all these changes into my fork of autotest-growl. To switch over to this fork, open a Windows command prompt and enter:

gem uninstall autotest-growl
gem install karl-autotest-growl --source http://gems.github.com

And then watch the notifications roll in!

Growl and Autotest work brilliantly together. Autotest runs all your tests in the background every time a file changes, giving you extremely fast feedback on your test driven development. And Growl notifications save you from needing to flip back to the Terminal to see the result of each test run, you get an unobtrusive popup in the corner of your screen showing the success or failure of the tests.

But what about those users working on the Windows platform?

Snarl is a windows counterpart to Growl. Providing much of the same functionality.

And there is a Snarl Ruby gem allowing us to create Snarl notifications from Ruby.

So lets convert our Growl calls to Snarl calls, and get Autotest notifications under Windows.

Installing Autotest, Snarl, and the Growl to Snarl converter

If you haven’t already download and install Ruby.

First up we need to download and install Snarl.

Then we need to install Autotest and the autotest-growl gem (that we are later going to override). Open a command prompt, and type the following (Autotest is part of the ZenTest gem):

gem install ZenTest
gem install ruby-snarl
gem install autotest-growl

Then save the code below to lib/autotest/growl-to-snarl.rb within your project. This code converts any Growl calls to equivalent Snarl calls.

growl-to-snarl.rb

require 'snarl'
module Autotest::Growl
 
  # Display a message through Snarl.
  def self.growl title, message, icon, priority=0, stick=""
    image = File.join(ENV['HOME'], '.autotest-growl', "#{icon}.png")
    image = File.join(GEM_PATH, 'img', "#{icon}.png") unless File.exists?(image)
 
	Snarl.show_message(title, message.inspect, image)
  end
 
end

Next we need to update our .autotest configuration file to include the autotest-growl gem, and the Growl to Snarl converter. Add the following to your .autotest file in the project root directory.

require 'autotest-growl'
require 'snarl'
require 'lib/autotest/growl-to-snarl'

Running Autotest with Snarl support

First up ensure Snarl is running (check for the icon in the system tray).

Autotest will fail to run on Windows if a HOME environment variable doesn’t exist, so we need to create one before we run (I’ve also noticed that the Ruby gem command will fail to run if the HOME evironment variable does exist, which is frustrating!).

Open a command prompt, navigate to the project root directory. Then enter the following to set the HOME environment variable and run Autotest.

set HOME="C:\Documents and Settings\username"
autotest

The results of your test runs should now display as Snarl notifications.

Autotest and JS Test Driver

June 19th, 2009

Google recently released a new Javascript testing framework, JS Test Driver. It provides incredibly fast execution for Javascript unit tests, and can be run from the command line without the need for manual control of browsers. Check out this introduction to JS Test Driver by Miško Hevery.

Fast test execution and the ability to be run from the command line make it a perfect fit to integrate into the Autotest test cycle. So I have.

The module below hooks into Autotest just before the normal tests are run. It runs JS Test Driver over all the tests in the project, outputs the results, and finally fires off a :ran_js_test_driver hook.

Errors and failed tests will automatically be notified through Growl (if Growl and autotest-growl are installed). By default successful tests runs are not notified through Growl, in order to keep distracting popups to a minimum.

Installing Autotest JS Test Driver

First you need to download a copy of JS Test Driver.

Save the JS Test Driver jar file to the lib/ directory within your project.

Then copy the code below to lib/autotest/js-test-driver.rb

js-test-driver.rb

# Run JS Test Driver as part of autotest
# Supports Growl notifications if using autotest-growl
 
require 'autotest'
 
module Autotest::JsTestDriver
 
    @@jar = File.dirname(__FILE__) + '/JsTestDriver-1.0b.jar'
    @@config_file = 'jsTestDriver.conf'
 
    def self.jar=(string)
        @@jar = string
    end
 
    def self.config_file=(string)
        @@config_file = string
    end
 
    def self.show_success=(bool)
        @@show_success=bool
    end
 
 
    Autotest.add_hook :run_command do |at|
        # run js test driver
        results = 'JS Test Driver:'
        results += `java -jar "#{@@jar}" --config "#{@@config_file}" --tests all --verbose`
        puts results
 
        at.results = [] if at.results.nil?
        at.results.concat(results.split("\n"))
 
        at.hook :ran_js_test_driver
 
    end
 
end
 
module Autotest::Growl
 
    @@show_js_test_success = false
 
    def self.show_js_test_success=(bool)
        @@show_js_test_success=bool
    end
 
  # Growl results of JS Test Driver
  Autotest.add_hook :ran_js_test_driver do |autotest|
 
    gist = autotest.results.grep( /Total\s+\d+\s+tests/ ).join(" / ").strip()
 
    if gist == ''
      growl @label + 'Cannot run JS Test Driver.', gist, 'error'
    else
      if gist =~ /Errors:\s+[1-9]\d*/
        growl @label + 'Error running some JS tests.', gist, 'failed'
      elsif gist =~ /Fails:\s+[1-9]\d*/
        growl @label + 'JS Test: Some tests failed.', gist, 'failed'
      elsif @@show_js_test_success
        growl @label + 'JS Test: All files are clean.', gist, 'passed'
      end
    end
    false
  end
 
end

Configuring Autotest and JS Test Driver

JS Test Driver uses a configuration file to connect with the JS Test Driver server, and to decide which javscript files to load.

Create a jsTestDriver.conf file in the project root directory as follows.

server: http://localhost:9876
 
load:
  - src/js/*.js
  - tests/js/*.js

This assumes that you have our javascript source files will be in the src/js/ directory, and our javascript test files will be in the src/js/ directory. We will create a test file, and associated code later.

The server: lets JS Test Driver know we will be connecting to a server on our local machine, on port 9876. We’ll get this server running later.

Next we need to configure Autotest to run JS Test Driver, by requiring the module and specifying the location of the JS Test Driver jar.

# Require the JS Test Driver module
require 'lib/autotest/js-test-driver'
 
# Set the location of the JS Test Driver jar
Autotest::JsTestDriver::jar = './lib/jsTestDriver-1.0b.jar'

You can also configure the location of the JS Test Driver config file, and whether or not to show successful test runs.

# Uncomment this if you have autotest-growl, and Growl installed
# And want to have notifications of JS Test Driver runs
# require 'autotest/growl'
 
# Uncomment this to change the location of the JS Test Driver config file
# By default we look for a jsTestDriver.conf file in the directory autotest is run from 
# Autotest::JsTestDriver::config_file = './jsTestDriver.conf'
 
# Uncomment this to show successful test runs
# Autotest::Growl::show_js_test_success = true

Now that all the installation and configuration is done, let get everything running.

Running Autotest with JS Test Driver

First up we need to get our JS Test Driver server up and running. Open a Terminal, and navigate to the directory containing the JS Test Driver jar. Run the following to start a server:

java -jar JsTestDriver-1.0b.jar --port 9876

Now we need to capture a browser to use for testing. Open a browser and automatically capture it for use with JS Test Driver by going to the following URL:


http://localhost:9876/capture

Now we can run autotest, and watch as it runs JS Test Driver and reports the results to us on every file change:

autotest

JS Test Driver will probably report that no tests were run, as we haven’t written any tests yet. Tests are written using the TestCase object, which exposes JUnit style functionality.

Writing Some Tests

Here is an example test file, and the production code it tests:

GreeterTest.js

GreeterTest = TestCase("GreeterTest");
 
GreeterTest.prototype.testGreet = function() {
  var greeter = new myapp.Greeter();
  assertEquals("Hello World.", greeter.greet("World"));
};

Greeter.js

myapp = {};
 
myapp.Greeter = function() { };
 
myapp.Greeter.prototype.greet = function(name) {
  return "Hello " + name + "!";
};

If you copy these to your tests/js/ and src/js/ directories respectively, Autotest should pick up the new files, run the tests and notify you that there is an error. See if you can spot it :P

To Do

This would be nice packaged up as a gem. It would also be nice if failed Javascript tests could stop further tests being run.

As an example of getting Autotest, Cucumber, and Growl up and running I’ve created a super simple test project. You can download the example project, or just create it from the code on this post.

Install Ruby, Growl, and Gems

First up we need to ensure that we have all our dependancies installed.

If you haven’t already, download and install Ruby.

Then we need to install the Autotest, Cucumber, and Growl Ruby gems. We can do this using the gem command that comes packaged with Ruby.

# Autotest test is part of the ZenTest gem
sudo gem install ZenTest
sudo gem install cucumber
# Use my modified autotest-growl gem (until the changes are merged into the official gem)
sudo gem install karl-autotest-growl --source http://gems.github.com

Next we need to ensure that the Growl application itself is installed. If not download and install Growl.

Create Project

Now we are ready to create our project. The either download the example project or create the file heirarchy below:

  • [dir] Autotest-Cucumber
    • [file] .autotest
    • [dir] features
      • [file] test.feature

Copy the code below into the .autotest file:

.autotest

require 'autotest/growl'

And the copy the following into the test.feature file:

test.feature

Feature:
 
    Scenario:
        Given I save 1
        Then I have 1

Set Environment

Lastly we need to set the AUTOFEATURE environment variable to true, so that autotest will run the Cucumber tests automatically:

AUTOFEATURE=true

Run Autotest!

Finally we can run autotest, and watch as it picks up the Cucumber tests, runs them, and notifies us via Growl. Open terminal and navigate to the project directory. Then run autotest:

autotest

Autotest will initiate a Cucumber run. Cucumber will pick up the test.feature file (because it looks for a features folder by default). The Cucumber run will show that you have 1 undefined scenario (and be kind enough to give you the code for your undefined steps). And finally Growl will display a notification that you have 1 undefined scenario, yay!

c:/ruby/bin/ruby c:/ruby/lib/ruby/gems/1.8/gems/aslakhellesoy-cucumber-0.3.11.3/bin/cucumber --format progress --format rerun --out C:/Temp/autotest-cucumber.17824.1 features
UU
 
1 scenario (1 undefined)
2 steps (2 undefined)
0m0.000s
 
You can implement step definitions for undefined steps with these snippets:
 
Given /^I save 1$/ do
  pending
end
 
Then /^I have 1$/ do
  pending
end

Following on to my previous post on Autotest, Cucumber, and Growl, I have forked the autotest-growl repository, and applied my fix for Cucumber notifications.

You find my patched version of autotest-growl on GitHub.

You can switch to this version of autotest-growl by uninstalling any existing version, and then installing from my fork on GitHub:

sudo gem uninstall autotest-growl
sudo gem install karl-autotest-growl --source http://gems.github.com

As well as using Autotest to run Cucumber scenarios I have also been looking into integrating lower level test into the Autotest cycle.

My first attempt at this is a small module to run Javascript Lint on all the javascript files within a project any time any file changes.

The module below hooks in to Autotest just before the tests are normally run. It runs javascript lint over all the *.js files in the project, outputs the results to the autotest results object and the standard output, and finally fires a new ran_javascript_lint hook

Errors and warnings found by Javascript Lint will also be notified through Growl (if Growl and autotest-growl are installed). If there are no errors or warnings than no Growl notification is shown. This keeps distracting popups to a minimum.

Installing Autotest Javascript Lint

First up, download Javascript Lint. Extract the jsl executable to lib/autotest/ within your project.

Copy the code below to lib/autotest/javascript-lint.rb within your project (the same directory where you have the jsl execuatable).

javascript-lint.rb

# Run Javascript Lint as part of autotest
# Supports Growl notifications if using autotest-growl
#
# Version 1.0
 
require 'autotest'
 
module Autotest::JavascriptLint
    @@js_dir = ''
    @@jsl_dir = File.dirname(__FILE__) + '/'
    @@config_file = ''
 
    def self.js_dir=(string)
        @@js_dir = string
    end
 
    def self.jsl_dir=(string)
        @@jsl_dir = string
    end
 
    def self.config_file=(string)
        @@config_file = string
    end
 
    Autotest.add_hook :run_command do |at|
 
        # run javascript lint
        results = `#{@@jsl_dir}jsl -conf "#{@@config_file}"  -process "#{@@js_dir}*.js" +recurse`
        puts results
 
        at.results = [] if at.results.nil?
        at.results.concat(results.split("\n"))
 
        at.hook :ran_javascript_lint
    end
 
end
 
module Autotest::Growl
 
    @@show_js_lint_success = false
 
    def self.show_js_lint_success=(bool)
        @@show_js_lint_success=bool
    end
 
    # Growl results of Javscript Lint
    Autotest.add_hook :ran_javascript_lint do |autotest|
        gist = autotest.results.grep(/\d+\s+error.*,\s+\d+\s+warning.*/).join(" / ").strip()
 
        if gist == ''
            growl @label + 'Cannot run javascript lint.', '', 'error'
        else
            if gist =~ /[1-9]\d*\s+(error)/
                growl @label + 'Lint: Some files have errors.', gist, 'failed'
            elsif gist =~ /[1-9]\d*\s+(warning)/
                growl @label + 'Lint: Some files have warnings.', gist, 'pending'
            elsif @@show_js_lint_success
                growl @label + 'Lint: All files are clean.', gist, 'passed'
            end
        end
        false
    end
 
end

Then add Autotest Javascript Lint to your .autotest configuration file within the base of your project.

require 'lib/autotest/javascript-lint'

To Do

This could be packaged as a gem for easy installation, and it could possibly be modified to only run over changed files.