Welcome to GKTCS Innovations Pvt. Ltd.

Corporate Training, Online Training and Consultancy

Surendra Panpaliya

Director, GKTCS Innovations Pvt. Ltd, Pune.

18+ Years of Experience ( MCA, PGDCS, BSc. [Electronics] , CCNA) Director , GKTCS Innovations Pvt. Ltd. Pune [ Nov 2009 – Till date ] IT Manager and Consultant at Rolta India Ltd, Mumbai [ April 2007 – Oct 2009 ] Associate Professor at Sinhgad Institute , Pune [Jan 2002 – April 2007] Instructor , ITM Bangalore [ May 2000 – Jan 2002 ] Project Trainee, DSYS Group, Bangalore [ Jan 1999 to April 2000] Skills ❑ Ruby, Rail,Python, Jython, Django, Android , PHP, LAMP ❑ Data Communication & Networking, CCNA ❑ UNIX /Linux Shell Scripting, System Programming ❑ CA Siteminder, Autosys, SSO, Service Desk, Service Delivery Author of 4 Books National Paper Presentation Awards at BARC Mumbai 2 Agenda

• Introduction to • Capybara installation • Environment setup Introduction to Capybara

◆ Capybara is a web-based software that simulates scenarios for user stories and automates testing for behavior-driven software development.

◆ It is a part of the testing framework written in the Ruby programming language that simulates various aspects of a web browser from the perspective of a real user. Introduction to Capybara

◆ Background and Motivation ◆ In the course of the software development process especially in the Agile and Test-driven Development environments, as the size of the tests increase, it becomes difficult to manage tests which are complex and not modular.

◆ By extending the human-readable behavior-driven development style of frameworks such as Cucumber and RSpec into the automation code itself, Capybara aims to develop simple web-based automated tests. Introduction to Capybara

◆ Anatomy of Capybara ◆ Capybara is a library/gem built to be used on top of an underlying web- based driver. It offers a user-friendly DSL (Domain Specific Language) which is used to describe actions that are executed by the underlying web driver.

◆ When the page is loaded using the DSL (and underlying web driver), Capybara will try to locate the relevant element in the DOM () and execute the action, such as click button, link, etc.

◆ Drivers ◆ By default, Capybara uses the :rack_test driver which does not have any support for executing JavaScript. Driver can be switched in Before and After blocks. Some of the web drivers supported by Capybara are mentioned below. Introduction to Capybara

◆ RackTest ◆ Written in Ruby, Capybara's default driver RackTest does not require a server to be started since it directly interacts with Rack interfaces. Consequently, it can only be used for Rack applications.

◆ Selenium-webdriver, which is mostly used in web-based automation frameworks, is supported by Capybara. Unlike Capybara's default driver, it supports JavaScript, can access HTTP resources outside of application and can also be set up for testing in headless mode which is especially useful for CI scenarios.

◆ Capybara-

◆ Capybara-webkit driver (gem) is used for true testing with JavaScript support. It uses QtWebKit and it is significantly faster than Selenium as it does not load the entire browser. Introduction to Capybara

◆ Matchers ◆ Capybara finds an element either using Domain-specific language or XPath/CSS Selectors. Partial matches can lead to unexpected results. Two or more matches can even result in a failure with an Ambiguous match error. The following are the matching strategies supported by Capybara:

◆ first: Pick the first element which matches. Not advisable to use.

◆ one: Allow only one element match. Error raised if more than one match.

◆ smart: If Capybara.exact is true, it behaves like the above option (one). If Capybara.exact is false, it will first try to find an exact match. Ambiguous exception is raised if more than one match is found. If no element is found, a new search for inexact matches is commenced. Again, an ambiguous exception is raised if more than one match is found.

◆ prefer_exact: Finds all matching (exact and which are not exact) elements. If multiple matches are found then the first exactly matching element is returned discarding other matches. User-Registration Process

◆ Here is an example of how user registration test is done using Capybara. There is a test to see if the user can continue with the registration process or if there are any holds on him. If he has the requisite credentials, he will be registered and then redirected to the 'Welcome' page.

◆ describe 'UserRegistration' do ◆ it 'allows a user to register' do

◆ visit new_user_registration_path ◆ fill_in 'First name', :with => 'New' ◆ fill_in 'Last name', :with => 'User'

◆ fill_in 'Email', :with => '[email protected]' ◆ fill_in 'Password', :with => 'userpassword' ◆ fill_in 'Password Confirmation', :with => 'userpassword'

◆ click_button 'Register' ◆ page.should have content 'Welcome'

◆ end

◆ end User-Registration Process

◆ Capybara with Cucumber

◆ An example of a Capybara feature used with Cucumber:

◆ When /^I want to add/ do

◆ fill_in 'a', :with => 100

◆ fill_in 'b', :with => 100

◆ click_button 'Add'

◆ end

◆ Capybara with RSpec

◆ Some minute integration is required in order to use Capybara with RSpec

