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?