Amit
Amit

Reputation: 39

Capybara Click_Button fails without Javascript

Im writing a simple login test using RSpec 3 and Capybara 2.2.0 and cannot for the life of me figure out why this test keeps failing.

I've managed to identify that the test isn't actually clicking on the button, but it thinks it is. Another strange thing is that even though this isn't a javascript form, running the test with capybara set to js: true, will render a successful test. What am I missing?

GemFile

source 'https://rubygems.org'
ruby '2.0.0'

gem 'rails', '4.0.1'
gem 'bootstrap-sass', '~> 3.0.2.0'
gem 'bcrypt-ruby', '3.1.2'
gem 'faker', '1.1.2'
gem 'will_paginate', '3.0.4'
gem 'will_paginate-bootstrap', '1.0.0'
gem 'holder_rails', '2.2.0'

group :development, :test do
  gem 'sqlite3', '1.3.8'
  gem 'rspec-rails', '~> 3.0.0.beta'
end

group :test do
  gem 'selenium-webdriver', '2.35.1'
  gem 'capybara'
  gem 'factory_girl_rails', '4.2.0'
  gem 'cucumber-rails', '1.4.0', :require => false
  gem 'database_cleaner', github: 'bmabey/database_cleaner'
  gem 'launchy'
  gem 'growl', '1.0.3'
end

gem 'sass-rails', '>= 3.2'
gem 'uglifier', '2.1.1'
gem 'coffee-rails', '4.0.1'
gem 'jquery-rails', '3.0.4'
gem 'turbolinks', '1.1.1'
gem 'jbuilder', '1.0.2'

group :doc do
  gem 'sdoc', '0.3.20', require: false
end

group :production do
  gem 'pg', '0.15.1'
  gem 'rails_12factor', '0.0.2'
end

*Authentication_pages_spec.rb*

require 'spec_helper'

describe "Authentication" do

  subject { page }

  describe "signin page" do
    before { visit signin_path }

    it { should have_content('Sign in') }
    it { should have_title('Sign In') }
  end

  describe "signin", :type => :feature do

    before :each do
      visit signin_path
    end

    describe "with invalid information" do
      specify do
        click_button 'Sign in'
        should have_selector('div.alert.alert-danger',  text: 'Invalid')
        should have_title('Sign In')
      end
    end

    describe "with valid information" do
      let(:user) { FactoryGirl.build(:user) }
        before do    
            fill_in "Username",     with: user.username
        fill_in "Password",     with: user.password
      end

      specify do
        click_button 'Sign in'
        save_and_open_page
        # current_path.should == root_path
        should_not have_title("Sign In")
        should have_content("dreams")
      end
    end
  end
end

Sessions.rb

class SessionsController < ApplicationController
    def new
    end

    def destroy
    end

    def create
        user = User.find_by(username: params[:session][:username].downcase)
        if user && user.authenticate(params[:session][:password])
            sign_in user
            redirect_to root_path
        else
            flash.now[:danger] = 'Invalid email/password combination'
            render 'new'
        end
    end
end

Result:

Failures:

  1) Authentication signin with valid information should not have title "Sign In"
     Failure/Error: should_not have_title("Sign In")
       expected there not to be title "Sign In" in "Adventure|Byte Games - Sign In"
     # ./spec/features/authentication_pages_spec.rb:39:in `block (4 levels) in <top (required)>'

  2) Authentication signin with invalid information should have css "div.alert.alert-danger" with text "Invalid"
     Failure/Error: should have_selector('div.alert.alert-danger',  text: 'Invalid')
     Capybara::ExpectationNotMet:
       expected to find css "div.alert.alert-danger" with text "Invalid" but there were no matches
     # ./spec/features/authentication_pages_spec.rb:23:in `block (4 levels) in <top (required)>'

Added Sign in View (new.html.erb)

<% provide(:title, "Sign In") %>
<h1>Sign in</h1>

<div class = "container">
<%= form_for(:session, url: sessions_path) do |f| %>
    <form role = "form">
        <div class="col-md-6 col-md-offset-3">

            <div class="form-group">
                <%= f.label :username %>
                <%= f.text_field :username, class: "form-control" %>
            </div>

            <div class="form-group">
                <%= f.label :password %>
                <%= f.password_field :password, class: "form-control"%>
            </div>

            <div class="form-group">
                <%= f.submit "Sign in", class: "btn btn-lg btn-primary" %>
            </div>

         </div>
    </form>
<% end %>
</div>

So it turns out that I was over doing the formatting on the form, the following view seems to work:

<% provide(:title, "Sign In") %>
<h1>Sign in</h1>

<div class = "container">
    <div class="col-md-6 col-md-offset-3">
        <%= form_for(:session, url: sessions_path) do |f| %>

            <%= f.label :username %>
            <%= f.text_field :username, class: "form-control" %>

            <%= f.label :password %>
            <%= f.password_field :password, class: "form-control"%>

            <%= f.submit "Sign in", class: "btn btn-lg btn-primary" %>

        <% end %>
    </div>
</div>

Upvotes: 1

Views: 1708

Answers (2)

Amit
Amit

Reputation: 39

So it turns out that I was over doing the formatting on the form, the following view seems to work:

<% provide(:title, "Sign In") %>
<h1>Sign in</h1>

<div class = "container">
    <div class="col-md-6 col-md-offset-3">
        <%= form_for(:session, url: sessions_path) do |f| %>

            <%= f.label :username %>
            <%= f.text_field :username, class: "form-control" %>

            <%= f.label :password %>
            <%= f.password_field :password, class: "form-control"%>

            <%= f.submit "Sign in", class: "btn btn-lg btn-primary" %>

        <% end %>
    </div>
</div>

Upvotes: 0

Dono
Dono

Reputation: 656

Personally I would not use the click_button method. It can be quite flaky.

I like to use this sort of thing

page.find('the.css.for.the.button').trigger('click') 

The reason for using trigger('click') is that it is much more reliable with javascript.

I hope that helps.

Upvotes: 2

Related Questions