◆ describe 'go to home page' do

◆ it 'opens the home page' do

◆ visit (get_homepage) ◆ page.should have_content('Welcome') ◆ end ◆ end Capybara Installation

◆ Surendras-MacBook-Pro:capybara SurendraMac$ gem install capybara ◆ Fetching: addressable-2.4.0.gem (100%) ◆ Successfully installed addressable-2.4.0

◆ Fetching: capybara-2.7.1.gem (100%)

◆ Successfully installed capybara-2.7.1 ◆ Parsing documentation for addressable-2.4.0

◆ Installing ri documentation for addressable-2.4.0

◆ Parsing documentation for capybara-2.7.1 ◆ Installing ri documentation for capybara-2.7.1 ◆ Done installing documentation for addressable, capybara after 3 seconds

◆ 2 gems installed Cucumber-rails Installation

◆ Surendras-MacBook-Pro:capybara SurendraMac$ gem install cucumber-rails

◆ Fetching: cucumber-rails-1.4.3.gem (100%) ◆ Successfully installed cucumber-rails-1.4.3

◆ Parsing documentation for cucumber-rails-1.4.3 ◆ Installing ri documentation for cucumber-rails-1.4.3

◆ Done installing documentation for cucumber-rails after 0 seconds ◆ 1 gem installed

◆ Surendras-MacBook-Pro:capybara SurendraMac$ pwd ◆ /Users/SurendraMac/capybara Cucumber - - init

◆ Surendras-MacBook-Pro:capybara SurendraMac$ cucumber --init

◆ create features ◆ create features/step_definitions ◆ create features/support ◆ create features/support/env.rb

◆ Surendras-MacBook-Pro:capybara SurendraMac$ ls

◆ features

◆ Surendras-MacBook-Pro:capybara SurendraMac$ cd features/

◆ Surendras-MacBook-Pro:features SurendraMac$ ls ◆ step_definitions support ◆ Surendras-MacBook-Pro:features SurendraMac$ ls

◆ step_definitions support youtube_search.feature Cucumber YouTube.feature

◆ Feature: Search for Videos on YouTube ◆ Scenario: Search for Videos of Large Rodents

◆ Given I am on the YouTube home page

◆ When I search for "capybara"

◆ Then videos of capybara are returned Cucumber Test

◆ Surendras-MacBook-Pro:capybara SurendraMac$ cucumber

◆ Feature: Search for Videos on YouTube

◆ Scenario: Search for Videos of Large Rodents # features/ youtube_search.feature:2 ◆ Given I am on the YouTube home page # features/ youtube_search.feature:3 ◆ When I search for "capybara" # features/youtube_search.feature:4

◆ Then videos of Capybara are returned # features/youtube_search.feature: 5

◆ 1 scenario (1 undefined)

◆ 3 steps (3 undefined)

◆ 0m0.025s Cucumber steps

◆ You can implement step definitions for undefined steps with these snippets:

◆ Given(/^I am on the YouTube home page$/) do

◆ pending # Write code here that turns the phrase above into concrete actions

◆ end

◆ When(/^I search for "([^"]*)"$/) do |arg1|

◆ pending # Write code here that turns the phrase above into concrete actions

◆ end

◆ Then(/^videos of Capybara are returned$/) do

◆ pending # Write code here that turns the phrase above into concrete actions

◆ end Cucumber Test

◆ Surendras-MacBook-Pro:capybara SurendraMac$ cucumber ◆ Feature: Search for Videos on YouTube

◆ Scenario: Search for Videos of Large Rodents # features/youtube_search.feature:2 ◆ Given I am on the YouTube home page # features/step_definitions/steps.rb:2 ◆ TODO (Cucumber::Pending) ◆ ./features/step_definitions/steps.rb:3:in `/^I am on the YouTube home page$/' ◆ features/youtube_search.feature:3:in `Given I am on the YouTube home page' ◆ When I search for "capybara" # features/step_definitions/steps.rb:6 ◆ Then videos of Capybara are returned # features/step_definitions/steps.rb:10

◆ 1 scenario (1 pending) ◆ 3 steps (2 skipped, 1 pending) ◆ 0m0.024s Support/env.rb

◆ Add following lines ◆ support/env.rb

◆ require 'capybara/cucumber'

◆ Capybara.default_driver = :selenium

◆ Cucumber steps Modification

◆ Given(/^I am on the YouTube home page$/) do ◆ visit 'http://www.youtube.com' ◆ end

◆ When(/^I search for "([^"]*)"$/) do |arg1|

◆ pending # Write code here that turns the phrase above into concrete actions ◆ end

◆ Then(/^videos of Capybara are returned$/) do

◆ pending # Write code here that turns the phrase above into concrete actions ◆ end Cucumber Test

◆ Surendras-MacBook-Pro:capybara SurendraMac$ cucumber ◆ Feature: Search for Videos on YouTube

