syntax.us Let the syntax do the talking
Blog Contact Posts Questions Tags Hire Me

Question:
How to start with Capybara-Selenium on Rails?

I use this post to get students started with using Capybara-Selenium to run RSpec feature tests on Rails.

Some students ask an obvious question, "Why should I use Capybara-Selenium to run RSpec feature tests on Rails?"

I usually answer with these responses:
  • For small Rails-prototype applications, Capybara-Selenium is optimal.
  • I can use Capybara-Selenium to test the JavaScript syntax in my Rails app.
  • Watching a robotic browser walk through my app gives me a sense of comfort.
  • Capybara-Selenium tests all or most layers in my Rails app.
  • Capybara-Selenium tests are a good place to start writing tests in my app.


What are some drawbacks to Capybara-Selenium testing?
  • It is slow.
  • It tests many layers at once, so it is not specific.
  • It depends on a browser like Firefox.


The steps listed below are useful to me when I create a new Rails app which has Capybara-Selenium testing enabled.

I usually start a new project by installing Ubuntu 14.04 inside of VirtualBox on my laptop:

https://www.virtualbox.org/wiki/Downloads
http://releases.ubuntu.com/14.04/ubuntu-14.04.2-desktop-amd64.iso

Once I have Ubuntu booted up, I prepare it for the installation of Ruby 2.2.2:

apt-get install autoconf bison build-essential libssl-dev libyaml-dev \
libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3       \
libgdbm-dev libsqlite3-dev gitk postgresql postgresql-server-dev-all  \
libpq-dev emacs wget curl chromium-browser openssh-server

apt-get update
apt-get upgrade
shutdown -r now
login
Then I install a recent version (as of this writing, 2.2.2) of Ruby:
cd ~
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
vi .bashrc
bash
ls -la ~/.rbenv/plugins/ruby-build/share/ruby-build/
rbenv install 2.2.2
rbenv global  2.2.2
Next I start work on my new Rails app:
mkdir ~/sites/
cd    ~/sites/
gem install rails -v 4.2.2
rails new myapp
cd myapp
rbenv local 2.2.2
vi Gemfile
My Gemfile should look like this:
ruby "2.2.2"
source 'https://rubygems.org'

gem 'thin'          ,'1.6.3'
gem 'rails_12factor','0.0.3'
gem 'haml'          ,'4.0.6'
gem 'haml-rails'    ,'0.9.0'
group :production do
  gem 'pg'          ,'0.18.2'
end

gem 'rails', '4.2.2'

gem 'sass-rails'  , '~> 5.0'
gem 'uglifier'    , '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 2.0'

group :development, :test do
  gem 'sqlite3'           ,'1.3.10'
  gem 'websocket'         ,'1.2.2'
  gem 'ffi'               ,'1.9.8'
  gem 'childprocess'      ,'0.5.6'
  gem 'rubyzip'           ,'1.1.7'
  gem 'selenium-webdriver','2.46.2'
  gem 'xpath'             ,'2.0.0'
  gem 'capybara'          ,'2.4.4'
  gem 'rspec-support'     ,'3.3.0'
  gem 'diff-lcs'          ,'1.2.5'
  gem 'rspec-mocks'       ,'3.3.0'
  gem 'rspec-expectations','3.3.0'
  gem 'rspec-core'        ,'3.3.1'
  gem 'rspec-rails'       ,'3.3.2'
  gem 'therubyracer', platforms: :ruby
  # In controller, call 'byebug' for a debugger console
  gem 'byebug'
  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '~> 2.0'
end
Then, I run these shell commands:
bundle install
bundle binstub thin
bundle binstub rspec-core
Next, I scaffold a tangible noun-like thing such as Car:
bin/rails g scaffold Car vin:string yr:integer model:string make:string color:string
bin/rake db:migrate
Now I have enough of a Rails app to write a Feature-Spec which uses RSpec, Capybara, and Selenium:
bin/rails g rspec:install
mkdir spec/features
Then I write enough of a spec to see if RSpec can start Firefox:
vi spec/features/firefox_spec.rb
I should type in something like this:
# spec/features/firefox_spec.rb
# Demo:
# bin/rspec spec/features/firefox_spec.rb
require 'rails_helper'
describe 'This should start Firefox', :js => true do
  it 'should start Firefox' do
    visit '/cars'
    # I should briefly see Firefox; then it should exit.
  end
end
Then I run it with this shell command:
bin/rspec spec/features/firefox_spec.rb
I should briefly see Firefox; then it should exit.
I should see something like this in my shell:
dan@ann15:~/sites/myapp $ 
dan@ann15:~/sites/myapp $ bin/rspec spec/features/firefox_spec.rb
   (9.5ms)  CREATE TABLE "cars" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "vin" varchar, "yr" integer, "model" varchar, "make" varchar, "color" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL) 
   (9.3ms)  CREATE TABLE "schema_migrations" ("version" varchar NOT NULL) 
   (0.2ms)  select sqlite_version(*)
   (13.1ms)  CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
   (0.2ms)  SELECT version FROM "schema_migrations"
   (12.9ms)  INSERT INTO "schema_migrations" (version) VALUES ('20150625221319')
  ActiveRecord::SchemaMigration Load (0.1ms)  SELECT "schema_migrations".* FROM "schema_migrations"
   (0.1ms)  begin transaction
