SlideShare a Scribd company logo
capybara-webkit
Testing Javascript without pain or loss of life
                 Joe Ferris
Modern applications
    use Javascript

• Rich user interfaces
• Faster, more responsive interfaces
• Easier to build reusable interface
  components
You need to test your
      Javascript
• No excuses
• Broken Javascript means a broken page
• In Javascript-heavy applications, it’s difficult
  to write capybara tests without running
  Javascript
Limits of rack-test
• “Dumb” web browser
• Follows redirects
• Rendering engine is Nokogiri
• Fill out forms, click links
• Handles 90% of the web
• (but the other 10% is the shiny part)
Simple Test
Feature: sign up for an account

 Scenario: sign up
  When I go to the home page
  And I fill in the following:
   | Email | jferris@thoughtbot.com |
   | Password | taters          |
  And I press "Sign up"
  Then I should have an email of "jferris@thoughtbot.com"

1 scenario (1 passed)
4 steps (4 passed)
0m0.446s
Simple Change
Feature: sign up for an account

 Scenario: sign up
  When I go to the home page
  And I fill in the following:
   | Email | jferris@thoughtbot.com |
   | Password | taters          |
  And I press "Sign up"
  Then I should have an email of "jferris@thoughtbot.com"
  And I should have an account name of "jferris"
Add some Javascript
<script type="text/javascript">
 $("#email").keyup(function () {
   var email = $(this).val();
   var name = email.replace(/@.*$/, "");
   $("#accountName").val(name);
 });
</script>
Feature: sign up for an account

  Scenario: sign up and get the default account name
   When I go to the home page
   And I fill in the following:
     | Email | jferris@thoughtbot.com |
     | Password | taters            |
   And I press "Sign up"
   Then I should have an email of "jferris@thoughtbot.com"
   And I should have an account name of "jferris"
     expected: "jferris"
         got: "" (using ==) (RSpec::Expectations::ExpectationNotMetError)
     ./features/step_definitions/web_steps.rb:218:in `/^I should have an account
name of "([^"]*)"$/'
     features/sign_up_javascript.feature:10:in `And I should have an account name of
"jferris"'

Failing Scenarios:
cucumber features/sign_up_javascript.feature:3

1 scenario (1 failed)
5 steps (1 failed, 4 passed)
0m0.398s
@javascript
Selenium

• Runs tests in a real browser (usually
  Firefox, but supports Chrome, Safari, and
  Internet Explorer)
• Supports any Javascript your browser
  supports, just like real users
• Easy to set up with capybara
Limits of Selenium

• Slow, slow, slow
• GUI browser adds a lot of cruft you don’t
  want that gets in the way
• Browsers were designed to be clicked on
  and looked at, not controlled and queried
Slow

• Boot up Firefox with fresh profile
• Set up Firefox with extension
• Communicates over JSON REST API
Unfriendly

• Automatic updates
• Download dialogs
• No console.log output
• Invisible Javascript errors
And I should see "Hello"
   expected there to be content "Hello" in ""
capybara-webkit

• Fast, fast, fast
• No browser UI
• Uses the WebKit engine
• console.log output
• Errors in standard output
Fast
                                         capybara-
                  rack-test   selenium
                                          webkit


Simple scenario     4.6s          8.3s     4.8s

  Filling in a
 bunch of text      42s           23s      6.4s
     fields
TypeError: Result of expression
'("#email").keyup' [undefined] is not a
function.
Mostly Easy
Gemfile:
gem "capybara-webkit"

features/support/env:
Capybara.javascript_driver = :webkit
But you need Qt


• Download installer on OS X
• Most Linux distros have a package
Caveats
• capybara-webkit’s engine is still designed to
  build browsers, so there are some
  interactions we can’t get between
• All tests are asynchronous (like with
  Selenium), so you still need Capybara’s
  retrying methods
• capybara-webkit is still young, so things are
  flakier than with Selenium
WebKits: how do they work?

  • capybara-webkit is built around QtWebKit
  • Headless browser listens for commands
    using a lightweight socket layer
  • Ruby driver implements the capybara API
    and communicates with the server
WebKit

• Based on KHTML
• Open source
• Powers Safari, Chrome, and other browsers
• Cross-platform, fast, standards-compliant
WebKit
• WebKit is not a browser, or really even a
  browser engine
• WebKit is a set of libraries for building
  browsers
• WebKit is not packaged as a standalone
  library
• There is no one WebKit
Qt

• Powers the KDE desktop
• Tools, extensions, and libraries for building
  GUI applications in C++
• Provides a packaged wrapper around
  WebKit called QtWebKit
QtWebKit

• Qt implementation of WebKit with nice API
  and documentation
• Lots of injection points for building your
  own browser
• We built a test harness instead
• capybara makes acceptance tests easy to write
• capybara-webkit is fast and easy to set up
• There is no excuse (anymore) for not testing
  Javascript
