Feature Testing AngularJS Views in a Rails App Breaks When Switching From ERB to Angular

angularjs, capybara, javascript, ruby-on-rails, testing

Solution

To make this work I set Capybara's javascript driver to poltergeist. This took installing phantomJS (>= 1.8.1) and setting js to true in my integration tests.

This is the process:

Install PhantomJS 1.9 (ubuntu 12.10 with 32bit OS directions displayed, adjust accordingly):

$ cd
$ wget https://phantomjs.googlecode.com/files/phantomjs-1.9.0-linux-i686.tar.bz2
$ tar jxvf https://phantomjs.googlecode.com/files/phantomjs-1.9.0-linux-i686.tar.bz2
$ sudo mv phantomjs-1.9.0-linux-i686.tar.bz2
$ phantomjs --version

Add poltergeist to the Gemfile and bundle install:

group :test do
  gem 'poltergeist'
end

In the 'test_helper.rb' file, or similar:

require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist

In your integration/feature tests, be sure to include 'js: true' like this:

scenario "Your test with Angular.js views", js: true do
  # test is here
end

# OR

it "Your test with Angular.js views", js: true do
  # test is here
end

Problem

To begin, I had a working rails 'show' page displaying a projects name and entries belonging to the project. When the projects name was displayed using angular $scope and the entries using a block in ERB, my tests passed. When I replaced the entries ERB code with the angular directive 'ng-repeat', only my entries testing scenarios began failing. Interestingly, the application was still working in the browser. And remember, the other $scope variable in my view was and still remains passing using a nearly identical test. Working show.html.erb (Entries Viewed in ERB): ``` <div ng-controller="ProjectCtrl"> <h1>This is {{ project.details.name }}</h1> <h2>Entries</h2> <% @entries.each do |e| %> <ul> <li> <%= e.title %> </li> <li> <%= e.summary %> </li> </ul> <% end %> </div> ``` Breaking show.html.erb (Entries Viewed in Angular): ``` <div ng-controller="ProjectCtrl"> <h1>This is {{ project.details.name }}</h1> <h2>Entries</h2> <ul ng-repeat=" e in project.entries "> <li> {{ e.title }} </li> <li> {{ e.summary }} </li> </ul> </div> ``` Angular Controller, data has been replaced with the returned JSON. ``` @ProjectCtrl = ["$scope", "$http", ($scope, $http) -> $http.get().success (data) -> $scope.project = {"details":{"name":"Project1","author":"brian"},"updated_at":"2013-04-13T16:48:46.406Z","entries":[{"title":"Test Title","summary":"Summary Test"},{"title":"The Third Entry","summary":"Summary of Third Entry"}]} ] ``` This is an example test that worked before but fails after replacing ERB with ng-repeat: ``` scenario "Displays Entries Summary" do project = Project.create!(details: {name: "aproject"}) Entry.create!(data: {summary: "Should Be Displayed"}, project_id: project.id) Entry.create!(data: {summary: "Should Not Be Displayed"}) visit project_path(project.id) page.must_have_content "Should Be Displayed" page.wont_have_content "Should Not Be Displayed" end ``` Am I missing something or will I have to alter the way I do feature testing?

Original source