Started GET "/cars" for 127.0.0.1 at 2015-06-25 22:32:09 +0000
Processing by CarsController#index as HTML
  Car Load (0.3ms)  SELECT "cars".* FROM "cars"
  Rendered cars/index.html.haml within layouts/application (15.4ms)
Completed 200 OK in 2131ms (Views: 1922.5ms | ActiveRecord: 0.3ms)
Started GET "/assets/application.css" for 127.0.0.1 at 2015-06-25 22:32:11 +0000
Started GET "/assets/application.js" for 127.0.0.1 at 2015-06-25 22:32:11 +0000
   (0.1ms)  rollback transaction
.

Finished in 9.97 seconds (files took 3.92 seconds to load)
1 example, 0 failures

dan@ann15:~/sites/myapp $ 
dan@ann15:~/sites/myapp $ 
Here is an animated GIF:

If that works I should start work on a spec which asks for the cars/new form:
# spec/features/cars_spec.rb
# Demo:
# bin/rspec spec/features/cars_spec.rb
require 'rails_helper'
describe 'This should use Firefox to test the cars resource.', :js => true do
  it 'should see the form at cars/new' do
    visit '/cars/new'
    expect(page).to have_text('New car')
    expect(page).to have_text('Vin')
    expect(page).to have_text('Model')
    expect(page).to have_text('Make')
  end
end
If that works I should write a spec which fills in the form and then looks for the data:
# spec/features/cars_spec.rb
# Demo:
# bin/rspec spec/features/cars_spec.rb
require 'rails_helper'
describe 'This should use Firefox to test the cars resource.', :js => true do
  it 'should see the form at cars/new' do
    visit '/cars/new'
    expect(page).to have_text('New car')
    expect(page).to have_text('Vin')
    expect(page).to have_text('Model')
    expect(page).to have_text('Make')
  end
  it 'should fill in form at cars/new' do
    visit '/cars/new'
    fill_in "Vin",   :with => "abc123XYZ"
    fill_in "Model", :with => "Mustang"
    fill_in "Make",  :with => "Ford"
    fill_in "Yr",    :with => "1968"
    fill_in "Color", :with => "Blue"
  end  
  it 'should submit form at cars/new' do
    visit '/cars/new'
    fill_in "Vin",   :with => "abc123XYZ"
    fill_in "Model", :with => "Mustang"
    fill_in "Make",  :with => "Ford"
    fill_in "Yr",    :with => "1968"
    fill_in "Color", :with => "Blue"
    click_on 'Save'
  end  
  it 'should display a new car' do
    visit '/cars/new'
    fill_in "Vin",   :with => "abc123XYZ"
    fill_in "Model", :with => "Mustang"
    fill_in "Make",  :with => "Ford"
    fill_in "Yr",    :with => "1968"
    fill_in "Color", :with => "Blue"
    click_on 'Save'
    expect(page).to have_text('Car was successfully created')
    expect(page).to have_text('abc123XYZ')
    expect(page).to have_text('Mustang')
    expect(page).to have_text('Ford')
    expect(page).to have_text('Blue')
  end  
  it 'should display cars' do
    visit '/cars/new'
    fill_in "Vin",   :with => "abc123XYZ"
    fill_in "Model", :with => "Mustang"
    fill_in "Make",  :with => "Ford"
    fill_in "Yr",    :with => "1968"
    fill_in "Color", :with => "Blue"
    click_on 'Save'
    click_on 'Back'
    expect(page).to have_text('Listing cars')    
    click_on 'New Car'
    fill_in "Vin",   :with => "def456XYZ"
    fill_in "Model", :with => "Vette"
    fill_in "Make",  :with => "Chevy"
    fill_in "Yr",    :with => "1967"
    fill_in "Color", :with => "Black"
    click_on 'Save'
    click_on 'Back'
    expect(page).to have_text('Listing cars')    
    expect(page).to have_text('Listing cars')
    expect(page).to have_text('abc123XYZ')
    expect(page).to have_text('Mustang')
    expect(page).to have_text('Ford')
    expect(page).to have_text('Blue')
    expect(page).to have_text('def456XYZ')
    expect(page).to have_text('Vette')
    expect(page).to have_text('Chevy')
    expect(page).to have_text('Black')
  end  
end
I ran the above spec on my laptop and captured it with byzanz screen capturer:

That worked so, I am convinced that Rails-RSpec-Capybara-Selenium is working well for me.


syntax.us Let the syntax do the talking
Blog Contact Posts Questions Tags Hire Me