Grunt Protractor Testing

A Complete Angular/Rails SPA Integration Test Example

Note: Since writing this post I’ve found a better way to write integration tests. I no longer advocate the method described below. For a more up-to-date guide, see How to Use RSpec to Test an Angular/Rails Single-Page Application.

What I wanted to achieve

My definition of “integration test” for an SPA: a test that exercises all layers from the UI to the database. To be extra clear, I mean an actual database instance, not something stubbed. My objective: run one command, anytime, with no preconditions, that runs all my integration tests. What I mean by “no preconditions” is that I don’t have to manually spin up Selenium or something like that before running my tests. You obviously can’t have no preconditions. There will always be some preconditions, like owning a computer.

How we’ll get there

My quest to be able to run a real integration test with one command led me to create the following situation:

  • When I run grunt serve, it starts a client server on port 9000 and a Rails server on port 3000
  • When I run grunt test, it starts a client server on port 9001 and a Rails server on port 3001 (so the two sets of servers aren’t trying to run on the same ports)

The dev side of things (grunt serve) is less involved than the testing side, so we’ll start with that and build from there.

Getting grunt serve to run Rails

Add this line to client/package.json:

grunt-rails-server“: “jasonswett/grunt-rails-server“,

Now run:
Now he have to add two things to our Gruntfile. We have to tell Grunt that we want to start our Rails server when grunt serve is run, and in order to be able to do that we have to load the grunt-rails-server npm task. Here is my entire Gruntfile:
Now if you run grunt serve it should spin up not only your client server but a Rails server on port 3000 as well. If you hit Ctrl+C to kill the Grunt server, it will also kill the Rails server. I don’t know about anybody else but I find this ability wonderfully exciting.

Getting grunt serve to run tests

Before we can get grunt serve to run our tests, we’ll of course have to have at least one test to run. First, create a new directory inside client/test called e2e.

Now create a file called main.spec.js inside test/e2e and give it the following content:

Now we’ll add

We also need to install a couple new modules that we’re using:

Lastly, we need to configure Protractor:

Before we try to run our tests, you’ll want to make sure you have Protractor properly installed. Run this command to check:

If you don’t have Protractor installed, follow the instructions in this tutorial to get it going. Now you should be able to run grunt serve and have it work.

But the test does not pass. We don’t have any element with an id of home-header yet. Let’s add it. In app/views/main.html, change

to

Now your test should pass.

Free Guide

Getting Started with Angular and Rails

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

A more meaningful test

I made that first test pretty trivial on purpose. Let’s add one that tests some actual database-hitting functionality:

This test or course fails at first, too. We need to add the code to make it work.

Finally, install the angularjs-rails-resource Bower package.

Now you should be able to run grunt test and see your new, more meaningful end-to-end test pass.

Is this adequate?

What I’ve done here probably leaves a lot of questions to be answered. The biggest one that comes to my mind is the question of what we do when we need to start creating data from factories, like what I would normally do using Factory Girl and RSpec. My honest answer to that question is that I have no idea. I’m again just kind of “learning in public”, documenting what I learn as I go, so I’ll be interested to see what I figure out at that point. Another question is why test Angular and Rails with Angular as opposed to testing Angular and Rails with Rails. I’m not completely sure. It was a gut feeling kind of thing. I’m actually starting to think it might be better to come at it from the Rails end. Perhaps it would be a good idea to run a build, then test that via RSpec and Capybara. I’d be interested to hear people’s thoughts in this area. There are two things I know for sure, though:

  1. I feel a hell of a lot better about real end-to-end testing than something that’s called end-to-end testing but only tests the client side.
  2. I’m glad I figured out something out that automatically runs Rails underneath my client app, at least for development environment purposes. So far it’s been super useful.

About the author

Jason Swett

3 Comments

Click here to post a comment

  • Nice, was waiting for this post.

    I’ve been playing around with a similar approach using gulp and found a solution for setting up test data: basically just use gulp-shell to run some shell commands like rake db:setup before protractor runs.

    This way, if there’s a signup spec or something, I can hardcode data for protractor to signup with and it will pass validations on the rails side since the db is fresh on each run.

    There’s probably a similar grunt-shell module. It’s a bit hacky, but it works for me at the moment.

    • NVM — I found it. Could be worth linking to from the article though (possible I missed it, but didn’t see link anywhere).