◆ Scenario: Search for Videos of Large Rodents # features/youtube_search.feature:2

◆ Given I am on the YouTube home page # features/step_definitions/steps.rb:2

◆ unable to obtain stable firefox connection in 60 seconds (127.0.0.1:7055) (Selenium::WebDriver::Error::WebDriverError) ◆ ./features/step_definitions/steps.rb:3:in `/^I am on the YouTube home page$/'

◆ features/youtube_search.feature:3:in `Given I am on the YouTube home page'

◆ When I search for "capybara" # features/step_definitions/steps.rb:6

◆ Then videos of Capybara are returned # features/step_definitions/steps.rb:10

◆ Failing Scenarios: ◆ cucumber features/youtube_search.feature:2 # Scenario: Search for Videos of Large Rodents

◆ 1 scenario (1 failed)

◆ 3 steps (1 failed, 2 skipped)

◆ 1m6.287s Selenium-webdriver installation

◆ Surendras-MacBook-Pro:capybara SurendraMac$ gem install selenium-webdriver

◆ Fetching: selenium-webdriver-2.53.4.gem (100%) ◆ Successfully installed selenium-webdriver-2.53.4

◆ Parsing documentation for selenium-webdriver-2.53.4 ◆ Installing ri documentation for selenium-webdriver-2.53.4

◆ Done installing documentation for selenium-webdriver after 4 seconds ◆ 1 gem installed

◆ Surendras-MacBook-Pro:capybara SurendraMac$ ls ◆ features Cucumber Test After Driver Installation

◆ Surendras-MacBook-Pro:capybara SurendraMac$ cucumber ◆ Feature: Search for Videos on YouTube

◆ Scenario: Search for Videos of Large Rodents # features/youtube_search.feature:2 ◆ Given I am on the YouTube home page # features/step_definitions/steps.rb:2 ◆ When I search for "capybara" # features/step_definitions/steps.rb:6 ◆ TODO (Cucumber::Pending) ◆ ./features/step_definitions/steps.rb:7:in `/^I search for "([^"]*)"$/' ◆ features/youtube_search.feature:4:in `When I search for "capybara"' ◆ Then videos of Caybara are returned # features/step_definitions/steps.rb:10

◆ 1 scenario (1 pending) ◆ 3 steps (1 skipped, 1 pending, 1 passed) ◆ 0m6.499s ◆ Surendras-MacBook-Pro:capybara SurendraMac$ Adding Search Query in steps

◆ Given(/^I am on the YouTube home page$/) do

◆ visit 'http://www.youtube.com'

◆ end

◆ When(/^I search for "([^"]*)"$/) do |search_term| ◆ fill_in 'search_query', :with => search_term

◆ click_on 'Search'

◆ end

◆ Then(/^videos of large rodents are returned$/) do ◆ expect(page).to have_content(‘Capybara')

◆ end Cucumber Steps with expect

◆ Given(/^I am on the YouTube home page$/) do

◆ visit 'http://www.youtube.com' ◆ end

◆ When(/^I search for "([^"]*)"$/) do |search_term|

◆ fill_in 'search_query', :with => search_term

◆ click_on ‘Search'

◆ end

◆ Then(/^videos of large rodents are returned$/) do ◆ expect(page).to have_content('Capybara')

◆ end Cucumber Test with all steps passed

Surendras-MacBook-Pro:capybara SurendraMac$ cucumber Feature: Search for Videos on YouTube

Scenario: Search for Videos of Large Rodents # features/ youtube_search.feature:2 Given I am on the YouTube home page # features/step_definitions/ steps.rb:2 When I search for "capybara" # features/step_definitions/steps.rb:6 Then videos of Capybara are returned # features/step_definitions/steps.rb:11

1 scenario (1 passed) 3 steps (3 passed) 0m11.566s Surendras-MacBook-Pro:capybara SurendraMac$ Detail Explanation of each step

• The first line tells Capybara to inform the driver (Selenium WebDriver) to open a browser and navigate to a URL we provide as a string: • visit ‘http://www.youtube.com' • Put geckodriver-v0.24.0-macos.tar.gz in /usr/local/bin • Selenium WebDriver has built-in mechanisms to wait for page loads in the browser so we don't have to worry about any kind of page load check. Note that this does not include waiting for asynchronous JavaScript, for example, Ajax/XHTTP requests. • After this we need to enter our search terms and click on the Search button so we tell Capybara to get the driver to fill in the search with our search terms. • Again Capybara's API is helpful in telling us this. • #note the search_term variable is passed from the Cucumber scenario • fill_in 'search_query', :with => search_term • click_on 'Search' Testing Web Apps with Capybara and Cucumber

• Step 1: Building the App • We’re going to create an incredibly simple app to test. For starters, let’s create a project folder and throw this in a Gemfile: • source : • gem "sinatra" • gem "shotgun" • gem "cucumber" • gem "capybara" • gem "" • Now, run bundle install in that directory. Testing Web Apps with Capybara and Cucumber