• capybara-webkit is open source
• Please submit pull requests
Thank You

   Joe Ferris          @joeferris


thoughtbot/capybara-
       webkit

More Related Content

Capybara-Webkit

  • 1. capybara-webkit Testing Javascript without pain or loss of life Joe Ferris
  • 2. Modern applications use Javascript • Rich user interfaces • Faster, more responsive interfaces • Easier to build reusable interface components
  • 3. You need to test your Javascript • No excuses • Broken Javascript means a broken page • In Javascript-heavy applications, it’s difficult to write capybara tests without running Javascript
  • 4. Limits of rack-test • “Dumb” web browser • Follows redirects • Rendering engine is Nokogiri • Fill out forms, click links • Handles 90% of the web • (but the other 10% is the shiny part)
  • 5. Simple Test Feature: sign up for an account Scenario: sign up When I go to the home page And I fill in the following: | Email | jferris@thoughtbot.com | | Password | taters | And I press "Sign up" Then I should have an email of "jferris@thoughtbot.com" 1 scenario (1 passed) 4 steps (4 passed) 0m0.446s
  • 6. Simple Change Feature: sign up for an account Scenario: sign up When I go to the home page And I fill in the following: | Email | jferris@thoughtbot.com | | Password | taters | And I press "Sign up" Then I should have an email of "jferris@thoughtbot.com" And I should have an account name of "jferris"
  • 7. Add some Javascript <script type="text/javascript"> $("#email").keyup(function () { var email = $(this).val(); var name = email.replace(/@.*$/, ""); $("#accountName").val(name); }); </script>
  • 8. Feature: sign up for an account Scenario: sign up and get the default account name When I go to the home page And I fill in the following: | Email | jferris@thoughtbot.com | | Password | taters | And I press "Sign up" Then I should have an email of "jferris@thoughtbot.com" And I should have an account name of "jferris" expected: "jferris" got: "" (using ==) (RSpec::Expectations::ExpectationNotMetError) ./features/step_definitions/web_steps.rb:218:in `/^I should have an account name of "([^"]*)"$/' features/sign_up_javascript.feature:10:in `And I should have an account name of "jferris"' Failing Scenarios: cucumber features/sign_up_javascript.feature:3 1 scenario (1 failed) 5 steps (1 failed, 4 passed) 0m0.398s
  • 10. Selenium • Runs tests in a real browser (usually Firefox, but supports Chrome, Safari, and Internet Explorer) • Supports any Javascript your browser supports, just like real users • Easy to set up with capybara
  • 11. Limits of Selenium • Slow, slow, slow • GUI browser adds a lot of cruft you don’t want that gets in the way • Browsers were designed to be clicked on and looked at, not controlled and queried
  • 12. Slow • Boot up Firefox with fresh profile • Set up Firefox with extension • Communicates over JSON REST API
  • 13. Unfriendly • Automatic updates • Download dialogs • No console.log output • Invisible Javascript errors
  • 14. And I should see "Hello" expected there to be content "Hello" in ""
  • 15. capybara-webkit • Fast, fast, fast • No browser UI • Uses the WebKit engine • console.log output • Errors in standard output
  • 16. Fast capybara- rack-test selenium webkit Simple scenario 4.6s 8.3s 4.8s Filling in a bunch of text 42s 23s 6.4s fields
  • 17. TypeError: Result of expression '("#email").keyup' [undefined] is not a function.
  • 19. But you need Qt • Download installer on OS X • Most Linux distros have a package
  • 20. Caveats • capybara-webkit’s engine is still designed to build browsers, so there are some interactions we can’t get between • All tests are asynchronous (like with Selenium), so you still need Capybara’s retrying methods • capybara-webkit is still young, so things are flakier than with Selenium
  • 21. WebKits: how do they work? • capybara-webkit is built around QtWebKit • Headless browser listens for commands using a lightweight socket layer • Ruby driver implements the capybara API and communicates with the server
  • 22. WebKit • Based on KHTML • Open source • Powers Safari, Chrome, and other browsers • Cross-platform, fast, standards-compliant
  • 23. WebKit • WebKit is not a browser, or really even a browser engine • WebKit is a set of libraries for building browsers • WebKit is not packaged as a standalone library • There is no one WebKit
  • 24. Qt • Powers the KDE desktop • Tools, extensions, and libraries for building GUI applications in C++ • Provides a packaged wrapper around WebKit called QtWebKit
  • 25. QtWebKit • Qt implementation of WebKit with nice API and documentation • Lots of injection points for building your own browser • We built a test harness instead
  • 26. • capybara makes acceptance tests easy to write • capybara-webkit is fast and easy to set up • There is no excuse (anymore) for not testing Javascript
  • 27. • capybara-webkit is open source • Please submit pull requests
  • 28. Thank You Joe Ferris @joeferris thoughtbot/capybara- webkit

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n