We use Selenium WebDriver Show archive.org snapshot with Capybara for end-to-end tests that need a real browser.
Important
Work on this lesson in
advisormode.
Learning goals
- You can explain how Capybara drives a browser, how its drivers differ (e.g.
rack_testvs. Selenium), and when a feature spec needs a real browser. - You can run a feature spec in a real browser, headless or visible, and watch what it does.
- You can explain why browser tests are flaky by nature β asynchronous JavaScript, timing, and the app and the browser running in separate threads or processes β and how Capybara's waiting and retrying counters that.
- You can diagnose and fix a flaky feature spec with our standard toolbox, e.g. capybara-lockstep and waiting finders instead of
sleep. - You can handle browser dialogs, file downloads and screenshots in a feature spec.
- You can explain how the app and the browser share one test database and how it is reset between examples.
- You know what running tests in parallel and on a CI server requires from your test setup.
Resources
Read what's new to you, skim what's familiar, skip what you already master. Stop when you can meet the learning goals.
Your agent can also generate an overview, a tutorial or an explanation for anything here, tailored to what you already know. Just ask.
Capybara
- π
Capybara README
Show archive.org snapshot
β read The DSL, Matching, Asynchronous JavaScript (Ajax and friends) for the waiting/retry mechanism, Transactions and database setup, and Drivers (
rack_testvs. Selenium) - π
Feature specs in rspec-rails
Show archive.org snapshot
β how a feature spec is set up, and how
js: trueswitches an example to the JavaScript driver - π
Waiting for it with Capybara's synchronize method
Show archive.org snapshot
β matchers poll, actions run once; the three processes involved (test runner, app server, browser);
synchronizefor coupled interactions - π Capybara::Node::Finders Show archive.org snapshot and Capybara::Node::Matchers Show archive.org snapshot β the API reference; also the source you read in the exercise
- π The two drivers as gems: rack-test Show archive.org snapshot and selenium-webdriver Show archive.org snapshot
Flaky tests and our toolbox
- π Fixing flaky E2E tests β our card on why browser tests flake and how to fix them
- βΆοΈ Fixing Flaky E2E Tests Show archive.org snapshot β the same content as a talk
- π capybara-lockstep β our card, and the gem's README Show archive.org snapshot : what problem it solves and how it keeps requests from bleeding between steps
- π Threads and processes in a Capybara/Selenium session
- π Run Selenium tests in Chrome and running tests in headless Chrome
- π parallel_tests Show archive.org snapshot β running the suite on several CPU cores; what it needs from your test setup
Dialogs, downloads, screenshots
- π Configure Selenium to not automatically close alerts and accept or deny confirmation dialogs β Capybara cannot interact with the page while a blocking dialog is open
- π Testing file downloads
- π Taking screenshots in Capybara
- π
evaluate_scriptmight freeze your browser, useexecute_script - π Specify the size of the Selenium browser window
- π Mock the browser time or time zone
Exercises
Try and use it
Your forked MovieDB should already include a feature spec that uses a real browser: it carries js: true metadata, which switches Capybara from Rack::Test to the Selenium driver. Add js: true to some of your other feature specs to test it yourself.
When you run such a spec with NO_HEADLESS=1 geordi rspec spec/features/..., you should see a browser opening. Get someone to help you if this does not work.
Some of your features might now fail. You might find solutions below:
A walk through the forest
Read the source of Capybara's
Finders#find / Finders#all
Show archive.org snapshot
and
Base#synchronize
Show archive.org snapshot
. Why does find wait for an element, while all doesn't? Why do specs that use all tend to become flaky?
Recognize common culprits
Have a look at this code:
class User < ApplicationRecord
def self.find_by_email(email)
@cached_users ||= {}
@cached_users[email] ||= User.find_by_email!(email)
end
end
Could it cause your tests to become flaky?