• Shotgun (reloading rack development server) • This is an automatic reloading version of the rackup command that's shipped with Rack. It can be used as an alternative to the complex reloading logic provided by web frameworks or in environments that don't support application reloading.

• The shotgun command starts one of Rack's supported servers (e.g., , thin, webrick) and listens for requests but does not load any part of the actual application. Each time a request is received, it forks, loads the application in the child process, processes the request, and exits the child process. The result is clean, application-wide reloading of all source files and templates on each request. Testing Web Apps with Capybara and Cucumber

• Usage • ----- • Installation: • gem install shotgun • Starting a server with a rackup file: • shotgun config.ru • Using Thin and starting on port 6000 instead of 9393 (default): • shotgun --server=thin --port=6000 config.ru • Running Sinatra apps: • shotgun hello.rb Testing Web Apps with Capybara and Cucumber

• See 'shotgun --help' for more advanced usage.

• Links • -----

• Shotgun: http://github.com/rtomayko/shotgun • Rack: http://rack.rubyforge.org/ • Sinatra: http://www.sinatrarb.com/

• The reloading system in Ian Bicking's webware framework served as inspiration • for the approach taken in Shotgun. Ian lays down the pros and cons of this • approach in the following article:

• http://ianbicking.org/docs/Webware_reload.html Testing Web Apps with Capybara and Cucumber

• Surendras-MacBook-Pro:webapp SurendraMac$ pwd • /Users/SurendraMac/capybara/webapp • Surendras-MacBook-Pro:webapp SurendraMac$ ruby myapp.rb • Surendras-MacBook-Pro:webapp SurendraMac$ ls • myapp.rb • Surendras-MacBook-Pro:webapp SurendraMac$ mkdir views • Surendras-MacBook-Pro:webapp SurendraMac$ ls • layout.erb myapp.rb views • Surendras-MacBook-Pro:webapp SurendraMac$ ls • config.ru myapp.rb views • Surendras-MacBook-Pro:webapp SurendraMac$ shotgun • == Shotgun/WEBrick on http://127.0.0.1:9393/ • [2016-07-08 06:26:11] INFO WEBrick 1.3.1 • [2016-07-08 06:26:11] INFO ruby 2.2.3 (2015-08-18) [x86_64-darwin14] • [2016-07-08 06:26:11] INFO WEBrick::HTTPServer#start: pid=28647 port=9393 Testing Web Apps with Capybara and Cucumber

• So, open a file called myapp.rb; simple app; it just simulates a site that might let you sign up for a newsletter. require "sinatra/base" class MyApp < Sinatra::Base get "/" do erb :index end post "/thankyou" do @name = params["name"] @email = params["email"] erb :thankyou end get "/form" do erb :form end end Testing Web Apps with Capybara and Cucumber

• views/layout.erb THE APP

THE APP

<%= yield %> That call to yield will be where the other templates are inserted. Testing Web Apps with Capybara and Cucumber

• views/index.erb

This is the home page

Sign up for our newsletter!

Testing Web Apps with Capybara and Cucumber

• views/form.erb

Fill out this form to receive our newsletter.

Testing Web Apps with Capybara and Cucumber views/thankyou.erb

Hi there, <%= @name %>. You'll now receive our email at <%= @email %>

So, there’s our app. To test it manually, you can put this in a config.ru file: require "./myapp" run MyApp click on browser http://localhost:9393/ Testing Web Apps with Capybara and Cucumber

THE APP

This is the home page

Sign up for our newsletter! Testing Web Apps with Capybara and Cucumber http://localhost:9393/form THE APP Fill out this form to receive our newsletter. Name: Email: Sign Up! Step 2: Setting our our Test Environment

Surendras-MacBook-Pro:webapp SurendraMac$ pwd /Users/SurendraMac/capybara/webapp Surendras-MacBook-Pro:webapp SurendraMac$ cucumber --init create features create features/step_definitions create features/support create features/support/env.rb Surendras-MacBook-Pro:webapp SurendraMac$ ls config.ru features myapp.rb views Surendras-MacBook-Pro:webapp SurendraMac$ Step 2: Setting our our Test Environment

Surendras-MacBook-Pro:webapp SurendraMac$ pwd /Users/SurendraMac/capybara/webapp Surendras-MacBook-Pro:webapp SurendraMac$ cucumber --init create features create features/step_definitions create features/support create features/support/env.rb Surendras-MacBook-Pro:webapp SurendraMac$ ls config.ru features myapp.rb views Surendras-MacBook-Pro:webapp SurendraMac$ Using Capybara with Cucumber

• The cucumber-rails gem comes with Capybara support built-in. If you are not using Rails, manually load the capybara/cucumber module:

• require 'capybara/cucumber' • Capybara.app = MyRackApp • You can use the Capybara DSL in your steps, like so:

• When /I sign in/ do • within("#session") do • fill_in 'Email', :with => '[email protected]' • fill_in 'Password', :with => 'password' • end • click_button 'Sign in' • end Using Capybara with RSpec

• Load RSpec 2.x support by adding the following line (typically to your spec_helper.rb file): • require 'capybara/rspec' • If you are using Rails, put your Capybara specs in spec/ features (only works if you have it configured in RSpec) and if you have your Capybara specs in a different directory, then tag the example groups with :type => :feature. • If you are not using Rails, tag all the example groups in which you want to use Capybara with :type => :feature. Using Capybara with RSpec

• You can now write your specs like so: • describe "the signin process", :type => :feature do • before :each do • User.make(:email => '[email protected]', :password => 'password') • end end end • it "signs me in" do • visit '/sessions/new' • within("#session") do • fill_in 'Email', :with => '[email protected]' • fill_in 'Password', :with => 'password' • end • click_button 'Sign in' • expect(page).to have_content 'Success' Using Capybara with RSpec

• feature "Signing in" do • background do • User.make(:email => '[email protected]', :password => 'caplin') • end • scenario "Signing in with correct credentials" do • visit '/sessions/new' • within("#session") do • fill_in 'Email', :with => '[email protected]' • fill_in 'Password', :with => 'caplin' • end • click_button 'Sign in' • expect(page).to have_content 'Success' • end Using Capybara with RSpec

• given(:other_user) { User.make(:email => '[email protected]', :password => 'rous') }

• scenario "Signing in as another user" do • visit '/sessions/new' • within("#session") do • fill_in 'Email', :with => other_user.email • fill_in 'Password', :with => other_user.password • end • click_button 'Sign in' • expect(page).to have_content 'Invalid email or password' • end • end Using Capybara with RSpec

• feature is in fact just an alias for describe ..., :type => :feature, background is an alias for before, scenario for it, and given/given! aliases for let/let!, respectively.

• Finally, Capybara matchers are supported in view specs:

• RSpec.describe "todos/show.html.erb", type: :view do • it "displays the todo title" do • assign :todo, Todo.new(title: "Buy milk")

• render

• expect(rendered).to have_css("header h1", text: "Buy milk") • end • end Using Capybara with Test::Unit

• If you are using Rails, add the following code in your test_helper.rb file to make Capybara available in all test cases deriving from ActionDispatch::IntegrationTest: • class ActionDispatch::IntegrationTest • # Make the Capybara DSL available in all integration tests • include Capybara::DSL

• # Reset sessions and driver between tests • # Use super wherever this method is redefined in your individual test classes • def teardown • Capybara.reset_sessions! • Capybara.use_default_driver • end • end Using Capybara with Test::Unit

• If you are not using Rails, define a base class for your Capybara tests like so: • class CapybaraTestCase < Test::Unit::TestCase • include Capybara::DSL

• def teardown • Capybara.reset_sessions! • Capybara.use_default_driver • end • end Using Capybara with Test::Unit

• Remember to call super in any subclasses that override teardown. • To switch the driver, set Capybara.current_driver. For instance,

• class BlogTest < ActionDispatch::IntegrationTest • setup do • Capybara.current_driver = Capybara.javascript_driver # :selenium by default • end

• test 'shows blog posts' do • # ... this test is run with Selenium ... • end • end Capybara Drivers

• Capybara uses the same DSL to drive a variety of browser and headless drivers. • Selecting the Driver • By default, Capybara uses the :rack_test driver, which is fast but limited: it does not support JavaScript, nor is it able to access HTTP resources outside of your Rack application, such as remote APIs and OAuth services. To get around these limitations, you can set up a different default driver for your features. For example if you'd prefer to run everything in Selenium, you could do:

• Capybara.default_driver = :selenium • However, if you are using RSpec or Cucumber, you may instead want to consider leaving the faster :rack_test as the default_driver, and marking only those tests that require a JavaScript-capable driver using :js => true or @, respectively. By default, JavaScript tests are run using the :selenium driver. You can change this by setting Capybara.javascript_driver. Capybara Drivers

• You can also change the driver temporarily (typically in the Before/setup and After/teardown blocks): • Capybara.current_driver = :webkit # temporarily select different driver • # tests here • Capybara.use_default_driver # switch back to default driver • Note: switching the driver creates a new session, so you may not be able to switch in the middle of a test. Capybara Drivers

• RackTest • RackTest is Capybara's default driver. It is written in pure Ruby and does not have any support for executing JavaScript. Since the RackTest driver interacts directly with Rack interfaces, it does not require a server to be started. However, this means that if your application is not a Rack application (Rails, Sinatra and most other Ruby frameworks are Rack applications) then you cannot use this driver. Furthermore, you cannot use the RackTest driver to test a remote application, or to access remote URLs (e.g., redirects to external sites, external APIs, or OAuth services) that your application might interact with. • capybara-mechanize provides a similar driver that can access remote servers. • RackTest can be configured with a set of headers like this: • Capybara.register_driver :rack_test do |app| • Capybara::RackTest::Driver.new(app, :headers => { 'HTTP_USER_AGENT' => 'Capybara' }) • end Capybara Drivers

