RSpec Single-Page Applications Testing

How to Use RSpec to Test an Angular/Rails Single-Page Application

I struggled for some time deciding how to “properly” put together an integration test for an Angular/Rails single-page application. First I tried to drive Rails with Protractor but that felt weird. Then it dawned on me that the fact that the SPA-ness of my Rails app is just a detail. This is a Rails app that happens to be a single-page application. I can still use RSpec to test my SPA just like I would for a non-SPA.

But because my Rails API layer is (rightfully) unaware of the client layer under normal circumstances, it’s not possible to simply act as if the SPA is a non-SPA. RSpec doesn’t know anything about the UI. My solution to this problem is to simulate a deployment before my test suite runs. “Simulate a deployment” is my fancy way of saying “run a grunt build“. It’s actually super simple.

Before you implement anything described below, you’ll probably want to configure Grunt to run Rails and get HTML5 pushState working. You may also like to read my post on how to deploy an Angular/Rails single-page app, because part of what I do here overlaps with that, and might not seem to make complete sense without understanding how I do a deployment.

The Feature We’re Testing

The “feature” I’ll demonstrate testing is a really simple one: a static list of groups. This feature is unrealistically simple but we cover enough ground by testing it that it will (I think) be obvious when we’re done how you’d test something more complex.

Here’s the Angular controller I’m using:

Here’s my view for it:

And here’s my route:

 

 Configuring Grunt’s Build Correctly

First, remove Rails’ public directory. Our public directory from now on will be replaced by the output of grunt build. (If you haven’t yet, I’d recommend reading How to Deploy an Angular/Rails Single-Page Application to Heroku.)

In our Gruntfile we’ll change the grunt build output directory from dist to ../public – the same public we just deleted. Change this:

To this:

Now if you run rails server and navigate to http://localhost:3000/, you should see your single-page app there, behaving exactly as it does when served by grunt serve.

Configuring RSpec

We’ll need to tell RSpec to run a grunt build before each integration test, and afterward we’ll want to kill the public directory we created. Add the following to spec/spec_helper.rb.

Here’s my full spec/spec_helper.rb for reference:

Notice the Rails.configuration.gruntfile_location in spec_helper.rb. This configuration setting doesn’t exist yet. We’ll need to define it. (By the way, this is just an arbitrary configuration setting I came up with. It seemed more appropriate to me to define the Gruntfile location as a config setting rather than hard-coding it in this spec_helper.rb.)

To define gruntfile_location, add this line to config/environments/test.rb:

You’ll also need to install a few certain gems in order for all this to work, including capybara, selenium-webdriver, database_cleaner and compass. (database_cleaner is actually not strictly necessary for what we’re doing but my sample code includes it so your tests won’t run without it if you’re copying and pasting my code.)

Now you’ll need to do a bundle install, of course.

Free Guide

Getting Started with Angular and Rails

Get an Angular/Rails app up and running in as little as 20 minutes

The Spec Itself

Here’s the spec I wrote to verify that the group list contains “Group One”.

If you run rspec spec/features/group_spec.rb, it should pass.

About the author

Jason Swett

2 Comments

Click here to post a comment