← Back to Upcase

Integration test fails when using selenium


(Chris Bradley) #1

I’m attempting to test a confirmation dialog when I delete an object. My integration test works fine until I add js: true to the scenario.

This passes:

scenario 'user deletes a chain' do
    user = FactoryGirl.create(:user)
    visit root_path
    click_link "Sign In"
    expect(current_path).to eq(new_user_session_path)
end

this fails:

scenario 'user deletes a chain', js: true do
    user = FactoryGirl.create(:user)
    visit root_path
    click_link "Sign In"
    expect(current_path).to eq(new_user_session_path)
end

here’s the failure:

  1) user deletes chain user deletes a chain
     Failure/Error: user = sign_in 'user'
       
       expected: "/users/sign_in"
            got: "/

What’s weird is that when the test runs and firefox is open, it fails when firefox is on the users/sign_in page. It feels like the expectation is firing before the page loads which is why it returns the root_path, but I’m just guessing. Any ideas?


(Ben Orenstein) #2
Failure/Error: user = sign_in 'user'

This bit makes me wonder if this test is actually failing where you think it is. Is it definitely failing at the final assertion of your test case?


(Matthew Sumner) #3

Not sure if this will help but I need this with logging in with js: true tests from this blog post

#spec/spec_helper.rb
...
  class ActiveRecord::Base
    mattr_accessor :shared_connection
    @@shared_connection = nil

    def self.connection
      @@shared_connection || retrieve_connection
    end
  end
 
  # Forces all threads to share the same connection. This works on
  # Capybara because it starts the web server in a thread.
  ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
...

This works as long as transactional fixtures is set to true


(Chris Bradley) #4

@benorenstein I’m pretty sure the test fails on the path expectation. I removed the method call in my test and now it looks like this:

  scenario 'user deletes a chain', js: true do
    visit root_path
    click_link "Sign In"
    expect(current_path).to eq(new_user_session_path)
  end

Here is the resulting error:

Failures:

  1) user deletes chain user deletes a chain
     Failure/Error: expect(current_path).to eq(new_user_session_path)
       
       expected: "/users/sign_in"
            got: "/"
       
       (compared using ==)

@DeviousDuck Thanks for the tip but I must confess much of the explanation in the blog post is over my head. I do like the potential efficiency gain by eliminating DB cleaner though.


(Jason Draper) #5

It looks like you have an assertion on the route and you have your root route set to the /users/sign_in. If you are asserting in your spec that you should be on /users/sign_in but you’re actually on /, (which is most likely the same thing in this case), then your expectation would fail.

As a general rule I try to avoid testing the actual route. In this case it doesn’t matter that your URL says /users/sign_in, it only matters that you have a login screen available so test for that instead. This also makes your tests more flexible so that in the future if you’re login becomes a modal or something like that, your test may not have to change as much.


(Chris Bradley) #6

@drapergeek My root is set to chains#index. So the flow is like this:

It just feels like the expect(current_path).to eq(new_user_session_path) expectation executes before the page redirects to /users/sign_in

I inserted a new expectation and the test passes now:

scenario 'user deletes a chain', js: true do
  visit root_path
  click_link "Sign In"
  expect(page).to have_css('h2', text: "Sign in")
  expect(current_path).to eq(new_user_session_path)
end

This is a good tip, Thank You. Are there any good, current guidelines floating around on what makes better integration expectations? It seems like testing for specific content is just as brittle as testing routes.


(Jason Draper) #7

Good catch! The have_css method has an automatic ‘wait’ built in through capybara, apparently the path check does not.

Checking for content is a bit brittle but as with all things, it is a trade off. Regardless of what page my login information is on, I’m 90% certain that it will have some form of a ‘sign in’ title. To make sure that my tests need as little updating as possible when it comes to content we use internalization. Derek Prior wrote a great post about that here: http://robots.thoughtbot.com/better-tests-through-internationalization/ . By relying on ‘concepts’ of text and not the actual text you’re tests become easier to manage.

As for a list of these rules, I can’t point you to a specific list but I’m certain that the Test Driven Development course mentions a lot of this same information.