• Selenium • At the moment, Capybara supports Selenium 2.0 (Webdriver), not Selenium RC. In order to use Selenium, you'll need to install the selenium-webdriver gem, and add it to your Gemfile if you're using bundler. Provided Firefox is installed, everything is set up for you, and you should be able to start using Selenium right away.

• Note: drivers which run the server in a different thread may not share the same transaction as your tests, causing data not to be shared between your test and test server, see "Transactions and database setup" below. Capybara Drivers

• Capybara-webkit • The capybara-webkit driver is for true headless testing. It uses QtWebKit to start a rendering engine process. It can execute JavaScript as well. It is significantly faster than drivers like Selenium since it does not load an entire browser. • You can install it with: • gem install capybara-webkit • And you can use it by: • Capybara.javascript_driver = :webkit Capybara DSL

• The DSL • A complete reference is available at rubydoc.info.

• Note: By default Capybara will only locate visible elements. This is because a real user would not be able to interact with non-visible elements.

• Note: All searches in Capybara are case sensitive. This is because Capybara heavily uses XPath, which doesn't support case insensitivity.

• Navigating • You can use the visit method to navigate to other pages: • visit('/projects') • visit(post_comments_path(post)) • The visit method only takes a single parameter, the request method is always GET. Capybara DSL

• You can get the current path of the browsing session, and test it using the have_current_path matcher: • expect(page).to have_current_path(post_comments_path(post))

• Clicking links and buttons • Full reference: Capybara::Node::Actions • You can interact with the webapp by following links and buttons. Capybara automatically follows any redirects, and submits forms associated with buttons. • click_link('id-of-link') • click_link('Link Text') • click_button('Save') • click_on('Link Text') # clicks on either links or buttons • click_on('Button Value') Interacting with forms

• Full reference: Capybara::Node::Actions • There are a number of tools for interacting with form elements:

• fill_in('First Name', :with => 'John') • fill_in('Password', :with => 'Seekrit') • fill_in('Description', :with => 'Really Long Text...') • choose('A Radio Button') • check('A Checkbox') • uncheck('A Checkbox') • attach_file('Image', '/path/to/image.jpg') • select('Option', :from => 'Select Box') Capybara Querying

• Full reference: Capybara::Node::Matchers • Capybara has a rich set of options for querying the page for the existence of certain elements, and working with and manipulating those elements. • page.has_selector?('table tr') • page.has_selector?(:, '//table/tr') • page.has_xpath?('//table/tr') • page.has_css?('table tr.foo') • page.has_content?('foo') Capybara Querying

• Note: The negative forms like has_no_selector? are different from not has_selector?. Read the section on asynchronous JavaScript for an explanation. • You can use these with RSpec's magic matchers: • expect(page).to have_selector('table tr') • expect(page).to have_selector(:xpath, '//table/tr') • expect(page).to have_xpath('//table/tr') • expect(page).to have_css('table tr.foo') • expect(page).to have_content('foo') Capybara Finding

• Full reference: Capybara::Node::Finders • You can also find specific elements, in order to manipulate them:

• find_field('First Name').value • find_link('Hello', :visible => :all).visible? • find_button('Send').click

• find(:xpath, "//table/tr").click • find("#overlay").find("h1").click • all('a').each { |a| a[:href] } • Note: find will wait for an element to appear on the page, as explained in the Ajax section. If the element does not appear it will raise an error. Capybara Finding and Scoping

