Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 272
Brian Petro Avatar asked Apr 25 '13 16:04

Brian Petro


2 Answers

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
like image 171
Brian Petro Avatar answered Oct 23 '22 02:10

Brian Petro


In your controller you're setting $scope.projects so in the template the variable 'project' should be available. In the template code you pasted you are 'ng-repeat'-ing over 'project.entries' (singular) Unless you made a typo or pasted pseudo code this can't work in the browser either.

I don't know enough about rails functional testing to tell you it will wait for all JS to finish before it does it's assertions. What about route changes in Angular?

I use Angular's JS testing setup with karma and Jasmine to test the Angular pages. Jasmine is then made aware of the Angular stack being active.

Check out this post: http://www.yearofmoo.com/2013/01/full-spectrum-testing-with-angularjs-and-testacular.html

like image 38
E_lexy Avatar answered Oct 23 '22 02:10

E_lexy