Autotesting JavaScript with Jasmine and Guard
One of the things I really loved about Rails in the early days was that it introduced me to the conc
A lot of what we do in Rails boils down to simple Crud. If you're in the habit of developing admin sections to allow your clients to control the front end of their site, you'll probably have noticed that these controllers in particular tend to all look the same. There are quite a few ways to DRY up the controller itself - using something like make_resourceful, for example, but what about your RSpec files?
Robby Russell recently posted a short article about RSpec's Shared Example Groups. Take a look at his post or at the RSpec documentation (it's not scary) to see how they work in more detail, but they basically allow you to share your it "should" do ..... end blocks, enabling them to be reused multiple times.
When you think about it, every time we spec a basic CRUD controller, we're doing the same thing - we should be able to just do something like this:
Well luckily for you we can! I've been using this pattern with most of my CRUD-based controllers for a while now. You just set up the model's name at the top (and in the case above perform the login_as_admin helper method to log the user in), and for each action in the controller use a specialised shared example group. The example groups all know how to understand your @model definition in before(:each) and map it to the various expectations that the CRUD specs run.
The great thing about this approach is that you can just dump these into your spec file and update them later if you need to. For example if you need to paginate the index action instead of the default find(:all) the shared example group will test, just remove the it_should_behave_like("CRUD GET index") and add your own describe block - the rest of the it_should_behave_like lines can stay as they are.
This approach works especially well if you take the approach to CRUD controllers where you create a CrudController class and subclass your CRUD controllers from it - e.g. from the example above:
My Admin::CrudController reflects on the name of the ContactsController subclass here and figures everything out without me having to do any work. This works because almost all of my Admin section code works the same way. If I need to diverge from the default CRUD behaviour, I just redefine the particular action in Admin::ContactsController:
I personally prefer this approach over the more declarative alternatives such as make_resourceful because I feel more in control this way. That said, I'm open to persuasion :)
Anyway the code for the shared example groups is on Github at http://github.com/edspencer/rspec-crud-controller-shared-example-groups. There's only one file there - just chuck in in your spec directory and add this line to spec_helper.rb:
Apart from the magic going on in the CrudSetup module at the top of that file, there's nothing special going on here, so you can tweak the examples to your particular approach. There's a good chance some of that code could be written more cleanly so please feel free to suggest changes / fork the file on Github.
UPDATE - Actually no, ignore the FUD about make_resourceful above, it works remarkably well with very few modifications to the shared groups - I'll post those up as soon as I'm done.
For further insights into enhancing your JavaScript and Rails testing strategies, consider reading about Autotesting JavaScript with Jasmine and Guard, which explores setting up an efficient autotest environment. Additionally, the article Jasmine and Jenkins Continuous Integration provides a practical guide on integrating JavaScript testing frameworks with Jenkins for continuous integration.
One of the things I really loved about Rails in the early days was that it introduced me to the conc
Having recently made the switch from svn to git, I wanted to achieve what svn externals did (and wha
I use Jasmine as my JavaScript unit/behavior testing framework of choice because it's elegant and ha
If you're using edge rails you may have noticed that you can now define your own JavaScript expansio