• These elements all have all the Capybara DSL methods available, so you can restrict them to specific parts of the page: • find('#navigation').click_link('Home') • expect(find('#navigation')).to have_button('Sign out’)

• Scoping • Capybara makes it possible to restrict certain actions, such as interacting with forms or clicking links and buttons, to within a specific area of the page. For this purpose you can use the generic within method. Optionally you can specify which kind of selector to use.

• within("li#employee") do • fill_in 'Name', :with => 'Jimmy' • end Capybara Scoping

• within(:xpath, "//li[@id='employee']") do • fill_in 'Name', :with => 'Jimmy' • end • There are special methods for restricting the scope to a specific fieldset, identified by either an id or the text of the fieldset's legend tag, and to a specific table, identified by either id or text of the table's caption tag.

• within_fieldset('Employee') do • fill_in 'Name', :with => 'Jimmy' • end

• within_table('Employee') do • fill_in 'Name', :with => 'Jimmy' • end Capybara Working with windows

• Capybara provides some methods to ease finding and switching windows: • facebook_window = window_opened_by do • click_button 'Like' • end • within_window facebook_window do • find('#login_email').set('[email protected]') • find('#login_password').set('qwerty') • click_button 'Submit' • end Capybara Scripting

• In drivers which support it, you can easily execute JavaScript: • page.execute_script("$('body').empty()") • For simple expressions, you can return the result of the script. Note that this may break with more complicated expressions: • result = page.evaluate_script('4 + 4'); Capybara Modals

• In drivers which support it, you can accept, dismiss and respond to alerts, confirms and prompts. • You can accept or dismiss alert messages by wrapping the code that produces an alert in a block: • accept_alert do • click_link('Show Alert') • end • You can accept or dismiss a confirmation by wrapping it in a block, as well:

• dismiss_confirm do • click_link('Show Confirm') • end Capybara Modals

• You can accept or dismiss prompts as well, and also provide text to fill in for the response: • accept_prompt(with: 'Linus Torvalds') do • click_link('Show Prompt About Linux') • end • All modal methods return the message that was presented. So, you can access the prompt message by assigning the return to a variable:

• message = accept_prompt(with: 'Linus Torvalds') do • click_link('Show Prompt About Linux') • end • expect(message).to eq('Who is the chief architect of Linux?') Capybara Debugging

• It can be useful to take a snapshot of the page as it currently is and take a look at it: • save_and_open_page • You can also retrieve the current state of the DOM as a string using page.html.

• print page.html • This is mostly useful for debugging. You should avoid testing against the contents of page.html and use the more expressive finder methods instead.

• Finally, in drivers that support it, you can save a screenshot: • page.save_screenshot('screenshot.png') • Or have it save and automatically open: • save_and_open_screenshot Capybara Debugging

• Matching • It is possible to customize how Capybara finds elements. At your disposal are two options, Capybara.exact and Capybara.match.

• Exactness • Capybara.exact and the exact option work together with the is expression inside the XPath gem. When exact is true, all is expressions match exactly, when it is false, they allow substring matches. Many of the selectors built into Capybara use the is expression. This way you can specify whether you want to allow substring matches or not. Capybara.exact is false by default.

• For example: • click_link("Password") # also matches "Password confirmation" • Capybara.exact = true • click_link("Password") # does not match "Password confirmation" • click_link("Password", exact: false) # can be overridden Capybara Strategy

• Using Capybara.match and the equivalent match option, you can control how Capybara behaves when multiple elements all match a query. There are currently four different strategies built into Capybara:

• first: Just picks the first element that matches. • one: Raises an error if more than one element matches. • smart: If exact is true, raises an error if more than one element matches, just like one. If exact is false, it will first try to find an exact match. An error is raised if more than one element is found. If no element is found, a new search is performed which allows partial matches. If that search returns multiple matches, an error is raised. • prefer_exact: If multiple matches are found, some of which are exact, and some of which are not, then the first exactly matching element is returned. • The default for Capybara.match is :smart. To emulate the behaviour in Capybara 2.0.x, set Capybara.match to :one. To emulate the behaviour in Capybara 1.x, set Capybara.match to :prefer_exact. Capybara Transaction and Database Setup

• Some Capybara drivers need to run against an actual HTTP server. Capybara takes care of this and starts one for you in the same process as your test, but on another thread. Selenium is one of those drivers, whereas RackTest is not.

• If you are using a SQL database, it is common to run every test in a transaction, which is rolled back at the end of the test, rspec- rails does this by default out of the box for example. • Since transactions are usually not shared across threads, this will cause data you have put into the database in your test code to be invisible to Capybara. • Cucumber handles this by using truncation instead of transactions, i.e. they empty out the entire database after each test. You can get the same behaviour by using a gem such as database_cleaner. Capybara Asynchronous JavaScript

• When working with asynchronous JavaScript, you might come across situations where you are attempting to interact with an element which is not yet present on the page. • Capybara automatically deals with this by waiting for elements to appear on the page. • When issuing instructions to the DSL such as: • click_link('foo') • click_link('bar') • expect(page).to have_content('baz') Capybara Asynchronous JavaScript

• If clicking on the foo link triggers an asynchronous process, such as an Ajax request, which, when complete will add the bar link to the page, clicking on the bar link would be expected to fail, since that link doesn't exist yet. • However Capybara is smart enough to retry finding the link for a brief period of time before giving up and throwing an error. • The same is true of the next line, which looks for the content baz on the page; it will retry looking for that content for a brief time. You can adjust how long this period is (the default is 2 seconds): • Capybara.default_max_wait_time = 5 Capybara Asynchronous JavaScript

• Be aware that because of this behaviour, the following two statements are not equivalent, and you should always use the latter! • !page.has_xpath?('a') • page.has_no_xpath?('a') • The former would immediately fail because the content has not yet been removed. Only the latter would wait for the asynchronous process to remove the content from the page.

• Capybara's RSpec matchers, however, are smart enough to handle either form. The two following statements are functionally equivalent:

• expect(page).not_to have_xpath('a') • expect(page).to have_no_xpath('a') Capybara Asynchronous JavaScript

• Capybara's waiting behaviour is quite advanced, and can deal with situations such as the following line of code: • expect(find('#sidebar').find('h1')).to have_content('Something') • Even if JavaScript causes #sidebar to disappear off the page, Capybara will automatically reload it and any elements it contains. • So if an AJAX request causes the contents of #sidebar to change, which would update the text of the h1 to "Something", and this happened, this test would pass. • If you do not want this behaviour, you can set Capybara.automatic_reload to false. Capybara DSL elsewhere

• Using the DSL elsewhere • You can mix the DSL into any context by including Capybara::DSL: • require 'capybara/dsl' • Capybara.default_driver = :webkit • module MyModule • include Capybara::DSL • def login! • within("//form[@id='session']") do • fill_in 'Email', :with => '[email protected]' • fill_in 'Password', :with => 'password' • end • click_button 'Sign in' • end • end Capybara Calling remote servers

• Normally Capybara expects to be testing an in-process Rack application, but you can also use it to talk to a web server running anywhere on the internet, by setting app_host: • Capybara.current_driver = :selenium • Capybara.app_host = 'http://www.google.com' • ... • visit('/') • Note: the default driver (:rack_test) does not support running against a remote server. With drivers that support it, you can also visit any URL directly: • visit('http://www.google.com') • By default Capybara will try to boot a rack application automatically. You might want to switch off Capybara's rack server if you are running against a remote application: • Capybara.run_server = false Capybara Named Sessions

• Named sessions • Capybara manages named sessions (:default if not specified) and multiple sessions using the same driver and test app instance can be interacted with. A new session will be created using the current driver if a session with the given name using the current driver and test app instance is not found.

• To perform operations in a different session and then revent to the previous session

• Capybara.using_session("Bob's session") do • #do something in Bob's browser session • end • #reverts to previous session • To permanently switch the current session to a different session • Capybara.session_name = "some other session" Capybara Using the sessions manually

• For ultimate control, you can instantiate and use a Session manually.

• require 'capybara'

• session = Capybara::Session.new(:webkit, my_rack_app) • session.within("//form[@id='session']") do • session.fill_in 'Email', :with => '[email protected]' • session.fill_in 'Password', :with => 'password' • end • session.click_button 'Sign in' Capybara Using the sessions manually

• XPath, CSS and selectors • Capybara does not try to guess what kind of selector you are going to give it, and will always use CSS by default. If you want to use XPath, you'll need to do:

• within(:xpath, '//ul/li') { ... } • find(:xpath, '//ul/li').text • find(:xpath, '//li[contains(.//a[@href = "#"]/text(), "foo")]').value • Alternatively you can set the default selector to XPath:

• Capybara.default_selector = :xpath • find('//ul/li').text XPath, CSS and selectors

• Capybara allows you to add custom selectors, which can be very useful if you find yourself using the same kinds of selectors very often:

• Capybara.add_selector(:id) do • xpath { |id| XPath.descendant[XPath.attr(:id) == id.to_s] } • end

• Capybara.add_selector(:row) do • xpath { |num| ".//tbody/tr[#{num}]" } • end

• Capybara.add_selector(:flash_type) do • { |type| "#flash.#{type}" } • end XPath, CSS and selectors

• The block given to xpath must always return an XPath expression as a String, or an XPath expression generated through the XPath gem. You can now use these selectors like this:

• find(:id, 'post_123') • find(:row, 3) • find(:flash_type, :notice) XPath, CSS and selectors

• Beware the XPath // trap • In XPath the expression // means something very specific, and it might not be what you think. Contrary to common belief, // means "anywhere in the document" not "anywhere in the current context". As an example:

• page.find(:xpath, '//body').all(:xpath, '//script') • You might expect this to find all script tags in the body, but actually, it finds all script tags in the entire document, not only those in the body! What you're looking for is the .// expression which means "any descendant of the current node":

• page.find(:xpath, '//body').all(:xpath, './/script') XPath, CSS and selectors

• The same thing goes for within:

• within(:xpath, '//body') do • page.find(:xpath, './/script') • within(:xpath, './/table/tbody') do • ... • end • end Capybara Configuring and adding drivers

• Capybara makes it convenient to switch between different drivers. It also exposes an API to tweak those drivers with whatever settings you want, or to add your own drivers. This is how to override the selenium driver configuration to use chrome:

• Capybara.register_driver :selenium do |app| • Capybara::Selenium::Driver.new(app, :browser => :chrome) • end • However, it's also possible to give this configuration a different name.

• Capybara.register_driver :selenium_chrome do |app| • Capybara::Selenium::Driver.new(app, :browser => :chrome) • end Capybara Configuring and adding drivers

• Then tests can switch between using different browsers effortlessly:

• Capybara.current_driver = :selenium_chrome • Whatever is returned from the block should conform to the API described by Capybara::Driver::Base, it does not however have to inherit from this class. Gems can use this API to add their own drivers to Capybara.

• The Selenium wiki has additional info about how the underlying driver can be configured.